From d7a2ef38c38c0d0fdd7778bbec3f4bfb021903a3 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Sun, 13 Aug 2023 15:47:21 +0200 Subject: [PATCH] New ORM API --- psalm-baseline.xml | 134 ++-------------- src/Db/ArrayCacheTrait.php | 129 --------------- src/Db/CacheContainer.php | 148 ++++++++++++++++++ src/Db/CachedArray.php | 100 ++++++++++++ src/Db/DbArray.php | 45 +----- .../NullCacheTrait.php => DbArrayTrait.php} | 61 ++++---- src/Db/DbPropertiesFactory.php | 47 ++---- src/Db/DbType.php | 50 +++++- src/Db/DriverArray.php | 57 +------ src/Db/MemoryArray.php | 2 +- src/Db/MysqlArray.php | 2 +- src/Db/NullCache/MysqlArray.php | 34 ---- src/Db/NullCache/PostgresArray.php | 33 ---- src/Db/NullCache/PostgresArrayBytea.php | 33 ---- src/Db/NullCache/RedisArray.php | 34 ---- src/Db/PostgresArray.php | 2 +- src/Db/RedisArray.php | 19 +-- src/Db/SqlArray.php | 12 -- src/Settings/Database/Memory.php | 5 + src/Settings/Database/Mysql.php | 6 + src/Settings/Database/Postgres.php | 6 + src/Settings/Database/Redis.php | 6 + src/Settings/DatabaseAbstract.php | 4 + tests/testing.php | 1 - tools/build_docs/layerUpgrade.php | 2 +- tools/build_docs/merge.php | 2 +- tools/build_docs/schemas.php | 4 +- tools/layerdiff.php | 3 + tools/static.php | 1 + tools/std.php | 7 +- 30 files changed, 396 insertions(+), 593 deletions(-) delete mode 100644 src/Db/ArrayCacheTrait.php create mode 100644 src/Db/CacheContainer.php create mode 100644 src/Db/CachedArray.php rename src/Db/{NullCache/NullCacheTrait.php => DbArrayTrait.php} (58%) delete mode 100644 src/Db/NullCache/MysqlArray.php delete mode 100644 src/Db/NullCache/PostgresArray.php delete mode 100644 src/Db/NullCache/PostgresArrayBytea.php delete mode 100644 src/Db/NullCache/RedisArray.php diff --git a/psalm-baseline.xml b/psalm-baseline.xml index e0a840850..25b8f1810 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -45,10 +45,6 @@ $eventHandler - - loop - loop - getMessage isInited @@ -64,33 +60,6 @@ - - self::call($a) - self::call($b) - self::call($callable) - self::call($promise) - self::call($promise) - self::timeout($promise, $timeout) - - - $callable instanceof Generator - - - $callable - - - ]]> - - - $v instanceof Generator ? self::consumeGenerator($v) : $v]]> - - - all - any - first - some - wait - \is_callable($callable) @@ -227,18 +196,13 @@ permAuthKey =& $this->API->datacenter->getDataCenterConnection($dc)->permAuthKey]]> - - - $value - - - getCache - - - - - ]]> - + + + ttl[$index])]]> + + + $cacheTtl + @@ -268,9 +232,6 @@ $settings $settings - - $instance - $v $value @@ -285,14 +246,6 @@ $dbSettings $dbSettings $dbSettings - $dbSettings - $dbSettings - $dbSettings - $dbSettings - $deserializer - $deserializer - $deserializer - $deserializer $deserializer $deserializer $deserializer @@ -301,25 +254,14 @@ $serializer $serializer $serializer - $serializer - $serializer - $serializer - $serializer - $table - $table - $table - $table $table $table $table $table - - static - - + $old - + setSettings @@ -349,14 +291,8 @@ $pdo - $pdo - - - $value - - $v @@ -411,9 +347,6 @@ $db $db $db - $db - $db - $db fetchRow()['count']]]> @@ -434,10 +367,6 @@ $class - - getReportPeers())]]> - getReportPeers())]]> - wrapper->getAPI()]]> @@ -720,19 +649,6 @@ - - \danog\MadelineProto\AsyncTools::after($a, $b) - \danog\MadelineProto\AsyncTools::all($promises) - \danog\MadelineProto\AsyncTools::any($promises) - \danog\MadelineProto\AsyncTools::call($promise) - \danog\MadelineProto\AsyncTools::first($promises) - \danog\MadelineProto\AsyncTools::some($promises) - \danog\MadelineProto\AsyncTools::timeout($promise, $timeout) - \danog\MadelineProto\AsyncTools::timeoutWithDefault($promise, $timeout, $default) - \danog\MadelineProto\AsyncTools::wait($promise) - loop - loop - wrapper->getAPI()->getEventHandler($class)]]> @@ -745,19 +661,14 @@ MTProtoToTd MTProtoToTdcli - all - any completePhoneLogin downloadToCallable downloadToDir downloadToStream end - first - loop phoneLogin requestCall requestSecretChat - some start tdToTdcli upload @@ -766,7 +677,6 @@ uploadFromStream uploadFromTgfile uploadFromUrl - wait account ??= new \danog\MadelineProto\Namespace\AbstractAPI('account')]]> @@ -789,9 +699,6 @@ upload ??= new \danog\MadelineProto\Namespace\AbstractAPI('upload')]]> users ??= new \danog\MadelineProto\Namespace\AbstractAPI('users')]]> - - $callback - setWrapper setWrapper @@ -822,7 +729,6 @@ downloadToCallable downloadToDir downloadToFile - loop methodCallAsyncRead uploadFromCallable uploadFromTgfile @@ -1295,7 +1201,6 @@ chats]]> - minDatabase?->sync()]]> wrapper) && $this->isInited()]]> wrapper) && isset(self::$references[$this->getSessionName()])]]> @@ -1305,9 +1210,6 @@ \is_int($dc_id) datacenter)]]> - - minDatabase]]> - settings->getAppInfo()->getLangCode()]]]> @@ -1561,7 +1463,7 @@ $db - API->chats]]> + db]]> db]]> @@ -1717,15 +1619,11 @@ - - Tools::wait($callable()) - completeLogin createApp getApp hasApp - loop settings]]> @@ -1832,9 +1730,6 @@ $ipcSocket $ipcSocket - - $unserialized - @@ -2454,13 +2349,4 @@ $result - - - function ($_) use ($callback) { - - - $callback() - $callback() - - diff --git a/src/Db/ArrayCacheTrait.php b/src/Db/ArrayCacheTrait.php deleted file mode 100644 index 875239a06..000000000 --- a/src/Db/ArrayCacheTrait.php +++ /dev/null @@ -1,129 +0,0 @@ -. - * - * @author Daniil Gentili - * @copyright 2016-2023 Daniil Gentili - * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 - * @link https://docs.madelineproto.xyz MadelineProto documentation - */ - -namespace danog\MadelineProto\Db; - -use danog\MadelineProto\Logger; -use Revolt\EventLoop; - -/** - * Array caching trait. - * - * @internal - */ -trait ArrayCacheTrait -{ - /** - * @var array - */ - private array $cache = []; - /** - * @var array - */ - private array $ttl = []; - - private int $cacheTtl = 5 * 60; - - /** - * Cache cleanup watcher ID. - */ - private ?string $cacheCleanupId = null; - - protected function setCacheTtl(int $ttl): void - { - $this->cacheTtl = $ttl; - } - - protected function getCache(string $key) - { - $this->ttl[$key] = \time() + $this->cacheTtl; - return $this->cache[$key]; - } - - protected function hasCache(string $key): bool - { - return isset($this->ttl[$key]); - } - - /** - * Save item in cache. - */ - protected function setCache(string $key, $value): void - { - $this->cache[$key] = $value; - $this->ttl[$key] = \time() + $this->cacheTtl; - } - - /** - * Remove key from cache. - */ - protected function unsetCache(string $key): void - { - unset($this->cache[$key], $this->ttl[$key]); - } - - protected function startCacheCleanupLoop(): void - { - $this->cacheCleanupId = EventLoop::repeat( - \max(1, $this->cacheTtl / 5), - fn () => $this->cleanupCache(), - ); - } - protected function stopCacheCleanupLoop(): void - { - if ($this->cacheCleanupId) { - EventLoop::cancel($this->cacheCleanupId); - $this->cacheCleanupId = null; - } - } - - protected function clearCache(): void - { - $this->cache = []; - $this->ttl = []; - } - - /** - * Remove all keys from cache. - */ - private function cleanupCache(): void - { - $newValues = []; - $newTtl = []; - $now = \time(); - $oldCount = 0; - foreach ($this->ttl as $key => $ttl) { - if ($ttl < $now) { - $oldCount++; - } else { - $newTtl[$key] = $this->ttl[$key]; - $newValues[$key] = $this->cache[$key]; - } - } - $this->ttl = $newTtl; - $this->cache = $newValues; - - Logger::log( - \sprintf( - 'cache for table: %s; keys left: %s; keys removed: %s', - (string) $this, - \count($this->cache), - $oldCount, - ), - Logger::VERBOSE, - ); - } -} diff --git a/src/Db/CacheContainer.php b/src/Db/CacheContainer.php new file mode 100644 index 000000000..47dd8baa1 --- /dev/null +++ b/src/Db/CacheContainer.php @@ -0,0 +1,148 @@ +. + * + * @author Daniil Gentili + * @copyright 2016-2023 Daniil Gentili + * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 + * @link https://docs.madelineproto.xyz MadelineProto documentation + */ + +namespace danog\MadelineProto\Db; + +use Amp\Sync\LocalMutex; +use Revolt\EventLoop; +use Traversable; + +/** @internal */ +final class CacheContainer +{ + /** + * @var array + */ + private array $cache = []; + /** + * @var array + */ + private array $ttl = []; + + private int $cacheTtl; + + /** + * Cache cleanup watcher ID. + */ + private ?string $cacheCleanupId = null; + + private LocalMutex $mutex; + + public function __construct( + public DbType $inner + ) { + $this->mutex = new LocalMutex; + } + public function __sleep() + { + $this->flushCache(); + return ['cache', 'ttl', 'inner']; + } + + public function startCacheCleanupLoop(int $cacheTtl): void + { + $this->cacheTtl = $cacheTtl; + if ($this->cacheCleanupId) { + EventLoop::cancel($this->cacheCleanupId); + } + $this->cacheCleanupId = EventLoop::repeat( + \max(1, $this->cacheTtl / 5), + fn () => $this->flushCache(), + ); + } + public function stopCacheCleanupLoop(): void + { + if ($this->cacheCleanupId) { + EventLoop::cancel($this->cacheCleanupId); + $this->cacheCleanupId = null; + } + } + + public function get(string|int $index): mixed + { + if (isset($this->ttl[$index])) { + return $this->cache[$index]; + } + + $result = $this->inner->offsetGet($index); + if (isset($this->ttl[$index])) { + return $this->cache[$index]; + } + + $this->ttl[$index] = \time() + $this->cacheTtl; + $this->cache[$index] = $result; + + return $result; + } + + public function set(string|int $key, mixed $value): void + { + $this->cache[$key] = $value; + $this->ttl[$key] = true; + } + + public function getIterator(): Traversable + { + $this->flushCache(); + return $this->inner->getIterator(); + } + + public function count(): int + { + $this->flushCache(); + return $this->inner->count(); + } + + public function clear(): void + { + $lock = $this->mutex->acquire(); + $this->cache = []; + $this->ttl = []; + $lock->release(); + + $this->inner->clear(); + } + + /** + * Flush all flushable keys. + */ + public function flushCache(): void + { + $lock = $this->mutex->acquire(); + try { + $newValues = []; + $newTtl = []; + $now = \time(); + foreach ($this->ttl as $key => &$ttl) { + if ($ttl === true) { + if ($this->cache[$key] === null) { + $this->inner->unset($key); + } else { + $this->inner->set($key, $this->cache[$key]); + } + $ttl = \time() + $this->cacheTtl; + } elseif ($ttl > $now) { + $newTtl[$key] = $this->ttl[$key]; + $newValues[$key] = $this->cache[$key]; + } + } + $this->ttl = $newTtl; + $this->cache = $newValues; + } finally { + $lock->release(); + } + } +} diff --git a/src/Db/CachedArray.php b/src/Db/CachedArray.php new file mode 100644 index 000000000..9c6778512 --- /dev/null +++ b/src/Db/CachedArray.php @@ -0,0 +1,100 @@ +. + * + * @author Daniil Gentili + * @copyright 2016-2023 Daniil Gentili + * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 + * @link https://docs.madelineproto.xyz MadelineProto documentation + */ + +namespace danog\MadelineProto\Db; + +use danog\MadelineProto\Settings\Database\DriverDatabaseAbstract; +use danog\MadelineProto\Settings\DatabaseAbstract; +use Traversable; + +/** + * Array caching proxy. + * + * @internal + * + * @template TKey as array-key + * @template TValue + * + * @implements DbArray + */ +final class CachedArray implements DbArray +{ + use DbArrayTrait; + + private CacheContainer $cache; + + /** + * Get instance. + */ + public static function getInstance(string $table, DbType|null $previous, DatabaseAbstract $settings): DbType + { + $new = $settings->getDriverClass(); + if ($previous === null) { + $previous = new self($new::getInstance($table, null, $settings)); + } elseif ($previous instanceof self) { + $previous->cache->inner = $new::getInstance($table, $previous->cache->inner, $settings); + } else { + $previous = new self($new::getInstance($table, $previous, $settings)); + } + if ($previous->cache->inner instanceof MemoryArray) { + $previous->cache->flushCache(); + return $previous->cache->inner; + } + \assert($settings instanceof DriverDatabaseAbstract); + $previous->cache->startCacheCleanupLoop($settings->getCacheTtl()); + return $previous; + } + + public function __construct(DbType $inner) + { + $this->cache = new CacheContainer($inner); + } + + public function __destruct() + { + $this->cache->stopCacheCleanupLoop(); + } + + public function count(): int + { + return $this->cache->count(); + } + + public function clear(): void + { + $this->cache->clear(); + } + + public function offsetGet(mixed $index): mixed + { + return $this->cache->get($index); + } + + public function set(string|int $key, mixed $value): void + { + $this->cache->set($key, $value); + } + + public function unset(string|int $key): void + { + $this->cache->set($key, null); + } + + public function getIterator(): Traversable + { + return $this->cache->getIterator(); + } +} diff --git a/src/Db/DbArray.php b/src/Db/DbArray.php index da98c6301..9c5c379d6 100644 --- a/src/Db/DbArray.php +++ b/src/Db/DbArray.php @@ -17,7 +17,6 @@ namespace danog\MadelineProto\Db; use ArrayAccess; -use Countable; /** * DB array interface. @@ -26,40 +25,10 @@ use Countable; * @template TValue * * @extends ArrayAccess + * @extends DbType */ -interface DbArray extends DbType, ArrayAccess, Countable +interface DbArray extends DbType, ArrayAccess { - /** - * Get Array copy. - * - * @psalm-return array - */ - public function getArrayCopy(): array; - /** - * Check if element is set. - * - * @param TKey $key - */ - public function isset(string|int $key): bool; - /** - * Unset element. - * - * @param TKey $key - */ - public function unset(string|int $key): void; - /** - * Set element. - * - * @param TKey $key - * @param TValue $value - */ - public function set(string|int $key, mixed $value): void; - /** - * Get element. - * - * @param TKey $index - */ - public function offsetGet(mixed $index): mixed; /** * Set element. * @@ -79,13 +48,9 @@ interface DbArray extends DbType, ArrayAccess, Countable */ public function offsetExists(mixed $index): bool; /** - * Clear all elements. - */ - public function clear(): void; - /** - * Get iterator. + * Get Array copy. * - * @return \Traversable + * @psalm-return array */ - public function getIterator(): \Traversable; + public function getArrayCopy(): array; } diff --git a/src/Db/NullCache/NullCacheTrait.php b/src/Db/DbArrayTrait.php similarity index 58% rename from src/Db/NullCache/NullCacheTrait.php rename to src/Db/DbArrayTrait.php index 1f2587abd..522465c11 100644 --- a/src/Db/NullCache/NullCacheTrait.php +++ b/src/Db/DbArrayTrait.php @@ -14,52 +14,45 @@ * @link https://docs.madelineproto.xyz MadelineProto documentation */ -namespace danog\MadelineProto\Db\NullCache; - -use RuntimeException; +namespace danog\MadelineProto\Db; /** - * Trait that disables database caching. - * - * @internal + * DB array trait. */ -trait NullCacheTrait +trait DbArrayTrait { - protected function setCacheTtl(int $ttl): void + /** + * Check if key isset. + * + * @param mixed $key + * @return bool true if the offset exists, otherwise false + */ + final public function isset(string|int $key): bool { - } - protected function hasCache(string $key): bool - { - return false; + return $this->offsetGet($key) !== null; } - protected function getCache(string $key): void + /** @param string|int $index */ + final public function offsetExists(mixed $index): bool { - throw new RuntimeException('Not implemented!'); + return $this->isset($index); + } + + final public function offsetSet(mixed $index, mixed $value): void + { + $this->set($index, $value); + } + + final public function offsetUnset(mixed $index): void + { + $this->unset($index); } /** - * Save item in cache. + * Get array copy. */ - protected function setCache(string $key, $value): void - { - } - - /** - * Remove key from cache. - */ - protected function unsetCache(string $key): void - { - } - - protected function clearCache(): void - { - } - - protected function startCacheCleanupLoop(): void - { - } - protected function stopCacheCleanupLoop(): void + final public function getArrayCopy(): array { + return \iterator_to_array($this->getIterator()); } } diff --git a/src/Db/DbPropertiesFactory.php b/src/Db/DbPropertiesFactory.php index f15ddad9c..078aee6d1 100644 --- a/src/Db/DbPropertiesFactory.php +++ b/src/Db/DbPropertiesFactory.php @@ -18,13 +18,8 @@ namespace danog\MadelineProto\Db; use danog\MadelineProto\Magic; use danog\MadelineProto\Settings\Database\DriverDatabaseAbstract; -use danog\MadelineProto\Settings\Database\Memory; -use danog\MadelineProto\Settings\Database\Mysql; -use danog\MadelineProto\Settings\Database\Postgres; -use danog\MadelineProto\Settings\Database\Redis; use danog\MadelineProto\Settings\Database\SerializerType; use danog\MadelineProto\Settings\DatabaseAbstract; -use InvalidArgumentException; /** * This factory class initializes the correct database backend for MadelineProto. @@ -35,30 +30,27 @@ final class DbPropertiesFactory { /** * @param array{serializer?: SerializerType, enableCache?: bool, cacheTtl?: int, innerMadelineProto?: bool, innerMadelineProtoSerializer?: SerializerType}|'array' $config - * @return DbType * @internal * @uses \danog\MadelineProto\Db\MemoryArray * @uses \danog\MadelineProto\Db\MysqlArray * @uses \danog\MadelineProto\Db\PostgresArray * @uses \danog\MadelineProto\Db\RedisArray */ - public static function get(DatabaseAbstract $dbSettings, string $table, string|array $config, ?DbType $value = null) + public static function get(DatabaseAbstract $dbSettings, string $table, string|array $config, ?DbType $value = null): DbArray { // Legacy if ($config === 'array') { $config = []; } - $dbSettingsCopy = clone $dbSettings; - $class = __NAMESPACE__; + $dbSettings = clone $dbSettings; - if ($dbSettingsCopy instanceof DriverDatabaseAbstract) { + if ($dbSettings instanceof DriverDatabaseAbstract) { $config = \array_merge([ - 'serializer' => $dbSettingsCopy->getSerializer() ?? ( + 'serializer' => $dbSettings->getSerializer() ?? ( Magic::$can_use_igbinary ? SerializerType::IGBINARY : SerializerType::SERIALIZE ), 'innerMadelineProto' => false, - 'enableCache' => true, - 'cacheTtl' => $dbSettingsCopy->getCacheTtl(), + 'cacheTtl' => $dbSettings->getCacheTtl(), ], $config); if ($config['innerMadelineProto'] @@ -73,31 +65,12 @@ final class DbPropertiesFactory ); } - $class = $dbSettings instanceof DriverDatabaseAbstract && (!($config['enableCache'] ?? true) || !$config['cacheTtl']) - ? __NAMESPACE__ . '\\NullCache' - : __NAMESPACE__; - - $dbSettingsCopy->setSerializer($config['serializer']); - $dbSettingsCopy->setCacheTtl($config['cacheTtl']); + $dbSettings->setSerializer($config['serializer']); + $dbSettings->setCacheTtl($config['cacheTtl']); } - switch (true) { - case $dbSettings instanceof Memory: - $class .= '\\MemoryArray'; - break; - case $dbSettings instanceof Mysql: - $class .= '\\MysqlArray'; - break; - case $dbSettings instanceof Postgres: - $class .= '\\PostgresArrayBytea'; - break; - case $dbSettings instanceof Redis: - $class .= '\\RedisArray'; - break; - default: - throw new InvalidArgumentException('Unknown dbType: ' . $dbSettings::class); - } - /** @var DbType $class */ - return $class::getInstance($table, $value, $dbSettingsCopy); + $result = CachedArray::getInstance($table, $value, $dbSettings); + \assert($result instanceof DbArray); + return $result; } } diff --git a/src/Db/DbType.php b/src/Db/DbType.php index 53adb3b81..f550bf6c1 100644 --- a/src/Db/DbType.php +++ b/src/Db/DbType.php @@ -16,9 +16,55 @@ namespace danog\MadelineProto\Db; +use Countable; use danog\MadelineProto\Settings\DatabaseAbstract; -interface DbType +/** + * DB type interface. + * + * @template TKey as array-key + * @template TValue + */ +interface DbType extends Countable { - public static function getInstance(string $table, DbType|array|null $previous, DatabaseAbstract $settings): static; + /** + * Check if element is set. + * + * @param TKey $key + */ + public function isset(string|int $key): bool; + /** + * Unset element. + * + * @param TKey $key + */ + public function unset(string|int $key): void; + /** + * Set element. + * + * @param TKey $key + * @param TValue $value + */ + public function set(string|int $key, mixed $value): void; + /** + * Get element. + * + * @param TKey $index + */ + public function offsetGet(mixed $index): mixed; + /** + * Clear all elements. + */ + public function clear(): void; + /** + * Get iterator. + * + * @return \Traversable + */ + public function getIterator(): \Traversable; + + /** + * Get instance. + */ + public static function getInstance(string $table, DbType|null $previous, DatabaseAbstract $settings): self; } diff --git a/src/Db/DriverArray.php b/src/Db/DriverArray.php index b6bdeee4d..51145ebb5 100644 --- a/src/Db/DriverArray.php +++ b/src/Db/DriverArray.php @@ -19,10 +19,8 @@ namespace danog\MadelineProto\Db; use danog\MadelineProto\Logger; use danog\MadelineProto\Magic; use danog\MadelineProto\Settings\Database\DriverDatabaseAbstract; -use danog\MadelineProto\Settings\Database\Memory; use danog\MadelineProto\Settings\Database\SerializerType; use danog\MadelineProto\Settings\DatabaseAbstract; -use IteratorAggregate; use function Amp\async; use function Amp\Future\await; @@ -35,10 +33,9 @@ use function Amp\Future\await; * @template TKey as array-key * @template TValue * - * @implements IteratorAggregate - * @implements DbArray + * @implements DbType */ -abstract class DriverArray implements DbArray, IteratorAggregate +abstract class DriverArray implements DbType { protected string $table; /** @var callable(mixed): mixed */ @@ -47,8 +44,6 @@ abstract class DriverArray implements DbArray, IteratorAggregate protected $deserializer; protected DriverDatabaseAbstract $dbSettings; - use ArrayCacheTrait; - /** * Initialize on startup. */ @@ -82,13 +77,7 @@ abstract class DriverArray implements DbArray, IteratorAggregate return $this; } - /** - * Check if key isset. - * - * @param mixed $key - * @return bool true if the offset exists, otherwise false - */ - public function isset(string|int $key): bool + final public function isset(string|int $key): bool { return $this->offsetGet($key) !== null; } @@ -96,7 +85,6 @@ abstract class DriverArray implements DbArray, IteratorAggregate private function setSettings(DriverDatabaseAbstract $settings): void { $this->dbSettings = $settings; - $this->setCacheTtl($settings->getCacheTtl()); $this->setSerializer($settings->getSerializer() ?? ( Magic::$can_use_igbinary ? SerializerType::IGBINARY : SerializerType::SERIALIZE )); @@ -112,7 +100,7 @@ abstract class DriverArray implements DbArray, IteratorAggregate } } - public static function getInstance(string $table, DbType|array|null $previous, DatabaseAbstract $settings): static + public static function getInstance(string $table, DbType|null $previous, DatabaseAbstract $settings): DbType { /** @var MysqlArray|PostgresArray|RedisArray */ $instance = new static(); @@ -122,8 +110,6 @@ abstract class DriverArray implements DbArray, IteratorAggregate $instance->setSettings($settings); - $instance->startCacheCleanupLoop(); - $instance->initConnection($settings); $instance->prepareTable(); @@ -165,14 +151,11 @@ abstract class DriverArray implements DbArray, IteratorAggregate SerializerType::STRING => fn ($v) => $v, }; } - private static function migrateDataToDb(self $new, DbArray|array|null $old): void + private static function migrateDataToDb(self $new, DbArray|null $old): void { $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 $oldName to $newName", Logger::ERROR); $counter = 0; @@ -186,7 +169,6 @@ abstract class DriverArray implements DbArray, IteratorAggregate $promises = []; Logger::log("Loading data to table {$newName}: $counter/$total", Logger::WARNING); } - $new->clearCache(); } if (self::getMigrationName($new, false) !== self::getMigrationName($old, false)) { Logger::log("Dropping data from table {$oldName}", Logger::WARNING); @@ -196,11 +178,6 @@ abstract class DriverArray implements DbArray, IteratorAggregate } } - public function __destruct() - { - $this->stopCacheCleanupLoop(); - } - /** * Get the value of table. */ @@ -216,30 +193,6 @@ abstract class DriverArray implements DbArray, IteratorAggregate { return ['table', 'dbSettings']; } - - final public function offsetExists($index): bool - { - return $this->isset($index); - } - - final public function offsetSet(mixed $index, mixed $value): void - { - $this->set($index, $value); - } - - final public function offsetUnset(mixed $index): void - { - $this->unset($index); - } - - /** - * Get array copy. - */ - public function getArrayCopy(): array - { - return \iterator_to_array($this->getIterator()); - } - private static function getMigrationName(DbType|array|null $instance, bool $include_serialization_type = true): ?string { if ($instance === null) { diff --git a/src/Db/MemoryArray.php b/src/Db/MemoryArray.php index e89b09e35..cfb8471d1 100644 --- a/src/Db/MemoryArray.php +++ b/src/Db/MemoryArray.php @@ -40,7 +40,7 @@ final class MemoryArray extends ArrayIterator implements DbArray /** * @param Memory $settings */ - public static function getInstance(string $table, DbType|array|null $previous, $settings): static + public static function getInstance(string $table, DbType|null $previous, $settings): DbType { if ($previous instanceof MemoryArray) { return $previous; diff --git a/src/Db/MysqlArray.php b/src/Db/MysqlArray.php index e4099aaa6..892217aec 100644 --- a/src/Db/MysqlArray.php +++ b/src/Db/MysqlArray.php @@ -33,7 +33,7 @@ use PDO; * @template TValue * @extends SqlArray */ -class MysqlArray extends SqlArray +final class MysqlArray extends SqlArray { // We're forced to use quoting (just like PDO does internally when using prepares) because native MySQL prepares are extremely slow. protected PDO $pdo; diff --git a/src/Db/NullCache/MysqlArray.php b/src/Db/NullCache/MysqlArray.php deleted file mode 100644 index d0addd853..000000000 --- a/src/Db/NullCache/MysqlArray.php +++ /dev/null @@ -1,34 +0,0 @@ -. - * - * @author Daniil Gentili - * @copyright 2016-2023 Daniil Gentili - * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 - * @link https://docs.madelineproto.xyz MadelineProto documentation - */ - -namespace danog\MadelineProto\Db\NullCache; - -use danog\MadelineProto\Db\MysqlArray as DbMysqlArray; - -/** - * MySQL database backend, no caching. - * - * @internal - * - * @template TKey as array-key - * @template TValue - * - * @extends DbMysqlArray - */ -final class MysqlArray extends DbMysqlArray -{ - use NullCacheTrait; -} diff --git a/src/Db/NullCache/PostgresArray.php b/src/Db/NullCache/PostgresArray.php deleted file mode 100644 index c309c2c79..000000000 --- a/src/Db/NullCache/PostgresArray.php +++ /dev/null @@ -1,33 +0,0 @@ -. - * - * @author Daniil Gentili - * @copyright 2016-2023 Daniil Gentili - * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 - * @link https://docs.madelineproto.xyz MadelineProto documentation - */ - -namespace danog\MadelineProto\Db\NullCache; - -use danog\MadelineProto\Db\PostgresArray as DbPostgresArray; - -/** - * Postgres database backend, no caching. - * - * @template TKey as array-key - * @template TValue - * - * @extends DbPostgresArray - * @internal - */ -final class PostgresArray extends DbPostgresArray -{ - use NullCacheTrait; -} diff --git a/src/Db/NullCache/PostgresArrayBytea.php b/src/Db/NullCache/PostgresArrayBytea.php deleted file mode 100644 index bdf42e50b..000000000 --- a/src/Db/NullCache/PostgresArrayBytea.php +++ /dev/null @@ -1,33 +0,0 @@ -. - * - * @author Daniil Gentili - * @copyright 2016-2023 Daniil Gentili - * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 - * @link https://docs.madelineproto.xyz MadelineProto documentation - */ - -namespace danog\MadelineProto\Db\NullCache; - -use danog\MadelineProto\Db\PostgresArrayBytea as DbPostgresArrayBytea; - -/** - * Postgres database backend, no caching. - * - * @template TKey as array-key - * @template TValue - * - * @extends DbPostgresArrayBytea - * @internal - */ -final class PostgresArrayBytea extends DbPostgresArrayBytea -{ - use NullCacheTrait; -} diff --git a/src/Db/NullCache/RedisArray.php b/src/Db/NullCache/RedisArray.php deleted file mode 100644 index 01d389040..000000000 --- a/src/Db/NullCache/RedisArray.php +++ /dev/null @@ -1,34 +0,0 @@ -. - * - * @author Daniil Gentili - * @copyright 2016-2023 Daniil Gentili - * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 - * @link https://docs.madelineproto.xyz MadelineProto documentation - */ - -namespace danog\MadelineProto\Db\NullCache; - -use danog\MadelineProto\Db\RedisArray as DbRedisArray; - -/** - * Redis database backend, no caching. - * - * @internal - * - * @template TKey as array-key - * @template TValue - * - * @extends DbRedisArray - */ -final class RedisArray extends DbRedisArray -{ - use NullCacheTrait; -} diff --git a/src/Db/PostgresArray.php b/src/Db/PostgresArray.php index cde219e46..b4862b6fb 100644 --- a/src/Db/PostgresArray.php +++ b/src/Db/PostgresArray.php @@ -29,7 +29,7 @@ use danog\MadelineProto\Settings\Database\SerializerType; * @template TValue * @extends PostgresArrayBytea */ -class PostgresArray extends PostgresArrayBytea +final class PostgresArray extends PostgresArrayBytea { /** * Prepare statements. diff --git a/src/Db/RedisArray.php b/src/Db/RedisArray.php index 81a45c71b..e9890d566 100644 --- a/src/Db/RedisArray.php +++ b/src/Db/RedisArray.php @@ -30,7 +30,7 @@ use danog\MadelineProto\Settings\Database\Redis as DatabaseRedis; * @template TValue * @extends DriverArray */ -class RedisArray extends DriverArray +final class RedisArray extends DriverArray { private RedisRedis $db; @@ -87,27 +87,17 @@ class RedisArray extends DriverArray } public function set(string|int $key, mixed $value): void { - if ($this->hasCache($key) && $this->getCache($key) === $value) { - return; - } - - $this->setCache($key, $value); - $this->db->set($this->rKey($key), ($this->serializer)($value)); - $this->setCache($key, $value); } public function offsetGet(mixed $offset): mixed { $offset = (string) $offset; - if ($this->hasCache($offset)) { - return $this->getCache($offset); - } $value = $this->db->get($this->rKey($offset)); - if ($value !== null && $value = ($this->deserializer)($value)) { - $this->setCache($offset, $value); + if ($value !== null) { + $value = ($this->deserializer)($value); } return $value; @@ -115,8 +105,6 @@ class RedisArray extends DriverArray public function unset(string|int $key): void { - $this->unsetCache($key); - $this->db->delete($this->rkey($key)); } @@ -152,7 +140,6 @@ class RedisArray extends DriverArray */ public function clear(): void { - $this->clearCache(); $request = $this->db->scan($this->itKey()); $keys = []; diff --git a/src/Db/SqlArray.php b/src/Db/SqlArray.php index a2d2a78d9..737c763c8 100644 --- a/src/Db/SqlArray.php +++ b/src/Db/SqlArray.php @@ -82,9 +82,6 @@ abstract class SqlArray extends DriverArray public function offsetGet(mixed $key): mixed { $key = (string) $key; - if ($this->hasCache($key)) { - return $this->getCache($key); - } $row = $this->execute($this->queries[self::SQL_GET], ['index' => $key])->fetchRow(); if ($row === null) { @@ -92,7 +89,6 @@ abstract class SqlArray extends DriverArray } $value = ($this->deserializer)($row['value']); - $this->setCache($key, $value); return $value; } @@ -100,11 +96,6 @@ abstract class SqlArray extends DriverArray public function set(string|int $key, mixed $value): void { $key = (string) $key; - if ($this->hasCache($key) && $this->getCache($key) === $value) { - return; - } - - $this->setCache($key, $value); $this->execute( $this->queries[self::SQL_SET], @@ -113,7 +104,6 @@ abstract class SqlArray extends DriverArray 'value' => ($this->serializer)($value), ], ); - $this->setCache($key, $value); } /** @@ -124,7 +114,6 @@ abstract class SqlArray extends DriverArray public function unset(string|int $key): void { $key = (string) $key; - $this->unsetCache($key); $this->execute( $this->queries[self::SQL_UNSET], @@ -151,7 +140,6 @@ abstract class SqlArray extends DriverArray */ public function clear(): void { - $this->clearCache(); $this->execute($this->queries[self::SQL_CLEAR]); } diff --git a/src/Settings/Database/Memory.php b/src/Settings/Database/Memory.php index ac3afa866..b8e1fdd46 100644 --- a/src/Settings/Database/Memory.php +++ b/src/Settings/Database/Memory.php @@ -16,6 +16,7 @@ namespace danog\MadelineProto\Settings\Database; +use danog\MadelineProto\Db\MemoryArray; use danog\MadelineProto\Settings\DatabaseAbstract; /** @@ -23,4 +24,8 @@ use danog\MadelineProto\Settings\DatabaseAbstract; */ final class Memory extends DatabaseAbstract { + public function getDriverClass(): string + { + return MemoryArray::class; + } } diff --git a/src/Settings/Database/Mysql.php b/src/Settings/Database/Mysql.php index d4f3c06e7..16f15c3f4 100644 --- a/src/Settings/Database/Mysql.php +++ b/src/Settings/Database/Mysql.php @@ -16,6 +16,8 @@ namespace danog\MadelineProto\Settings\Database; +use danog\MadelineProto\Db\MysqlArray; + /** * MySQL backend settings. * @@ -23,6 +25,10 @@ namespace danog\MadelineProto\Settings\Database; */ final class Mysql extends SqlAbstract { + public function getDriverClass(): string + { + return MysqlArray::class; + } public function mergeArray(array $settings): void { $settings = $settings['db']['mysql'] ?? []; diff --git a/src/Settings/Database/Postgres.php b/src/Settings/Database/Postgres.php index 83b7c2453..17493863f 100644 --- a/src/Settings/Database/Postgres.php +++ b/src/Settings/Database/Postgres.php @@ -16,11 +16,17 @@ namespace danog\MadelineProto\Settings\Database; +use danog\MadelineProto\Db\PostgresArrayBytea; + /** * Postgres backend settings. */ final class Postgres extends SqlAbstract { + public function getDriverClass(): string + { + return PostgresArrayBytea::class; + } public function mergeArray(array $settings): void { $settings = $settings['db']['postgres'] ?? []; diff --git a/src/Settings/Database/Redis.php b/src/Settings/Database/Redis.php index 3e269627d..593d9c9cf 100644 --- a/src/Settings/Database/Redis.php +++ b/src/Settings/Database/Redis.php @@ -16,11 +16,17 @@ namespace danog\MadelineProto\Settings\Database; +use danog\MadelineProto\Db\RedisArray; + /** * Redis backend settings. */ final class Redis extends DriverDatabaseAbstract { + public function getDriverClass(): string + { + return RedisArray::class; + } /** * Database number. */ diff --git a/src/Settings/DatabaseAbstract.php b/src/Settings/DatabaseAbstract.php index 1380bf6d9..a94ccb5ce 100644 --- a/src/Settings/DatabaseAbstract.php +++ b/src/Settings/DatabaseAbstract.php @@ -16,6 +16,7 @@ namespace danog\MadelineProto\Settings; +use danog\MadelineProto\Db\DbType; use danog\MadelineProto\SettingsAbstract; /** @@ -143,4 +144,7 @@ abstract class DatabaseAbstract extends SettingsAbstract return $this; } + + /** @return class-string */ + abstract public function getDriverClass(): string; } diff --git a/tests/testing.php b/tests/testing.php index 990381dea..c2bc34ba1 100755 --- a/tests/testing.php +++ b/tests/testing.php @@ -344,4 +344,3 @@ foreach (json_decode(getenv('TEST_DESTINATION_GROUPS'), true) as $peer) { $sentMessage = $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message, 'entities' => [['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => mb_strlen($message), 'user_id' => $mention]]]); $MadelineProto->logger($sentMessage, Logger::NOTICE); } -}); diff --git a/tools/build_docs/layerUpgrade.php b/tools/build_docs/layerUpgrade.php index f24739c45..32b7cf7de 100644 --- a/tools/build_docs/layerUpgrade.php +++ b/tools/build_docs/layerUpgrade.php @@ -4,7 +4,7 @@ * Upgrade layer number. * * @param integer $layer Layer number - * + * @internal */ function layerUpgrade(int $layer): void { diff --git a/tools/build_docs/merge.php b/tools/build_docs/merge.php index 6a7843a0e..6f1b645ff 100644 --- a/tools/build_docs/merge.php +++ b/tools/build_docs/merge.php @@ -4,7 +4,7 @@ use danog\MadelineProto\Lang; /** * Merge extracted docs. - * + * @internal */ function mergeExtracted(): void { diff --git a/tools/build_docs/schemas.php b/tools/build_docs/schemas.php index bea1c6da1..d35af1643 100644 --- a/tools/build_docs/schemas.php +++ b/tools/build_docs/schemas.php @@ -2,7 +2,7 @@ /** * Load schema file names. - * + * @internal */ function loadSchemas(): array { @@ -19,6 +19,7 @@ function loadSchemas(): array * Return max available layer number. * * @param array $schemas Scheme array + * @internal * * @return integer */ @@ -32,6 +33,7 @@ function maxLayer(array $schemas): int * Init docs. * * @param array $layers Scheme array + * @internal * * @return array Documentation information for old docs */ diff --git a/tools/layerdiff.php b/tools/layerdiff.php index 757acdb79..d30319587 100644 --- a/tools/layerdiff.php +++ b/tools/layerdiff.php @@ -30,6 +30,8 @@ if ($argc !== 3) { * * @param int $layer Layer number * + * @internal + * * @return void */ function getTL($layer) @@ -40,6 +42,7 @@ function getTL($layer) return ['methods' => $layer->getMethods(), 'constructors' => $layer->getConstructors()]; } +/** @internal */ function getUrl($constructor, $type) { $orig = $constructor; diff --git a/tools/static.php b/tools/static.php index 89317d4ce..f080c94dd 100644 --- a/tools/static.php +++ b/tools/static.php @@ -9,6 +9,7 @@ require 'vendor/autoload.php'; $class = new \ReflectionClass(Tools::class); $methods = $class->getMethods(ReflectionMethod::IS_STATIC | ReflectionMethod::IS_PUBLIC); +/** @internal */ function ssort($a, $b) { return strlen($b->getName())-strlen($a->getName()); diff --git a/tools/std.php b/tools/std.php index f0128381a..d089e8615 100644 --- a/tools/std.php +++ b/tools/std.php @@ -15,12 +15,7 @@ foreach ($classes as $class) { } $methods = array_unique($methods); -function ssort($a, $b) -{ - return strlen($b->getName())-strlen($a->getName()); -} - -usort($methods, 'ssort'); +usort($methods, fn ($a, $b) => strlen($b->getName())-strlen($a->getName())); $find = []; $replace = [];