1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-11-30 10:19:00 +01:00

Implement serialization type migration

This commit is contained in:
Daniil Gentili 2023-05-26 17:20:13 +02:00
parent 14f6cfcedc
commit d17dcca02a
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
9 changed files with 55 additions and 43 deletions

View File

@ -27,7 +27,7 @@ final class Postgres
$config = PostgresConfig::fromString('host='.\str_replace('tcp://', '', $settings->getUri()))
->withUser($settings->getUsername())
->withPassword($settings->getPassword())
->withDatabase(strtolower($settings->getDatabase()));
->withDatabase(\strtolower($settings->getDatabase()));
static::createDb($config);
static::$connections[$dbKey] = new PostgresConnectionPool($config, $settings->getMaxConnections(), $settings->getIdleTimeout());

View File

@ -81,17 +81,18 @@ abstract class DriverArray implements DbArray, IteratorAggregate
return $this->offsetGet($key) !== null;
}
private function setSettings(SqlAbstract $settings): void {
private function setSettings(SqlAbstract $settings): void
{
$this->dbSettings = $settings;
$this->setCacheTtl($settings->getCacheTtl());
$this->setSerializer($settings->getSerializer());
}
public function __wakeup()
public function __wakeup(): void
{
$this->setSettings($this->dbSettings);
}
/** @param SqlAbstract $settings */
public static function getInstance(string $table, DbType|array|null $previous, DatabaseAbstract $settings): static
{
@ -106,7 +107,7 @@ abstract class DriverArray implements DbArray, IteratorAggregate
$instance->initConnection($settings);
$instance->prepareTable();
if (self::getClassName($previous) !== self::getClassName($instance)) {
if (self::getMigrationName($previous) !== self::getMigrationName($instance)) {
if ($previous instanceof DriverArray) {
$previous->initStartup();
}
@ -146,11 +147,13 @@ abstract class DriverArray implements DbArray, IteratorAggregate
}
private static function migrateDataToDb(self $new, DbArray|array|null $old): void
{
if (!empty($old) && self::getClassName($old) !== self::getClassName($new)) {
$oldName = self::getMigrationName($old);
$newName = self::getMigrationName($new);
if (!empty($old) && $oldName !== $newName) {
if (!$old instanceof DbArray) {
$old = MemoryArray::getInstance('', $old, new Memory);
}
Logger::log('Converting '.$old::class.' to '.$new::class, Logger::ERROR);
Logger::log("Converting $oldName to $newName", Logger::ERROR);
$counter = 0;
$total = \count($old);
@ -165,7 +168,10 @@ abstract class DriverArray implements DbArray, IteratorAggregate
}
$new->clearCache();
}
$old->clear();
if (self::getMigrationName($new, false) !== self::getMigrationName($old, false)) {
Logger::log("Dropping data from table {$old}", Logger::WARNING);
$old->clear();
}
Logger::log('Converting database done.', Logger::ERROR);
}
}
@ -214,13 +220,17 @@ abstract class DriverArray implements DbArray, IteratorAggregate
return \iterator_to_array($this->getIterator());
}
private static function getClassName($instance): ?string
private static function getMigrationName(DbType|array|null $instance, bool $include_serialization_type = true): ?string
{
if ($instance === null) {
return null;
} elseif (\is_array($instance)) {
return 'Array';
}
return \str_replace('NullCache\\', '', $instance::class);
$base = \str_replace('NullCache\\', '', $instance::class);
if ($include_serialization_type && $instance instanceof DriverArray) {
$base .= ' ('.$instance->dbSettings->getSerializer()->value.')';
}
return $base;
}
}

View File

@ -4,11 +4,9 @@ declare(strict_types=1);
namespace danog\MadelineProto\Db;
use Amp\Postgres\ByteA;
use danog\MadelineProto\Db\Driver\Postgres;
use danog\MadelineProto\Exception;
use danog\MadelineProto\Logger;
use danog\MadelineProto\Settings\Database\Postgres as DatabasePostgres;
use danog\MadelineProto\Settings\Database\SerializerType;
/**
@ -62,16 +60,16 @@ class PostgresArray extends PostgresArrayBytea
protected function setSerializer(SerializerType $serializer): void
{
$this->serializer = match ($serializer) {
SerializerType::SERIALIZE => fn ($v) => bin2hex(\serialize($v)),
SerializerType::IGBINARY => fn ($v) => bin2hex(\igbinary_serialize($v)),
SerializerType::JSON => fn ($v) => bin2hex(\json_encode($v, JSON_THROW_ON_ERROR|JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES)),
SerializerType::STRING => fn ($v) => bin2hex(\strval($v)),
SerializerType::SERIALIZE => fn ($v) => \bin2hex(\serialize($v)),
SerializerType::IGBINARY => fn ($v) => \bin2hex(\igbinary_serialize($v)),
SerializerType::JSON => fn ($v) => \bin2hex(\json_encode($v, JSON_THROW_ON_ERROR|JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES)),
SerializerType::STRING => fn ($v) => \bin2hex(\strval($v)),
};
$this->deserializer = match ($serializer) {
SerializerType::SERIALIZE => fn ($v) => \unserialize(hex2bin($v)),
SerializerType::IGBINARY => fn ($v) => \igbinary_unserialize(hex2bin($v)),
SerializerType::JSON => fn ($value) => \json_decode(hex2bin($value), true, 256, JSON_THROW_ON_ERROR),
SerializerType::STRING => fn ($v) => hex2bin($v),
SerializerType::SERIALIZE => fn ($v) => \unserialize(\hex2bin($v)),
SerializerType::IGBINARY => fn ($v) => \igbinary_unserialize(\hex2bin($v)),
SerializerType::JSON => fn ($value) => \json_decode(\hex2bin($value), true, 256, JSON_THROW_ON_ERROR),
SerializerType::STRING => fn ($v) => \hex2bin($v),
};
}
/**

View File

@ -49,7 +49,6 @@ use danog\MadelineProto\MTProtoTools\UpdatesState;
use danog\MadelineProto\SecretChats\MessageHandler;
use danog\MadelineProto\SecretChats\ResponseHandler;
use danog\MadelineProto\SecretChats\SeqNoHandler;
use danog\MadelineProto\Settings\Database\SerializerType;
use danog\MadelineProto\Settings\TLSchema;
use danog\MadelineProto\TL\Conversion\BotAPI;
use danog\MadelineProto\TL\Conversion\BotAPIFiles;
@ -503,12 +502,12 @@ final class MTProto implements TLCallback, LoggerGetter
* @see DbPropertiesFactory
*/
protected static array $dbProperties = [
'chats' => ['serializer' => SerializerType::SERIALIZE],
'full_chats' => ['serializer' => SerializerType::SERIALIZE],
'sponsoredMessages' => ['serializer' => SerializerType::SERIALIZE],
'channelParticipants' => ['serializer' => SerializerType::SERIALIZE],
'usernames' => ['serializer' => SerializerType::SERIALIZE],
'session' => ['serializer' => SerializerType::SERIALIZE, 'enableCache' => false],
'chats' => [],
'full_chats' => [],
'sponsoredMessages' => [],
'channelParticipants' => [],
'usernames' => [],
'session' => ['enableCache' => false],
];
/**

View File

@ -25,7 +25,6 @@ use danog\MadelineProto\Db\DbPropertiesTrait;
use danog\MadelineProto\Exception;
use danog\MadelineProto\Logger;
use danog\MadelineProto\MTProto;
use danog\MadelineProto\Settings\Database\SerializerType;
use danog\MadelineProto\TL\TLCallback;
use Revolt\EventLoop;
@ -69,7 +68,7 @@ final class MinDatabase implements TLCallback
* @see DbPropertiesFactory
*/
protected static array $dbProperties = [
'db' => ['serializer' => SerializerType::SERIALIZE],
'db' => [],
];
public function __construct(MTProto $API)

View File

@ -26,7 +26,6 @@ use danog\MadelineProto\Exception;
use danog\MadelineProto\Logger;
use danog\MadelineProto\MTProto;
use danog\MadelineProto\MTProto\OutgoingMessage;
use danog\MadelineProto\Settings\Database\SerializerType;
use danog\MadelineProto\TL\TLCallback;
use danog\MadelineProto\Tools;
use Webmozart\Assert\Assert;
@ -88,7 +87,7 @@ final class ReferenceDatabase implements TLCallback
* @see DbPropertiesFactory
*/
protected static array $dbProperties = [
'db' => ['serializer' => SerializerType::SERIALIZE],
'db' => [],
];
public function __construct(private MTProto $API)

View File

@ -30,7 +30,6 @@ use Amp\TimeoutException;
use danog\MadelineProto\Db\DbPropertiesFactory;
use danog\MadelineProto\Db\DriverArray;
use danog\MadelineProto\Ipc\Server;
use danog\MadelineProto\Settings\Database\SerializerType;
use danog\MadelineProto\Settings\DatabaseAbstract;
use Revolt\EventLoop;
use Throwable;
@ -215,7 +214,7 @@ abstract class Serialization
$unserialized = DbPropertiesFactory::get(
$settings,
$tableName,
['serializer' => SerializerType::SERIALIZE],
[],
$unserialized,
);
} else {

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace danog\MadelineProto\Settings\Database;
use danog\MadelineProto\Magic;
use danog\MadelineProto\Settings\DatabaseAbstract;
/**
@ -21,9 +22,11 @@ abstract class DriverDatabaseAbstract extends DatabaseAbstract
protected string $password = '';
/**
* Which serializer strategy to use by default.
* Which serializer to use by default.
*
* If null, the best serializater is chosen.
*/
protected SerializerType $serializer = SerializerType::SERIALIZE;
protected ?SerializerType $serializer = null;
public function mergeArray(array $settings): void
{
@ -112,10 +115,15 @@ abstract class DriverDatabaseAbstract extends DatabaseAbstract
public function getSerializer(): SerializerType
{
return $this->serializer;
return $this->serializer ?? (Magic::$can_use_igbinary ? SerializerType::IGBINARY : SerializerType::SERIALIZE);
}
public function setSerializer(SerializerType $serializer): void
/**
* Which serializer to use by default.
*
* If null, the best serializer is chosen.
*/
public function setSerializer(?SerializerType $serializer): void
{
$this->serializer = $serializer;
}

View File

@ -2,10 +2,10 @@
namespace danog\MadelineProto\Settings\Database;
enum SerializerType
enum SerializerType: string
{
case SERIALIZE;
case IGBINARY;
case JSON;
case STRING;
case SERIALIZE = 'serialize';
case IGBINARY = 'igbinary';
case JSON = 'json';
case STRING = 'string';
}