From 17a320b7c8516856e24ae494c54874d3cfdb8ffc Mon Sep 17 00:00:00 2001 From: Roman Kelesidis Date: Mon, 22 Jul 2024 14:55:04 +0700 Subject: [PATCH] =?UTF-8?q?Refactored=20cache=20drivers=20=F0=9F=97=83=20(?= =?UTF-8?q?#1553)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refactored cache drivers 🗃 * Updated * Update APCu.php * Update APCu.php * Update APCu.php * Update APCu.php * Update APCu.php * Update Redis.php * Update Redis.php * Updated * Update * Updated * Update config.php * Updated * Updated * Updated * Updated * Update config.php * Updated * Update composer.lock * Delete composer.lock * Create composer.lock * Update composer.lock * Update common.php * Update File.php * Updated * Update Sqlite.php * Update common.php * Update Redis.php * Updated * Update common.php * Updated --- common.php | 15 +- composer.json | 2 + composer.lock | 456 ++++++++++++++++++++++-- install/sql/mysql.sql | 3 - library/config.php | 26 +- library/includes/cron/jobs/cache_gc.php | 21 -- src/Legacy/Cache/APCu.php | 118 ++++-- src/Legacy/Cache/Common.php | 45 ++- src/Legacy/Cache/File.php | 170 ++++----- src/Legacy/Cache/Memcache.php | 111 ------ src/Legacy/Cache/Memcached.php | 190 ++++++++++ src/Legacy/Cache/Redis.php | 166 ++++++--- src/Legacy/Cache/Sqlite.php | 176 ++++----- src/Legacy/Cache/SqliteCommon.php | 167 --------- src/Legacy/Caches.php | 19 +- src/Legacy/Datastore/APCu.php | 86 +++-- src/Legacy/Datastore/Common.php | 12 +- src/Legacy/Datastore/File.php | 111 ++++-- src/Legacy/Datastore/Memcache.php | 115 ------ src/Legacy/Datastore/Memcached.php | 184 ++++++++++ src/Legacy/Datastore/Redis.php | 137 +++++-- src/Legacy/Datastore/Sqlite.php | 130 ++++--- src/Legacy/Datastore/SqliteCommon.php | 167 --------- 23 files changed, 1561 insertions(+), 1066 deletions(-) delete mode 100644 library/includes/cron/jobs/cache_gc.php delete mode 100644 src/Legacy/Cache/Memcache.php create mode 100644 src/Legacy/Cache/Memcached.php delete mode 100644 src/Legacy/Cache/SqliteCommon.php delete mode 100644 src/Legacy/Datastore/Memcache.php create mode 100644 src/Legacy/Datastore/Memcached.php delete mode 100644 src/Legacy/Datastore/SqliteCommon.php diff --git a/common.php b/common.php index 5c2c135f2..baa74ce5f 100644 --- a/common.php +++ b/common.php @@ -129,24 +129,15 @@ switch ($bb_cfg['datastore_type']) { case 'apcu': $datastore = new TorrentPier\Legacy\Datastore\APCu($bb_cfg['cache']['prefix']); break; - - case 'memcache': - $datastore = new TorrentPier\Legacy\Datastore\Memcache($bb_cfg['cache']['memcache'], $bb_cfg['cache']['prefix']); + case 'memcached': + $datastore = new TorrentPier\Legacy\Datastore\Memcached($bb_cfg['cache']['memcached'], $bb_cfg['cache']['prefix']); break; - case 'sqlite': - $default_cfg = [ - 'db_file_path' => $bb_cfg['cache']['db_dir'] . 'datastore.sqlite.db', - 'pconnect' => true, - 'con_required' => true, - ]; - $datastore = new TorrentPier\Legacy\Datastore\Sqlite($default_cfg, $bb_cfg['cache']['prefix']); + $datastore = new TorrentPier\Legacy\Datastore\Sqlite($bb_cfg['cache']['db_dir'] . 'datastore', $bb_cfg['cache']['prefix']); break; - case 'redis': $datastore = new TorrentPier\Legacy\Datastore\Redis($bb_cfg['cache']['redis'], $bb_cfg['cache']['prefix']); break; - case 'filecache': default: $datastore = new TorrentPier\Legacy\Datastore\File($bb_cfg['cache']['db_dir'] . 'datastore/', $bb_cfg['cache']['prefix']); diff --git a/composer.json b/composer.json index e375574e0..ffb9a8d76 100644 --- a/composer.json +++ b/composer.json @@ -48,7 +48,9 @@ "google/recaptcha": "^1.3", "jacklul/monolog-telegram": "^3.1", "josantonius/cookie": "^2.0", + "league/flysystem": "^3.28", "longman/ip-tools": "1.2.1", + "matthiasmullie/scrapbook": "^1.5", "monolog/monolog": "^3.4", "samdark/sitemap": "2.4.1", "symfony/mailer": "^6.3", diff --git a/composer.lock b/composer.lock index 7574756b5..27c8e5600 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4978862c1744c10fc0986a0ef31f0e81", + "content-hash": "5bf770ec31048776ac6470189024cb19", "packages": [ { "name": "arokettu/bencode", @@ -516,16 +516,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.5.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "0c5ccfcfea312b5c5a190a21ac5cef93f74baf99" + "reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/0c5ccfcfea312b5c5a190a21ac5cef93f74baf99", - "reference": "0c5ccfcfea312b5c5a190a21ac5cef93f74baf99", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/063d9aa8696582f5a41dffbbaf3c81024f0a604a", + "reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a", "shasum": "" }, "require": { @@ -535,7 +535,7 @@ }, "require-dev": { "phpstan/phpstan": "^1.10", - "psr/log": "^1.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", "symfony/phpunit-bridge": "^4.2 || ^5", "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, @@ -572,7 +572,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.5.0" + "source": "https://github.com/composer/ca-bundle/tree/1.5.1" }, "funding": [ { @@ -588,7 +588,7 @@ "type": "tidelift" } ], - "time": "2024-03-15T14:00:32+00:00" + "time": "2024-07-08T15:28:20+00:00" }, { "name": "doctrine/lexer", @@ -976,22 +976,22 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.8.1", + "version": "7.9.1", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "41042bc7ab002487b876a0683fc8dce04ddce104" + "reference": "a629e5b69db96eb4939c1b34114130077dd4c6fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", - "reference": "41042bc7ab002487b876a0683fc8dce04ddce104", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a629e5b69db96eb4939c1b34114130077dd4c6fc", + "reference": "a629e5b69db96eb4939c1b34114130077dd4c6fc", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0.1", - "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -1002,9 +1002,9 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "ext-curl": "*", - "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "guzzle/client-integration-tests": "3.0.2", "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", "psr/log": "^1.1 || ^2.0 || ^3.0" }, "suggest": { @@ -1082,7 +1082,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.8.1" + "source": "https://github.com/guzzle/guzzle/tree/7.9.1" }, "funding": [ { @@ -1098,20 +1098,20 @@ "type": "tidelift" } ], - "time": "2023-12-03T20:35:24+00:00" + "time": "2024-07-19T16:19:57+00:00" }, { "name": "guzzlehttp/promises", - "version": "2.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" + "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", - "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", + "url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", + "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", "shasum": "" }, "require": { @@ -1119,7 +1119,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.36 || ^9.6.15" + "phpunit/phpunit": "^8.5.39 || ^9.6.20" }, "type": "library", "extra": { @@ -1165,7 +1165,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.2" + "source": "https://github.com/guzzle/promises/tree/2.0.3" }, "funding": [ { @@ -1181,20 +1181,20 @@ "type": "tidelift" } ], - "time": "2023-12-03T20:19:20+00:00" + "time": "2024-07-18T10:29:17+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.6.2", + "version": "2.7.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", - "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", "shasum": "" }, "require": { @@ -1209,8 +1209,8 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "http-interop/http-factory-tests": "^0.9", - "phpunit/phpunit": "^8.5.36 || ^9.6.15" + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -1281,7 +1281,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.6.2" + "source": "https://github.com/guzzle/psr7/tree/2.7.0" }, "funding": [ { @@ -1297,7 +1297,7 @@ "type": "tidelift" } ], - "time": "2023-12-03T20:05:35+00:00" + "time": "2024-07-18T11:15:46+00:00" }, { "name": "jacklul/monolog-telegram", @@ -1485,6 +1485,194 @@ }, "time": "2022-09-24T15:57:16+00:00" }, + { + "name": "league/flysystem", + "version": "3.28.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "e611adab2b1ae2e3072fa72d62c62f52c2bf1f0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/e611adab2b1ae2e3072fa72d62c62f52c2bf1f0c", + "reference": "e611adab2b1ae2e3072fa72d62c62f52c2bf1f0c", + "shasum": "" + }, + "require": { + "league/flysystem-local": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "conflict": { + "async-aws/core": "<1.19.0", + "async-aws/s3": "<1.14.0", + "aws/aws-sdk-php": "3.209.31 || 3.210.0", + "guzzlehttp/guzzle": "<7.0", + "guzzlehttp/ringphp": "<1.1.1", + "phpseclib/phpseclib": "3.0.15", + "symfony/http-client": "<5.2" + }, + "require-dev": { + "async-aws/s3": "^1.5 || ^2.0", + "async-aws/simple-s3": "^1.1 || ^2.0", + "aws/aws-sdk-php": "^3.295.10", + "composer/semver": "^3.0", + "ext-fileinfo": "*", + "ext-ftp": "*", + "ext-mongodb": "^1.3", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.5", + "google/cloud-storage": "^1.23", + "guzzlehttp/psr7": "^2.6", + "microsoft/azure-storage-blob": "^1.1", + "mongodb/mongodb": "^1.2", + "phpseclib/phpseclib": "^3.0.36", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5.11|^10.0", + "sabre/dav": "^4.6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "File storage abstraction for PHP", + "keywords": [ + "WebDAV", + "aws", + "cloud", + "file", + "files", + "filesystem", + "filesystems", + "ftp", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/3.28.0" + }, + "time": "2024-05-22T10:09:12+00:00" + }, + { + "name": "league/flysystem-local", + "version": "3.28.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-local.git", + "reference": "13f22ea8be526ea58c2ddff9e158ef7c296e4f40" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/13f22ea8be526ea58c2ddff9e158ef7c296e4f40", + "reference": "13f22ea8be526ea58c2ddff9e158ef7c296e4f40", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/flysystem": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Local\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Local filesystem adapter for Flysystem.", + "keywords": [ + "Flysystem", + "file", + "files", + "filesystem", + "local" + ], + "support": { + "source": "https://github.com/thephpleague/flysystem-local/tree/3.28.0" + }, + "time": "2024-05-06T20:05:52+00:00" + }, + { + "name": "league/mime-type-detection", + "version": "1.15.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301", + "reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.15.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2024-01-28T23:22:08+00:00" + }, { "name": "longman/ip-tools", "version": "1.2.1", @@ -1545,6 +1733,106 @@ }, "time": "2016-10-23T20:08:46+00:00" }, + { + "name": "matthiasmullie/scrapbook", + "version": "1.5.3", + "source": { + "type": "git", + "url": "https://github.com/matthiasmullie/scrapbook.git", + "reference": "c339d56e136713aab532718eff453663b4b38efe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/matthiasmullie/scrapbook/zipball/c339d56e136713aab532718eff453663b4b38efe", + "reference": "c339d56e136713aab532718eff453663b4b38efe", + "shasum": "" + }, + "require": { + "php": ">=8.0.0", + "psr/cache": "^2.0||^3.0", + "psr/simple-cache": "^2.0||^3.0" + }, + "provide": { + "psr/cache-implementation": "^1.0||^2.0||^3.0", + "psr/simple-cache-implementation": "^1.0||^2.0||^3.0" + }, + "require-dev": { + "ext-pcntl": "*", + "friendsofphp/php-cs-fixer": ">=2.0", + "phpunit/phpunit": ">=10.0", + "squizlabs/php_codesniffer": ">=3.0" + }, + "suggest": { + "couchbase/couchbase": ">=3.0", + "ext-apcu": ">=4.0.0", + "ext-couchbase": ">=3.0.0", + "ext-memcached": ">=2.0.0", + "ext-pdo": ">=0.1.0", + "ext-redis": ">=2.2.0||0.0.0.0", + "league/flysystem": ">=1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "MatthiasMullie\\Scrapbook\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthias Mullie", + "email": "scrapbook@mullie.eu", + "homepage": "https://www.mullie.eu", + "role": "Developer" + } + ], + "description": "Scrapbook is a PHP cache library, with adapters for e.g. Memcached, Redis, Couchbase, APCu, SQL and additional capabilities (e.g. transactions, stampede protection) built on top.", + "homepage": "https://scrapbook.cash", + "keywords": [ + "Buffer", + "Flysystem", + "apc", + "buffered", + "cache", + "caching", + "commit", + "couchbase", + "filesystem", + "key", + "memcached", + "mitigation", + "mysql", + "postgresql", + "protection", + "psr-16", + "psr-6", + "psr-cache", + "psr-simple-cache", + "redis", + "rollback", + "sql", + "sqlite", + "stampede", + "store", + "transaction", + "transactional", + "value" + ], + "support": { + "issues": "https://github.com/matthiasmullie/scrapbook/issues", + "source": "https://github.com/matthiasmullie/scrapbook/tree/1.5.3" + }, + "funding": [ + { + "url": "https://github.com/matthiasmullie", + "type": "github" + } + ], + "time": "2024-04-02T13:33:01+00:00" + }, { "name": "monolog/monolog", "version": "3.7.0", @@ -1852,6 +2140,55 @@ ], "time": "2024-07-20T21:41:07+00:00" }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, { "name": "psr/container", "version": "2.0.2", @@ -2165,6 +2502,57 @@ }, "time": "2021-07-14T16:46:02+00:00" }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, { "name": "ralouphie/getallheaders", "version": "3.0.3", @@ -3679,5 +4067,5 @@ "php": "^8.1" }, "platform-dev": [], - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/install/sql/mysql.sql b/install/sql/mysql.sql index a618920d7..1ddd0bb1b 100644 --- a/install/sql/mysql.sql +++ b/install/sql/mysql.sql @@ -647,9 +647,6 @@ VALUES ('1', 'Attach maintenance', 'attach_maintenance.php', 'daily', '', '05:00 '', '0', '0', '0'), ('1', 'Tracker dl-complete count', 'tr_complete_count.php', 'interval', '', '', '255', '', '', '06:00:00', '0', '', '0', '0', '0'), - ('1', 'Cache garbage collector', 'cache_gc.php', 'interval', '', '', '255', '', '', '00:05:00', '0', '', '0', - '0', - '0'), ('1', 'Sitemap update', 'sitemap.php', 'daily', '', '06:00:00', '30', '', '', '', '0', '', '0', '0', '0'), ('1', 'Update forums atom', 'update_forums_atom.php', 'interval', '', '', '255', '', '', '00:15:00', '0', '', '0', diff --git a/library/config.php b/library/config.php index f1af7cae7..a20da000f 100644 --- a/library/config.php +++ b/library/config.php @@ -54,36 +54,32 @@ $bb_cfg['db_alias'] = [ // Cache $bb_cfg['cache'] = [ - 'pconnect' => true, 'db_dir' => realpath(BB_ROOT) . '/internal_data/cache/filecache/', 'prefix' => 'tp_', - 'memcache' => [ + 'memcached' => [ 'host' => '127.0.0.1', 'port' => 11211, - 'pconnect' => true, - 'con_required' => true, ], 'redis' => [ 'host' => '127.0.0.1', 'port' => 6379, 'pconnect' => !PHP_ZTS, // Redis pconnect supported only for non-thread safe compilations of PHP - 'con_required' => true, ], - // Available cache types: filecache, memcache, sqlite, redis, apcu (filecache by default) + // Available cache types: filecache, memcached, sqlite, redis, apcu (filecache by default) 'engines' => [ - 'bb_cache' => ['filecache', []], - 'bb_config' => ['filecache', []], - 'tr_cache' => ['filecache', []], - 'session_cache' => ['filecache', []], - 'bb_cap_sid' => ['filecache', []], - 'bb_login_err' => ['filecache', []], - 'bb_poll_data' => ['filecache', []], - 'bb_ip2countries' => ['filecache', []], + 'bb_cache' => ['filecache'], + 'bb_config' => ['filecache'], + 'tr_cache' => ['filecache'], + 'session_cache' => ['filecache'], + 'bb_cap_sid' => ['filecache'], + 'bb_login_err' => ['filecache'], + 'bb_poll_data' => ['filecache'], + 'bb_ip2countries' => ['filecache'], ], ]; // Datastore -// Available datastore types: filecache, memcache, sqlite, redis, apcu (filecache by default) +// Available datastore types: filecache, memcached, sqlite, redis, apcu (filecache by default) $bb_cfg['datastore_type'] = 'filecache'; // Server diff --git a/library/includes/cron/jobs/cache_gc.php b/library/includes/cron/jobs/cache_gc.php deleted file mode 100644 index a39a9ce0d..000000000 --- a/library/includes/cron/jobs/cache_gc.php +++ /dev/null @@ -1,21 +0,0 @@ - $cache_val) { - if (method_exists(CACHE($cache_name), 'gc')) { - $changes = CACHE($cache_name)->gc(); - $cron_runtime_log[] = date('Y-m-d H:i:s') . " -- " . str_pad("$cache_name ", 25, '-', STR_PAD_RIGHT) . " del: $changes"; - } -} diff --git a/src/Legacy/Cache/APCu.php b/src/Legacy/Cache/APCu.php index 1b3e6cab1..d7f73d0da 100644 --- a/src/Legacy/Cache/APCu.php +++ b/src/Legacy/Cache/APCu.php @@ -9,72 +9,122 @@ namespace TorrentPier\Legacy\Cache; +use MatthiasMullie\Scrapbook\Adapters\Apc; + /** * Class APCu * @package TorrentPier\Legacy\Cache */ class APCu extends Common { - public $used = true; - public $engine = 'APCu'; - public $prefix; + /** + * Currently in usage + * + * @var bool + */ + public bool $used = true; - public function __construct($prefix = null) + /** + * Cache driver name + * + * @var string + */ + public string $engine = 'APCu'; + + /** + * Cache prefix + * + * @var string + */ + private string $prefix; + + /** + * Adapters\Apc class + * + * @var Apc + */ + private Apc $apcu; + + /** + * APCu constructor + * + * @param string $prefix + */ + public function __construct(string $prefix) { global $debug; - if (!$this->is_installed()) { - die("Error: $this->engine extension not installed"); - } - + $this->apcu = new Apc(); $this->prefix = $prefix; $this->dbg_enabled = $debug->sqlDebugAllowed(); } - public function get($name, $get_miss_key_callback = '', $ttl = 0) + /** + * Fetch data from cache + * + * @param string $name + * @return mixed + */ + public function get(string $name): mixed { - $this->cur_query = "cache->get('$name')"; + $name = $this->prefix . $name; + + $this->cur_query = "cache->" . __FUNCTION__ . "('$name')"; $this->debug('start'); + + $result = $this->apcu->get($name); + $this->debug('stop'); $this->cur_query = null; $this->num_queries++; - return apcu_fetch($this->prefix . $name); + return $result; } - public function set($name, $value, $ttl = 0) + /** + * Store data into cache + * + * @param string $name + * @param mixed $value + * @param int $ttl + * @return bool + */ + public function set(string $name, mixed $value, int $ttl = 0): bool { - $this->cur_query = "cache->set('$name')"; + $name = $this->prefix . $name; + + $this->cur_query = "cache->" . __FUNCTION__ . "('$name')"; $this->debug('start'); - if (apcu_store($this->prefix . $name, $value, $ttl)) { - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; + $result = $this->apcu->set($name, $value, $ttl); - return true; - } + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; - return false; + return $result; } - public function rm($name = '') + /** + * Removes data from cache + * + * @param string|null $name + * @return bool + */ + public function rm(string $name = null): bool { - if ($name) { - $this->cur_query = "cache->rm('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; + $targetMethod = is_string($name) ? 'delete' : 'flush'; + $name = is_string($name) ? ("'" . $this->prefix . $name . "'") : null; - return apcu_delete($this->prefix . $name); - } + $this->cur_query = "cache->$targetMethod($name)"; + $this->debug('start'); - return apcu_clear_cache(); - } + $result = $this->apcu->$targetMethod($name); - public function is_installed(): bool - { - return extension_loaded('apcu') && apcu_enabled(); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return $result; } } diff --git a/src/Legacy/Cache/Common.php b/src/Legacy/Cache/Common.php index 03029b512..bf33b8f3f 100644 --- a/src/Legacy/Cache/Common.php +++ b/src/Legacy/Cache/Common.php @@ -15,31 +15,44 @@ namespace TorrentPier\Legacy\Cache; */ class Common { - public $used = false; + /** + * Currently in usage + * + * @var bool + */ + public bool $used = true; /** - * Returns value of variable + * Fetch data from cache + * + * @param string $name + * @return mixed */ - public function get($name, $get_miss_key_callback = '', $ttl = 604800) - { - if ($get_miss_key_callback) { - return $get_miss_key_callback($name); - } - return \is_array($name) ? [] : false; - } - - /** - * Store value of variable - */ - public function set($name, $value, $ttl = 604800) + public function get(string $name): mixed { return false; } /** - * Remove variable + * Store data into cache + * + * @param string $name + * @param mixed $value + * @param int $ttl + * @return bool */ - public function rm($name = '') + public function set(string $name, mixed $value, int $ttl = 604800): bool + { + return false; + } + + /** + * Removes data from cache + * + * @param string|null $name + * @return bool + */ + public function rm(string $name = null): bool { return false; } diff --git a/src/Legacy/Cache/File.php b/src/Legacy/Cache/File.php index 18a913937..b370e2748 100644 --- a/src/Legacy/Cache/File.php +++ b/src/Legacy/Cache/File.php @@ -9,125 +9,127 @@ namespace TorrentPier\Legacy\Cache; +use League\Flysystem\Filesystem; +use League\Flysystem\Local\LocalFilesystemAdapter; +use MatthiasMullie\Scrapbook\Adapters\Flysystem; + /** * Class File * @package TorrentPier\Legacy\Cache */ class File extends Common { - public $used = true; - public $engine = 'Filecache'; - public $dir; - public $prefix; + /** + * Currently in usage + * + * @var bool + */ + public bool $used = true; - public function __construct($dir, $prefix = null) + /** + * Cache driver name + * + * @var string + */ + public string $engine = 'File'; + + /** + * Cache prefix + * + * @var string + */ + private string $prefix; + + /** + * Adapters\File class + * + * @var Flysystem + */ + private Flysystem $file; + + /** + * File constructor + * + * @param string $dir + * @param string $prefix + */ + public function __construct(string $dir, string $prefix) { global $debug; - $this->dir = $dir; + $adapter = new LocalFilesystemAdapter($dir, null, LOCK_EX); + $filesystem = new Filesystem($adapter); + $this->file = new Flysystem($filesystem); $this->prefix = $prefix; $this->dbg_enabled = $debug->sqlDebugAllowed(); } - public function get($name, $get_miss_key_callback = '', $ttl = 0) + /** + * Fetch data from cache + * + * @param string $name + * @return mixed + */ + public function get(string $name): mixed { - $filecache = []; - $filename = $this->dir . clean_filename($this->prefix . $name) . '.php'; + $name = $this->prefix . $name; - $this->cur_query = "cache->get('$name')"; + $this->cur_query = "cache->" . __FUNCTION__ . "('$name')"; $this->debug('start'); - if (is_file($filename) && is_readable($filename)) { - require($filename); - } - - $this->debug('stop'); - $this->cur_query = null; - - return (!empty($filecache['value'])) ? $filecache['value'] : false; - } - - public function set($name, $value, $ttl = 86400) - { - if (!\function_exists('var_export')) { - return false; - } - - $this->cur_query = "cache->set('$name')"; - $this->debug('start'); - - $filename = $this->dir . clean_filename($this->prefix . $name) . '.php'; - $expire = TIMENOW + $ttl; - $cache_data = ['expire' => $expire, 'value' => $value]; - - $filecache = "'; + $result = $this->file->get($name); $this->debug('stop'); $this->cur_query = null; $this->num_queries++; - return (bool)file_write($filecache, $filename, max_size: false, replace_content: true); + return $result; } - public function rm($name = '') + /** + * Store data into cache + * + * @param string $name + * @param mixed $value + * @param int $ttl + * @return bool + */ + public function set(string $name, mixed $value, int $ttl = 0): bool { - $clear = false; - if ($name) { - $this->cur_query = "cache->rm('$name')"; - $this->debug('start'); + $name = $this->prefix . $name; - $filename = $this->dir . clean_filename($this->prefix . $name) . '.php'; - if (is_file($filename)) { - $clear = (bool)unlink($filename); - } + $this->cur_query = "cache->" . __FUNCTION__ . "('$name')"; + $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - } else { - if (is_dir($this->dir)) { - if ($dh = opendir($this->dir)) { - while (($file = readdir($dh)) !== false) { - if ($file != "." && $file != "..") { - $filename = $this->dir . $file; + $result = $this->file->set($name, $value, $ttl); - unlink($filename); - $clear = true; - } - } - closedir($dh); - } - } - } - return $clear; + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return $result; } - public function gc($expire_time = TIMENOW) + /** + * Removes data from cache + * + * @param string|null $name + * @return bool + */ + public function rm(string $name = null): bool { - $filecache = []; - $clear = false; + $targetMethod = is_string($name) ? 'delete' : 'flush'; + $name = is_string($name) ? ("'" . $this->prefix . $name . "'") : null; - if (is_dir($this->dir)) { - if ($dh = opendir($this->dir)) { - while (($file = readdir($dh)) !== false) { - if ($file != "." && $file != "..") { - $filename = $this->dir . $file; + $this->cur_query = "cache->$targetMethod($name)"; + $this->debug('start'); - require($filename); + $result = $this->file->$targetMethod($name); - if (!empty($filecache['expire']) && ($filecache['expire'] < $expire_time)) { - unlink($filename); - $clear = true; - } - } - } - closedir($dh); - } - } + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; - return $clear; + return $result; } } diff --git a/src/Legacy/Cache/Memcache.php b/src/Legacy/Cache/Memcache.php deleted file mode 100644 index cada1f7d7..000000000 --- a/src/Legacy/Cache/Memcache.php +++ /dev/null @@ -1,111 +0,0 @@ -is_installed()) { - die("Error: $this->engine extension not installed"); - } - - $this->cfg = $cfg; - $this->prefix = $prefix; - $this->memcache = new \Memcache(); - $this->dbg_enabled = $debug->sqlDebugAllowed(); - } - - public function connect() - { - $connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect'; - - $this->cur_query = $connect_type . ' ' . $this->cfg['host'] . ':' . $this->cfg['port']; - $this->debug('start'); - - if (@$this->memcache->$connect_type($this->cfg['host'], $this->cfg['port'])) { - $this->connected = true; - } - - if (!$this->connected && $this->cfg['con_required']) { - die("Could not connect to $this->engine server"); - } - - $this->debug('stop'); - $this->cur_query = null; - } - - public function get($name, $get_miss_key_callback = '', $ttl = 0) - { - if (!$this->connected) { - $this->connect(); - } - - $this->cur_query = "cache->get('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return ($this->connected) ? $this->memcache->get($this->prefix . $name) : false; - } - - public function set($name, $value, $ttl = 0) - { - if (!$this->connected) { - $this->connect(); - } - - $this->cur_query = "cache->set('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return ($this->connected) ? $this->memcache->set($this->prefix . $name, $value, false, $ttl) : false; - } - - public function rm($name = '') - { - if (!$this->connected) { - $this->connect(); - } - - if ($name) { - $this->cur_query = "cache->rm('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return ($this->connected) ? $this->memcache->delete($this->prefix . $name, 0) : false; - } - - return ($this->connected) ? $this->memcache->flush() : false; - } - - public function is_installed() - { - return class_exists('Memcache'); - } -} diff --git a/src/Legacy/Cache/Memcached.php b/src/Legacy/Cache/Memcached.php new file mode 100644 index 000000000..bb1ee267e --- /dev/null +++ b/src/Legacy/Cache/Memcached.php @@ -0,0 +1,190 @@ +client = new MemcachedClient(); + $this->cfg = $cfg; + $this->prefix = $prefix; + $this->dbg_enabled = $debug->sqlDebugAllowed(); + } + + /** + * Connect to cache + * + * @return void + */ + private function connect(): void + { + $this->cur_query = 'connect ' . $this->cfg['host'] . ':' . $this->cfg['port']; + $this->debug('start'); + + if ($this->client->addServer($this->cfg['host'], $this->cfg['port'])) { + $this->connected = true; + } + + if (!$this->connected) { + die("Could not connect to $this->engine server"); + } + + $this->memcached = new MemcachedCache($this->client); + + $this->debug('stop'); + $this->cur_query = null; + } + + /** + * Fetch data from cache + * + * @param string $name + * @return mixed + */ + public function get(string $name): mixed + { + if (!$this->connected) { + $this->connect(); + } + + $name = $this->prefix . $name; + + $this->cur_query = "cache->" . __FUNCTION__ . "('$name')"; + $this->debug('start'); + + $result = $this->memcached->get($name); + + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return $result; + } + + /** + * Store data into cache + * + * @param string $name + * @param mixed $value + * @param int $ttl + * @return bool + */ + public function set(string $name, mixed $value, int $ttl = 0): bool + { + if (!$this->connected) { + $this->connect(); + } + + $name = $this->prefix . $name; + + $this->cur_query = "cache->" . __FUNCTION__ . "('$name')"; + $this->debug('start'); + + $result = $this->memcached->set($name, $value, $ttl); + + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return $result; + } + + /** + * Removes data from cache + * + * @param string|null $name + * @return bool + */ + public function rm(string $name = null): bool + { + if (!$this->connected) { + $this->connect(); + } + + $targetMethod = is_string($name) ? 'delete' : 'flush'; + $name = is_string($name) ? ("'" . $this->prefix . $name . "'") : null; + + $this->cur_query = "cache->$targetMethod($name)"; + $this->debug('start'); + + $result = $this->memcached->$targetMethod($name); + + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return $result; + } +} diff --git a/src/Legacy/Cache/Redis.php b/src/Legacy/Cache/Redis.php index 3b45e06e5..2b5b6f45a 100644 --- a/src/Legacy/Cache/Redis.php +++ b/src/Legacy/Cache/Redis.php @@ -9,112 +9,184 @@ namespace TorrentPier\Legacy\Cache; +use Redis as RedisClient; +use MatthiasMullie\Scrapbook\Adapters\Redis as RedisCache; + /** * Class Redis * @package TorrentPier\Legacy\Cache */ class Redis extends Common { - public $used = true; - public $engine = 'Redis'; - public $cfg; - public $redis; - public $prefix; - public $connected = false; + /** + * Currently in usage + * + * @var bool + */ + public bool $used = true; - public function __construct($cfg, $prefix = null) + /** + * Connection status + * + * @var bool + */ + public bool $connected = false; + + /** + * Cache driver name + * + * @var string + */ + public string $engine = 'Redis'; + + /** + * Cache config + * + * @var array + */ + private array $cfg; + + /** + * Cache prefix + * + * @var string + */ + private string $prefix; + + /** + * Redis class + * + * @var RedisClient + */ + private RedisClient $client; + + /** + * Adapters\Redis class + * + * @var RedisCache + */ + private RedisCache $redis; + + /** + * Redis constructor + * + * @param array $cfg + * @param string $prefix + */ + public function __construct(array $cfg, string $prefix) { global $debug; - if (!$this->is_installed()) { - die("Error: $this->engine extension not installed"); - } - + $this->client = new RedisClient(); $this->cfg = $cfg; $this->prefix = $prefix; - $this->redis = new \Redis(); $this->dbg_enabled = $debug->sqlDebugAllowed(); } - public function connect() + /** + * Connect to cache + * + * @return void + */ + private function connect(): void { - $connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect'; + $connectType = $this->cfg['pconnect'] ? 'pconnect' : 'connect'; - $this->cur_query = $connect_type . ' ' . $this->cfg['host'] . ':' . $this->cfg['port']; + $this->cur_query = $connectType . ' ' . $this->cfg['host'] . ':' . $this->cfg['port']; $this->debug('start'); - if (@$this->redis->$connect_type($this->cfg['host'], $this->cfg['port'])) { + if ($this->client->$connectType($this->cfg['host'], $this->cfg['port'])) { $this->connected = true; } - if (!$this->connected && $this->cfg['con_required']) { + if (!$this->connected) { die("Could not connect to $this->engine server"); } + $this->redis = new RedisCache($this->client); + $this->debug('stop'); $this->cur_query = null; } - public function get($name, $get_miss_key_callback = '', $ttl = 0) + /** + * Fetch data from cache + * + * @param string $name + * @return mixed + */ + public function get(string $name): mixed { if (!$this->connected) { $this->connect(); } - $this->cur_query = "cache->get('$name')"; + $name = $this->prefix . $name; + + $this->cur_query = "cache->" . __FUNCTION__ . "('$name')"; $this->debug('start'); + + $result = $this->redis->get($name); + $this->debug('stop'); $this->cur_query = null; $this->num_queries++; - return ($this->connected) ? unserialize($this->redis->get($this->prefix . $name)) : false; + return $result; } - public function set($name, $value, $ttl = 0) + /** + * Store data into cache + * + * @param string $name + * @param mixed $value + * @param int $ttl + * @return bool + */ + public function set(string $name, mixed $value, int $ttl = 0): bool { if (!$this->connected) { $this->connect(); } - $this->cur_query = "cache->set('$name')"; + $name = $this->prefix . $name; + + $this->cur_query = "cache->" . __FUNCTION__ . "('$name')"; $this->debug('start'); - if ($this->redis->set($this->prefix . $name, serialize($value))) { - if ($ttl > 0) { - $this->redis->expire($this->prefix . $name, $ttl); - } + $result = $this->redis->set($name, $value, $ttl); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; - return true; - } - - return false; + return $result; } - public function rm($name = '') + /** + * Removes data from cache + * + * @param string|null $name + * @return bool + */ + public function rm(string $name = null): bool { if (!$this->connected) { $this->connect(); } - if ($name) { - $this->cur_query = "cache->rm('$name')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; + $targetMethod = is_string($name) ? 'delete' : 'flush'; + $name = is_string($name) ? ("'" . $this->prefix . $name . "'") : null; - return ($this->connected) ? $this->redis->del($this->prefix . $name) : false; - } + $this->cur_query = "cache->$targetMethod($name)"; + $this->debug('start'); - return ($this->connected) ? $this->redis->flushDB() : false; - } + $result = $this->redis->$targetMethod($name); - public function is_installed() - { - return class_exists('Redis'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return $result; } } diff --git a/src/Legacy/Cache/Sqlite.php b/src/Legacy/Cache/Sqlite.php index 8be1d1ede..0200c22eb 100644 --- a/src/Legacy/Cache/Sqlite.php +++ b/src/Legacy/Cache/Sqlite.php @@ -9,7 +9,8 @@ namespace TorrentPier\Legacy\Cache; -use SQLite3; +use MatthiasMullie\Scrapbook\Adapters\SQLite as SQLiteCache; +use PDO; /** * Class Sqlite @@ -17,107 +18,116 @@ use SQLite3; */ class Sqlite extends Common { - public $used = true; - public $db; - public $prefix; - public $engine = 'SQLite'; - public $cfg = [ - 'db_file_path' => '/path/to/cache.db.sqlite', - 'table_name' => 'cache', - 'table_schema' => 'CREATE TABLE cache ( - cache_name VARCHAR(255), - cache_expire_time INT, - cache_value TEXT, - PRIMARY KEY (cache_name) - )', - 'pconnect' => true, - 'con_required' => true, - 'log_name' => 'CACHE', - ]; + /** + * Currently in usage + * + * @var bool + */ + public bool $used = true; - public function __construct($cfg, $prefix = null) + /** + * Cache driver name + * + * @var string + */ + public string $engine = 'SQLite'; + + /** + * Cache prefix + * + * @var string + */ + private string $prefix; + + /** + * Adapters\SQLite class + * + * @var SQLiteCache + */ + private SQLiteCache $sqlite; + + /** + * Sqlite constructor + * + * @param string $dir + * @param string $prefix + */ + public function __construct(string $dir, string $prefix) { - if (!$this->is_installed()) { - die('Error: SQLite3 extension not installed'); - } + global $debug; - $this->cfg = array_merge($this->cfg, $cfg); - $this->db = new SqliteCommon($this->cfg); + $client = new PDO("sqlite:$dir.db"); + $this->sqlite = new SQLiteCache($client); $this->prefix = $prefix; + $this->dbg_enabled = $debug->sqlDebugAllowed(); } - public function get($name, $get_miss_key_callback = '', $ttl = 604800) + /** + * Fetch data from cache + * + * @param string $name + * @return mixed + */ + public function get(string $name): mixed { - if (empty($name)) { - return \is_array($name) ? [] : false; - } - $this->db->shard($name); - $cached_items = []; - $prefix_len = \strlen($this->prefix); - $prefix_sql = SQLite3::escapeString($this->prefix); + $name = $this->prefix . $name; - $name_ary = $name_sql = (array)$name; - array_deep($name_sql, 'SQLite3::escapeString'); + $this->cur_query = "cache->" . __FUNCTION__ . "('$name')"; + $this->debug('start'); - // get available items - $rowset = $this->db->fetch_rowset(" - SELECT cache_name, cache_value - FROM " . $this->cfg['table_name'] . " - WHERE cache_name IN('$prefix_sql" . implode("','$prefix_sql", $name_sql) . "') AND cache_expire_time > " . TIMENOW . " - LIMIT " . \count($name_sql) . " - "); + $result = $this->sqlite->get($name); - $this->db->debug('start', 'unserialize()'); - foreach ($rowset as $row) { - $cached_items[substr($row['cache_name'], $prefix_len)] = unserialize($row['cache_value']); - } - $this->db->debug('stop'); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; - // get miss items - if ($get_miss_key_callback and $miss_key = array_diff($name_ary, array_keys($cached_items))) { - foreach ($get_miss_key_callback($miss_key) as $k => $v) { - $this->set($this->prefix . $k, $v, $ttl); - $cached_items[$k] = $v; - } - } - // return - if (\is_array($this->prefix . $name)) { - return $cached_items; - } - - return $cached_items[$name] ?? false; + return $result; } - public function set($name, $value, $ttl = 604800) + /** + * Store data into cache + * + * @param string $name + * @param mixed $value + * @param int $ttl + * @return bool + */ + public function set(string $name, mixed $value, int $ttl = 0): bool { - $this->db->shard($this->prefix . $name); - $name_sql = SQLite3::escapeString($this->prefix . $name); - $expire = TIMENOW + $ttl; - $value_sql = SQLite3::escapeString(serialize($value)); + $name = $this->prefix . $name; - $result = $this->db->query("REPLACE INTO " . $this->cfg['table_name'] . " (cache_name, cache_expire_time, cache_value) VALUES ('$name_sql', $expire, '$value_sql')"); - return (bool)$result; + $this->cur_query = "cache->" . __FUNCTION__ . "('$name')"; + $this->debug('start'); + + $result = $this->sqlite->set($name, $value, $ttl); + + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return $result; } - public function rm($name = '') + /** + * Removes data from cache + * + * @param string|null $name + * @return bool + */ + public function rm(string $name = null): bool { - if ($name) { - $this->db->shard($this->prefix . $name); - $result = $this->db->query("DELETE FROM " . $this->cfg['table_name'] . " WHERE cache_name = '" . SQLite3::escapeString($this->prefix . $name) . "'"); - } else { - $result = $this->db->query("DELETE FROM " . $this->cfg['table_name']); - } - return (bool)$result; - } + $targetMethod = is_string($name) ? 'delete' : 'flush'; + $name = is_string($name) ? ("'" . $this->prefix . $name . "'") : null; - public function gc($expire_time = TIMENOW) - { - $result = $this->db->query("DELETE FROM " . $this->cfg['table_name'] . " WHERE cache_expire_time < $expire_time"); - return $result ? $this->db->changes() : 0; - } + $this->cur_query = "cache->$targetMethod($name)"; + $this->debug('start'); - public function is_installed() - { - return class_exists('SQLite3'); + $result = $this->sqlite->$targetMethod($name); + + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return $result; } } diff --git a/src/Legacy/Cache/SqliteCommon.php b/src/Legacy/Cache/SqliteCommon.php deleted file mode 100644 index fa8033474..000000000 --- a/src/Legacy/Cache/SqliteCommon.php +++ /dev/null @@ -1,167 +0,0 @@ - 'sqlite.db', - 'table_name' => 'table_name', - 'table_schema' => 'CREATE TABLE table_name (...)', - 'pconnect' => true, - 'con_required' => true, - 'log_name' => 'SQLite', - 'shard_type' => 'none', # none, string, int (тип перевичного ключа для шардинга) - 'shard_val' => 0, # для string - кол. начальных символов, для int - делитель (будет использован остаток от деления) - ]; - public $engine = 'SQLite'; - public $dbh; - public $connected = false; - public $shard_val = false; - - public $table_create_attempts = 0; - - public function __construct($cfg) - { - global $debug; - - $this->cfg = array_merge($this->cfg, $cfg); - $this->dbg_enabled = $debug->sqlDebugAllowed(); - } - - public function connect() - { - $this->cur_query = $this->dbg_enabled ? 'connect to: ' . $this->cfg['db_file_path'] : 'connect'; - $this->debug('start'); - - if (@$this->dbh = new SQLite3($this->cfg['db_file_path'])) { - $this->connected = true; - } - - if (!$this->connected && $this->cfg['con_required']) { - trigger_error('SQLite not connected', E_USER_ERROR); - } - - $this->debug('stop'); - $this->cur_query = null; - } - - public function create_table() - { - $this->table_create_attempts++; - return $this->dbh->query($this->cfg['table_schema']); - } - - public function shard($name) - { - $type = $this->cfg['shard_type']; - - if ($type == 'none') { - return; - } - if (\is_array($name)) { - trigger_error('cannot shard: $name is array', E_USER_ERROR); - } - - // define shard_val - if ($type == 'string') { - $shard_val = substr($name, 0, $this->cfg['shard_val']); - } else { - $shard_val = $name % $this->cfg['shard_val']; - } - // все запросы должны быть к одному и тому же шарду - if ($this->shard_val !== false) { - if ($shard_val != $this->shard_val) { - trigger_error("shard cannot be reassigned. [{$this->shard_val}, $shard_val, $name]", E_USER_ERROR); - } else { - return; - } - } - $this->shard_val = $shard_val; - $this->cfg['db_file_path'] = str_replace('*', $shard_val, $this->cfg['db_file_path']); - } - - public function query($query) - { - if (!$this->connected) { - $this->connect(); - } - - $this->cur_query = $query; - $this->debug('start'); - - if (!$result = @$this->dbh->query($query)) { - $rowsresult = $this->dbh->query("PRAGMA table_info({$this->cfg['table_name']})"); - $rowscount = 0; - while ($row = $rowsresult->fetchArray(SQLITE3_ASSOC)) { - $rowscount++; - } - if (!$this->table_create_attempts && !$rowscount) { - if ($this->create_table()) { - $result = $this->dbh->query($query); - } - } - if (!$result) { - $this->trigger_error($this->get_error_msg()); - } - } - - $this->debug('stop'); - $this->cur_query = null; - - $this->num_queries++; - - return $result; - } - - public function fetch_row($query) - { - $result = $this->query($query); - return \is_resource($result) ? $result->fetchArray(SQLITE3_ASSOC) : false; - } - - public function fetch_rowset($query) - { - $result = $this->query($query); - $rowset = []; - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - $rowset[] = $row; - } - return $rowset; - } - - public function changes() - { - return \is_resource($this->dbh) ? $this->dbh->changes() : 0; - } - - public function escape($str) - { - return SQLite3::escapeString($str); - } - - public function get_error_msg() - { - return 'SQLite error #' . $this->dbh->lastErrorCode() . ': ' . $this->dbh->lastErrorMsg(); - } - - public function trigger_error($msg = 'DB Error') - { - if (error_reporting()) { - trigger_error($msg, E_USER_ERROR); - } - } -} diff --git a/src/Legacy/Caches.php b/src/Legacy/Caches.php index 4d60f9b64..b7a09d520 100644 --- a/src/Legacy/Caches.php +++ b/src/Legacy/Caches.php @@ -32,7 +32,6 @@ class Caches $this->ref[$cache_name] =& $this->obj['__stub']; } else { $cache_type =& $engine_cfg[0]; - $cache_cfg =& $engine_cfg[1]; switch ($cache_type) { case 'apcu': @@ -41,18 +40,15 @@ class Caches } $this->ref[$cache_name] =& $this->obj[$cache_name]; break; - case 'memcache': + case 'memcached': if (!isset($this->obj[$cache_name])) { - $this->obj[$cache_name] = new Cache\Memcache($this->cfg['memcache'], $this->cfg['prefix']); + $this->obj[$cache_name] = new Cache\Memcached($this->cfg['memcached'], $this->cfg['prefix']); } $this->ref[$cache_name] =& $this->obj[$cache_name]; break; case 'sqlite': if (!isset($this->obj[$cache_name])) { - $cache_cfg['pconnect'] = $this->cfg['pconnect']; - $cache_cfg['db_file_path'] = $this->get_db_path($cache_name, $cache_cfg, '.sqlite.db'); - - $this->obj[$cache_name] = new Cache\Sqlite($cache_cfg, $this->cfg['prefix']); + $this->obj[$cache_name] = new Cache\Sqlite($this->cfg['db_dir'] . $cache_name, $this->cfg['prefix']); } $this->ref[$cache_name] =& $this->obj[$cache_name]; break; @@ -75,13 +71,4 @@ class Caches return $this->ref[$cache_name]; } - - public function get_db_path($name, $cfg, $ext) - { - if (!empty($cfg['shard_type']) && $cfg['shard_type'] != 'none') { - return $this->cfg['db_dir'] . $name . '_*' . $ext; - } - - return $this->cfg['db_dir'] . $name . $ext; - } } diff --git a/src/Legacy/Datastore/APCu.php b/src/Legacy/Datastore/APCu.php index 08ec2c00e..cd25fa64f 100644 --- a/src/Legacy/Datastore/APCu.php +++ b/src/Legacy/Datastore/APCu.php @@ -9,54 +9,99 @@ namespace TorrentPier\Legacy\Datastore; +use MatthiasMullie\Scrapbook\Adapters\Apc; + /** * Class APCu * @package TorrentPier\Legacy\Datastore */ class APCu extends Common { - public string $prefix; + /** + * Cache driver name + * + * @var string + */ public string $engine = 'APCu'; - public function __construct($prefix = null) + /** + * Cache prefix + * + * @var string + */ + private string $prefix; + + /** + * Adapters\Apc class + * + * @var Apc + */ + private Apc $apcu; + + /** + * APCu constructor + * + * @param string $prefix + */ + public function __construct(string $prefix) { global $debug; - if (!$this->is_installed()) { - die("Error: $this->engine extension not installed"); - } - + $this->apcu = new Apc(); $this->prefix = $prefix; $this->dbg_enabled = $debug->sqlDebugAllowed(); } - public function store($title, $var) + /** + * Store data into cache + * + * @param string $item_name + * @param mixed $item_data + * @return bool + */ + public function store(string $item_name, mixed $item_data): bool { - $this->data[$title] = $var; + $this->data[$item_name] = $item_data; + $item_name = $this->prefix . $item_name; - $this->cur_query = "cache->set('$title')"; + $this->cur_query = "cache->" . __FUNCTION__ . "('$item_name')"; $this->debug('start'); + + $result = $this->apcu->set($item_name, $item_data); + $this->debug('stop'); $this->cur_query = null; $this->num_queries++; - return (bool)apcu_store($this->prefix . $title, $var); + return $result; } - public function clean() + /** + * Removes data from cache + * + * @return void + */ + public function clean(): void { foreach ($this->known_items as $title => $script_name) { + $title = $this->prefix . $title; $this->cur_query = "cache->rm('$title')"; $this->debug('start'); + + $this->apcu->delete($title); + $this->debug('stop'); $this->cur_query = null; $this->num_queries++; - - apcu_delete($this->prefix . $title); } } - public function _fetch_from_store() + /** + * Fetch cache from store + * + * @return void + */ + public function _fetch_from_store(): void { $item = null; if (!$items = $this->queued_items) { @@ -65,18 +110,15 @@ class APCu extends Common } foreach ($items as $item) { - $this->cur_query = "cache->get('$item')"; + $item_title = $this->prefix . $item; + $this->cur_query = "cache->get('$item_title')"; $this->debug('start'); + + $this->data[$item] = $this->apcu->get($item_title); + $this->debug('stop'); $this->cur_query = null; $this->num_queries++; - - $this->data[$item] = apcu_fetch($this->prefix . $item); } } - - public function is_installed(): bool - { - return extension_loaded('apcu') && apcu_enabled(); - } } diff --git a/src/Legacy/Datastore/Common.php b/src/Legacy/Datastore/Common.php index 139ee15d7..58bd69653 100644 --- a/src/Legacy/Datastore/Common.php +++ b/src/Legacy/Datastore/Common.php @@ -18,7 +18,7 @@ class Common /** * Директория с builder-скриптами (внутри INC_DIR) */ - public $ds_dir = 'datastore'; + public string $ds_dir = 'datastore'; /** * Готовая к употреблению data @@ -86,8 +86,16 @@ class Common return isset($this->data[$title]); } - public function store($item_name, $item_data) + /** + * Store data into cache + * + * @param string $item_name + * @param mixed $item_data + * @return bool + */ + public function store(string $item_name, mixed $item_data): bool { + return false; } public function rm($items) diff --git a/src/Legacy/Datastore/File.php b/src/Legacy/Datastore/File.php index 27f2ffea2..86dab53e7 100644 --- a/src/Legacy/Datastore/File.php +++ b/src/Legacy/Datastore/File.php @@ -9,65 +9,104 @@ namespace TorrentPier\Legacy\Datastore; +use League\Flysystem\Filesystem; +use League\Flysystem\Local\LocalFilesystemAdapter; +use MatthiasMullie\Scrapbook\Adapters\Flysystem; + /** * Class File * @package TorrentPier\Legacy\Datastore */ class File extends Common { - public $dir; - public $prefix; - public $engine = 'Filecache'; + /** + * Cache driver name + * + * @var string + */ + public string $engine = 'File'; - public function __construct($dir, $prefix = null) + /** + * Cache prefix + * + * @var string + */ + private string $prefix; + + /** + * Adapters\File class + * + * @var Flysystem + */ + private Flysystem $file; + + /** + * File constructor + * + * @param string $dir + * @param string $prefix + */ + public function __construct(string $dir, string $prefix) { global $debug; + $adapter = new LocalFilesystemAdapter($dir, null, LOCK_EX); + $filesystem = new Filesystem($adapter); + $this->file = new Flysystem($filesystem); $this->prefix = $prefix; - $this->dir = $dir; $this->dbg_enabled = $debug->sqlDebugAllowed(); } - public function store($title, $var) + /** + * Store data into cache + * + * @param string $item_name + * @param mixed $item_data + * @return bool + */ + public function store(string $item_name, mixed $item_data): bool { - $this->cur_query = "cache->set('$title')"; + $this->data[$item_name] = $item_data; + $item_name = $this->prefix . $item_name; + + $this->cur_query = "cache->" . __FUNCTION__ . "('$item_name')"; $this->debug('start'); - $this->data[$title] = $var; - - $filename = $this->dir . clean_filename($this->prefix . $title) . '.php'; - - $filecache = "'; + $result = $this->file->set($item_name, $item_data); $this->debug('stop'); $this->cur_query = null; $this->num_queries++; - return (bool)file_write($filecache, $filename, max_size: false, replace_content: true); + return $result; } - public function clean() + /** + * Removes data from cache + * + * @return void + */ + public function clean(): void { - $dir = $this->dir; + foreach ($this->known_items as $title => $script_name) { + $title = $this->prefix . $title; + $this->cur_query = "cache->rm('$title')"; + $this->debug('start'); - if (is_dir($dir)) { - if ($dh = opendir($dir)) { - while (($file = readdir($dh)) !== false) { - if ($file != "." && $file != "..") { - $filename = $dir . $file; + $this->file->delete($title); - unlink($filename); - } - } - closedir($dh); - } + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; } } - public function _fetch_from_store() + /** + * Fetch cache from store + * + * @return void + */ + public function _fetch_from_store(): void { $item = null; if (!$items = $this->queued_items) { @@ -76,19 +115,15 @@ class File extends Common } foreach ($items as $item) { - $filename = $this->dir . $this->prefix . $item . '.php'; - - $this->cur_query = "cache->get('$item')"; + $item_title = $this->prefix . $item; + $this->cur_query = "cache->get('$item_title')"; $this->debug('start'); + + $this->data[$item] = $this->file->get($item_title); + $this->debug('stop'); $this->cur_query = null; $this->num_queries++; - - if (is_file($filename) && is_readable($filename)) { - require($filename); - - $this->data[$item] = $filecache; - } } } } diff --git a/src/Legacy/Datastore/Memcache.php b/src/Legacy/Datastore/Memcache.php deleted file mode 100644 index f561d50b7..000000000 --- a/src/Legacy/Datastore/Memcache.php +++ /dev/null @@ -1,115 +0,0 @@ -is_installed()) { - die("Error: $this->engine extension not installed"); - } - - $this->cfg = $cfg; - $this->prefix = $prefix; - $this->memcache = new \Memcache(); - $this->dbg_enabled = $debug->sqlDebugAllowed(); - } - - public function connect() - { - $connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect'; - - $this->cur_query = $connect_type . ' ' . $this->cfg['host'] . ':' . $this->cfg['port']; - $this->debug('start'); - - if (@$this->memcache->$connect_type($this->cfg['host'], $this->cfg['port'])) { - $this->connected = true; - } - - if (!$this->connected && $this->cfg['con_required']) { - die("Could not connect to $this->engine server"); - } - - $this->debug('stop'); - $this->cur_query = null; - } - - public function store($title, $var) - { - if (!$this->connected) { - $this->connect(); - } - $this->data[$title] = $var; - - $this->cur_query = "cache->set('$title')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - return (bool)$this->memcache->set($this->prefix . $title, $var); - } - - public function clean() - { - if (!$this->connected) { - $this->connect(); - } - foreach ($this->known_items as $title => $script_name) { - $this->cur_query = "cache->rm('$title')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - $this->memcache->delete($this->prefix . $title, 0); - } - } - - public function _fetch_from_store() - { - $item = null; - if (!$items = $this->queued_items) { - $src = $this->_debug_find_caller('enqueue'); - trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR); - } - - if (!$this->connected) { - $this->connect(); - } - foreach ($items as $item) { - $this->cur_query = "cache->get('$item')"; - $this->debug('start'); - $this->debug('stop'); - $this->cur_query = null; - $this->num_queries++; - - $this->data[$item] = $this->memcache->get($this->prefix . $item); - } - } - - public function is_installed() - { - return class_exists('Memcache'); - } -} diff --git a/src/Legacy/Datastore/Memcached.php b/src/Legacy/Datastore/Memcached.php new file mode 100644 index 000000000..1cb3e517f --- /dev/null +++ b/src/Legacy/Datastore/Memcached.php @@ -0,0 +1,184 @@ +client = new MemcachedClient(); + $this->cfg = $cfg; + $this->prefix = $prefix; + $this->dbg_enabled = $debug->sqlDebugAllowed(); + } + + /** + * Connect to cache + * + * @return void + */ + private function connect(): void + { + $this->cur_query = 'connect ' . $this->cfg['host'] . ':' . $this->cfg['port']; + $this->debug('start'); + + if ($this->client->addServer($this->cfg['host'], $this->cfg['port'])) { + $this->connected = true; + } + + if (!$this->connected) { + die("Could not connect to $this->engine server"); + } + + $this->memcached = new MemcachedCache($this->client); + + $this->debug('stop'); + $this->cur_query = null; + } + + /** + * Store data into cache + * + * @param string $item_name + * @param mixed $item_data + * @return bool + */ + public function store(string $item_name, mixed $item_data): bool + { + if (!$this->connected) { + $this->connect(); + } + + $this->data[$item_name] = $item_data; + $item_name = $this->prefix . $item_name; + + $this->cur_query = "cache->" . __FUNCTION__ . "('$item_name')"; + $this->debug('start'); + + $result = $this->memcached->set($item_name, $item_data); + + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return $result; + } + + /** + * Removes data from cache + * + * @return void + */ + public function clean(): void + { + if (!$this->connected) { + $this->connect(); + } + + foreach ($this->known_items as $title => $script_name) { + $title = $this->prefix . $title; + $this->cur_query = "cache->rm('$title')"; + $this->debug('start'); + + $this->memcached->delete($title); + + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + } + } + + /** + * Fetch cache from store + * + * @return void + */ + public function _fetch_from_store(): void + { + $item = null; + if (!$items = $this->queued_items) { + $src = $this->_debug_find_caller('enqueue'); + trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR); + } + + if (!$this->connected) { + $this->connect(); + } + + foreach ($items as $item) { + $item_title = $this->prefix . $item; + $this->cur_query = "cache->get('$item_title')"; + $this->debug('start'); + + $this->data[$item] = $this->memcached->get($item_title); + + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + } + } +} diff --git a/src/Legacy/Datastore/Redis.php b/src/Legacy/Datastore/Redis.php index 35b662603..7cf193d44 100644 --- a/src/Legacy/Datastore/Redis.php +++ b/src/Legacy/Datastore/Redis.php @@ -9,84 +9,157 @@ namespace TorrentPier\Legacy\Datastore; +use Redis as RedisClient; +use MatthiasMullie\Scrapbook\Adapters\Redis as RedisCache; + /** * Class Redis * @package TorrentPier\Legacy\Datastore */ class Redis extends Common { - public $cfg; - public $redis; - public $prefix; - public $connected = false; - public $engine = 'Redis'; + /** + * Cache driver name + * + * @var string + */ + public string $engine = 'Redis'; - public function __construct($cfg, $prefix = null) + /** + * Connection status + * + * @var bool + */ + public bool $connected = false; + + /** + * Cache config + * + * @var array + */ + private array $cfg; + + /** + * Cache prefix + * + * @var string + */ + private string $prefix; + + /** + * Redis class + * + * @var RedisClient + */ + private RedisClient $client; + + /** + * Adapters\Redis class + * + * @var RedisCache + */ + private RedisCache $redis; + + /** + * Redis constructor + * + * @param array $cfg + * @param string $prefix + */ + public function __construct(array $cfg, string $prefix) { global $debug; - if (!$this->is_installed()) { - die("Error: $this->engine extension not installed"); - } - + $this->client = new RedisClient(); $this->cfg = $cfg; - $this->redis = new \Redis(); - $this->dbg_enabled = $debug->sqlDebugAllowed(); $this->prefix = $prefix; + $this->dbg_enabled = $debug->sqlDebugAllowed(); } - public function connect() + /** + * Connect to cache + * + * @return void + */ + private function connect(): void { - $connect_type = ($this->cfg['pconnect']) ? 'pconnect' : 'connect'; + $connectType = $this->cfg['pconnect'] ? 'pconnect' : 'connect'; - $this->cur_query = $connect_type . ' ' . $this->cfg['host'] . ':' . $this->cfg['port']; + $this->cur_query = $connectType . ' ' . $this->cfg['host'] . ':' . $this->cfg['port']; $this->debug('start'); - if (@$this->redis->$connect_type($this->cfg['host'], $this->cfg['port'])) { + if ($this->client->$connectType($this->cfg['host'], $this->cfg['port'])) { $this->connected = true; } - if (!$this->connected && $this->cfg['con_required']) { + if (!$this->connected) { die("Could not connect to $this->engine server"); } + $this->redis = new RedisCache($this->client); + $this->debug('stop'); $this->cur_query = null; } - public function store($title, $var) + /** + * Store data into cache + * + * @param string $item_name + * @param mixed $item_data + * @return bool + */ + public function store(string $item_name, mixed $item_data): bool { if (!$this->connected) { $this->connect(); } - $this->data[$title] = $var; - $this->cur_query = "cache->set('$title')"; + $this->data[$item_name] = $item_data; + $item_name = $this->prefix . $item_name; + + $this->cur_query = "cache->" . __FUNCTION__ . "('$item_name')"; $this->debug('start'); + + $result = $this->redis->set($item_name, $item_data); + $this->debug('stop'); $this->cur_query = null; $this->num_queries++; - return (bool)$this->redis->set($this->prefix . $title, serialize($var)); + return $result; } - public function clean() + /** + * Removes data from cache + * + * @return void + */ + public function clean(): void { if (!$this->connected) { $this->connect(); } + foreach ($this->known_items as $title => $script_name) { + $title = $this->prefix . $title; $this->cur_query = "cache->rm('$title')"; $this->debug('start'); + + $this->redis->delete($title); + $this->debug('stop'); $this->cur_query = null; $this->num_queries++; - - $this->redis->del($this->prefix . $title); } } - public function _fetch_from_store() + /** + * Fetch cache from store + * + * @return void + */ + public function _fetch_from_store(): void { $item = null; if (!$items = $this->queued_items) { @@ -97,19 +170,17 @@ class Redis extends Common if (!$this->connected) { $this->connect(); } + foreach ($items as $item) { - $this->cur_query = "cache->get('$item')"; + $item_title = $this->prefix . $item; + $this->cur_query = "cache->get('$item_title')"; $this->debug('start'); + + $this->data[$item] = $this->redis->get($item_title); + $this->debug('stop'); $this->cur_query = null; $this->num_queries++; - - $this->data[$item] = unserialize($this->redis->get($this->prefix . $item)); } } - - public function is_installed() - { - return class_exists('Redis'); - } } diff --git a/src/Legacy/Datastore/Sqlite.php b/src/Legacy/Datastore/Sqlite.php index d03647a0e..855b98aa0 100644 --- a/src/Legacy/Datastore/Sqlite.php +++ b/src/Legacy/Datastore/Sqlite.php @@ -9,7 +9,8 @@ namespace TorrentPier\Legacy\Datastore; -use SQLite3; +use MatthiasMullie\Scrapbook\Adapters\SQLite as SQLiteCache; +use PDO; /** * Class Sqlite @@ -17,73 +18,110 @@ use SQLite3; */ class Sqlite extends Common { - public $engine = 'SQLite'; - public $db; - public $prefix; - public $cfg = [ - 'db_file_path' => '/path/to/datastore.db.sqlite', - 'table_name' => 'datastore', - 'table_schema' => 'CREATE TABLE datastore ( - ds_title VARCHAR(255), - ds_data TEXT, - PRIMARY KEY (ds_title) - )', - 'pconnect' => true, - 'con_required' => true, - 'log_name' => 'DATASTORE', - ]; + /** + * Cache driver name + * + * @var string + */ + public string $engine = 'SQLite'; - public function __construct($cfg, $prefix = null) + /** + * Cache prefix + * + * @var string + */ + private string $prefix; + + /** + * Adapters\SQLite class + * + * @var SQLiteCache + */ + private SQLiteCache $sqlite; + + /** + * Sqlite constructor + * + * @param string $dir + * @param string $prefix + */ + public function __construct(string $dir, string $prefix) { - if (!$this->is_installed()) { - die('Error: SQLite3 extension not installed'); - } + global $debug; - $this->cfg = array_merge($this->cfg, $cfg); - $this->db = new SqliteCommon($this->cfg); + $client = new PDO("sqlite:$dir.db"); + $this->sqlite = new SQLiteCache($client); $this->prefix = $prefix; + $this->dbg_enabled = $debug->sqlDebugAllowed(); } - public function store($item_name, $item_data) + /** + * Store data into cache + * + * @param string $item_name + * @param mixed $item_data + * @return bool + */ + public function store(string $item_name, mixed $item_data): bool { $this->data[$item_name] = $item_data; + $item_name = $this->prefix . $item_name; - $ds_title = SQLite3::escapeString($this->prefix . $item_name); - $ds_data = SQLite3::escapeString(serialize($item_data)); + $this->cur_query = "cache->" . __FUNCTION__ . "('$item_name')"; + $this->debug('start'); - $result = $this->db->query("REPLACE INTO " . $this->cfg['table_name'] . " (ds_title, ds_data) VALUES ('$ds_title', '$ds_data')"); + $result = $this->sqlite->set($item_name, $item_data); - return (bool)$result; + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + + return $result; } - public function clean() + /** + * Removes data from cache + * + * @return void + */ + public function clean(): void { - $this->db->query("DELETE FROM " . $this->cfg['table_name']); + foreach ($this->known_items as $title => $script_name) { + $title = $this->prefix . $title; + $this->cur_query = "cache->rm('$title')"; + $this->debug('start'); + + $this->sqlite->delete($title); + + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; + } } - public function _fetch_from_store() + /** + * Fetch cache from store + * + * @return void + */ + public function _fetch_from_store(): void { + $item = null; if (!$items = $this->queued_items) { - return; + $src = $this->_debug_find_caller('enqueue'); + trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR); } - $prefix_len = \strlen($this->prefix); - $prefix_sql = SQLite3::escapeString($this->prefix); + foreach ($items as $item) { + $item_title = $this->prefix . $item; + $this->cur_query = "cache->get('$item_title')"; + $this->debug('start'); - array_deep($items, 'SQLite3::escapeString'); - $items_list = $prefix_sql . implode("','$prefix_sql", $items); + $this->data[$item] = $this->sqlite->get($item_title); - $rowset = $this->db->fetch_rowset("SELECT ds_title, ds_data FROM " . $this->cfg['table_name'] . " WHERE ds_title IN ('$items_list')"); - - $this->db->debug('start', "unserialize()"); - foreach ($rowset as $row) { - $this->data[substr($row['ds_title'], $prefix_len)] = unserialize($row['ds_data']); + $this->debug('stop'); + $this->cur_query = null; + $this->num_queries++; } - $this->db->debug('stop'); - } - - public function is_installed() - { - return class_exists('SQLite3'); } } diff --git a/src/Legacy/Datastore/SqliteCommon.php b/src/Legacy/Datastore/SqliteCommon.php deleted file mode 100644 index 717e31a19..000000000 --- a/src/Legacy/Datastore/SqliteCommon.php +++ /dev/null @@ -1,167 +0,0 @@ - 'sqlite.db', - 'table_name' => 'table_name', - 'table_schema' => 'CREATE TABLE table_name (...)', - 'pconnect' => true, - 'con_required' => true, - 'log_name' => 'SQLite', - 'shard_type' => 'none', # none, string, int (тип перевичного ключа для шардинга) - 'shard_val' => 0, # для string - кол. начальных символов, для int - делитель (будет использован остаток от деления) - ]; - public $engine = 'SQLite'; - public $dbh; - public $connected = false; - public $shard_val = false; - - public $table_create_attempts = 0; - - public function __construct($cfg) - { - global $debug; - - $this->cfg = array_merge($this->cfg, $cfg); - $this->dbg_enabled = $debug->sqlDebugAllowed(); - } - - public function connect() - { - $this->cur_query = $this->dbg_enabled ? 'connect to: ' . $this->cfg['db_file_path'] : 'connect'; - $this->debug('start'); - - if (@$this->dbh = new SQLite3($this->cfg['db_file_path'])) { - $this->connected = true; - } - - if (!$this->connected && $this->cfg['con_required']) { - trigger_error('SQLite not connected', E_USER_ERROR); - } - - $this->debug('stop'); - $this->cur_query = null; - } - - public function create_table() - { - $this->table_create_attempts++; - return $this->dbh->query($this->cfg['table_schema']); - } - - public function shard($name) - { - $type = $this->cfg['shard_type']; - - if ($type == 'none') { - return; - } - if (\is_array($name)) { - trigger_error('cannot shard: $name is array', E_USER_ERROR); - } - - // define shard_val - if ($type == 'string') { - $shard_val = substr($name, 0, $this->cfg['shard_val']); - } else { - $shard_val = $name % $this->cfg['shard_val']; - } - // все запросы должны быть к одному и тому же шарду - if ($this->shard_val !== false) { - if ($shard_val != $this->shard_val) { - trigger_error("shard cannot be reassigned. [{$this->shard_val}, $shard_val, $name]", E_USER_ERROR); - } else { - return; - } - } - $this->shard_val = $shard_val; - $this->cfg['db_file_path'] = str_replace('*', $shard_val, $this->cfg['db_file_path']); - } - - public function query($query) - { - if (!$this->connected) { - $this->connect(); - } - - $this->cur_query = $query; - $this->debug('start'); - - if (!$result = @$this->dbh->query($query)) { - $rowsresult = $this->dbh->query("PRAGMA table_info({$this->cfg['table_name']})"); - $rowscount = 0; - while ($row = $rowsresult->fetchArray(SQLITE3_ASSOC)) { - $rowscount++; - } - if (!$this->table_create_attempts && !$rowscount) { - if ($this->create_table()) { - $result = $this->dbh->query($query); - } - } - if (!$result) { - $this->trigger_error($this->get_error_msg()); - } - } - - $this->debug('stop'); - $this->cur_query = null; - - $this->num_queries++; - - return $result; - } - - public function fetch_row($query) - { - $result = $this->query($query); - return \is_resource($result) ? $result->fetchArray(SQLITE3_ASSOC) : false; - } - - public function fetch_rowset($query) - { - $result = $this->query($query); - $rowset = []; - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - $rowset[] = $row; - } - return $rowset; - } - - public function changes() - { - return \is_resource($this->dbh) ? $this->dbh->changes() : 0; - } - - public function escape($str) - { - return SQLite3::escapeString($str); - } - - public function get_error_msg() - { - return 'SQLite error #' . $this->dbh->lastErrorCode() . ': ' . $this->dbh->lastErrorMsg(); - } - - public function trigger_error($msg = 'DB Error') - { - if (error_reporting()) { - trigger_error($msg, E_USER_ERROR); - } - } -}