From ea7102744d44e59a0fccee812dc48efb4bc0e4c3 Mon Sep 17 00:00:00 2001 From: Christian Kuhn <lolli@schwarzbu.ch> Date: Sun, 28 Nov 2021 03:40:17 +0100 Subject: [PATCH] [!!!][TASK] Remove WincacheBackend cache backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves: #96115 Related: #94665 Releases: master Change-Id: Id7702f2328a0ca848656caae8350d6facc65068a Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/72336 Tested-by: Stefan Bürk <stefan@buerk.tech> Tested-by: Wouter Wolters <typo3@wouterwolters.nl> Tested-by: Benni Mack <benni@typo3.org> Reviewed-by: Stefan Bürk <stefan@buerk.tech> Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl> Reviewed-by: Benni Mack <benni@typo3.org> --- .../Classes/Cache/Backend/WincacheBackend.php | 263 ----------------- ...g-96107-DeprecatedFunctionalityRemoved.rst | 1 + .../Cache/Backend/WincacheBackendTest.php | 279 ------------------ 3 files changed, 1 insertion(+), 542 deletions(-) delete mode 100644 typo3/sysext/core/Classes/Cache/Backend/WincacheBackend.php delete mode 100644 typo3/sysext/core/Tests/UnitDeprecated/Cache/Backend/WincacheBackendTest.php diff --git a/typo3/sysext/core/Classes/Cache/Backend/WincacheBackend.php b/typo3/sysext/core/Classes/Cache/Backend/WincacheBackend.php deleted file mode 100644 index 025c105c0000..000000000000 --- a/typo3/sysext/core/Classes/Cache/Backend/WincacheBackend.php +++ /dev/null @@ -1,263 +0,0 @@ -<?php - -/* - * This file is part of the TYPO3 CMS project. - * - * It is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, either version 2 - * of the License, or any later version. - * - * For the full copyright and license information, please read the - * LICENSE.txt file that was distributed with this source code. - * - * The TYPO3 project - inspiring people to share! - */ - -namespace TYPO3\CMS\Core\Cache\Backend; - -use TYPO3\CMS\Core\Cache\Exception; -use TYPO3\CMS\Core\Cache\Exception\InvalidDataException; -use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; - -/** - * A caching backend which stores cache entries by using wincache. - * - * This backend uses the following types of keys: - * - tag_xxx - * xxx is tag name, value is array of associated identifiers identifier. This - * is "forward" tag index. It is mainly used for obtaining content by tag - * (get identifier by tag -> get content by identifier) - * - ident_xxx - * xxx is identifier, value is array of associated tags. This is "reverse" tag - * index. It provides quick access for all tags associated with this identifier - * and used when removing the identifier - * - * Each key is prepended with a prefix. By default prefix consists from two parts - * separated by underscore character and ends in yet another underscore character: - * - "TYPO3" - * - MD5 of script path and filename and SAPI name - * This prefix makes sure that keys from the different installations do not - * conflict. - * - * @deprecated since v11, will be removed in v12. A substitution with similar characteristics is the ApcuBackend. - */ -class WincacheBackend extends AbstractBackend implements TaggableBackendInterface -{ - /** - * A prefix to separate stored data from other data possible stored in the wincache - * - * @var string - */ - protected $identifierPrefix; - - /** - * Constructs this backend - * - * @param string $context Unused, for backward compatibility only - * @param array $options Configuration options - * @throws Exception If wincache PHP extension is not loaded - */ - public function __construct($context, array $options = []) - { - if (!extension_loaded('wincache')) { - throw new Exception('The PHP extension "wincache" must be installed and loaded in order to use the wincache backend.', 1343331520); - } - trigger_error(__CLASS__ . ' will be removed in TYPO3 v12, use ApcuBackend as substitution with similar characteristics.', E_USER_DEPRECATED); - parent::__construct($context, $options); - } - - /** - * Saves data in the cache - * - * @param string $entryIdentifier An identifier for this specific cache entry - * @param string $data The data to be stored - * @param array $tags Tags to associate with this cache entry - * @param int $lifetime Lifetime of this cache entry in seconds. If NULL is specified, the default lifetime is used. "0" means unlimited lifetime. - * @throws Exception if no cache frontend has been set - * @throws \InvalidArgumentException if the identifier is not valid - * @throws InvalidDataException if $data is not a string - */ - public function set($entryIdentifier, $data, array $tags = [], $lifetime = null) - { - if (!$this->cache instanceof FrontendInterface) { - throw new Exception('No cache frontend has been set yet via setCache().', 1343331521); - } - if (!is_string($data)) { - throw new InvalidDataException('The specified data is of type "' . gettype($data) . '" but a string is expected.', 1343331522); - } - $tags[] = '%WCBE%' . $this->cache->getIdentifier(); - $expiration = $lifetime ?? $this->defaultLifetime; - $success = wincache_ucache_set($this->identifierPrefix . $entryIdentifier, $data, $expiration); - if ($success === true) { - $this->removeIdentifierFromAllTags($entryIdentifier); - $this->addIdentifierToTags($entryIdentifier, $tags); - } else { - throw new Exception('Could not set value.', 1343331523); - } - } - - /** - * Loads data from the cache - * - * @param string $entryIdentifier An identifier which describes the cache entry to load - * @return mixed The cache entry's content as a string or FALSE if the cache entry could not be loaded - */ - public function get($entryIdentifier) - { - $success = false; - $value = wincache_ucache_get($this->identifierPrefix . $entryIdentifier, $success); - return $success ? $value : $success; - } - - /** - * Checks if a cache entry with the specified identifier exists - * - * @param string $entryIdentifier An identifier specifying the cache entry - * @return bool TRUE if such an entry exists, FALSE if not - */ - public function has($entryIdentifier) - { - return wincache_ucache_exists($this->identifierPrefix . $entryIdentifier); - } - - /** - * Removes all cache entries matching the specified identifier. - * Usually this only affects one entry but if - for what reason ever - - * old entries for the identifier still exist, they are removed as well. - * - * @param string $entryIdentifier Specifies the cache entry to remove - * @return bool TRUE if (at least) an entry could be removed or FALSE if no entry was found - */ - public function remove($entryIdentifier) - { - $this->removeIdentifierFromAllTags($entryIdentifier); - return wincache_ucache_delete($this->identifierPrefix . $entryIdentifier); - } - - /** - * Finds and returns all cache entry identifiers which are tagged by the - * specified tag. - * - * @param string $tag The tag to search for - * @return array An array with identifiers of all matching entries. An empty array if no entries matched - */ - public function findIdentifiersByTag($tag) - { - $success = false; - $identifiers = wincache_ucache_get($this->identifierPrefix . 'tag_' . $tag, $success); - if ($success === false) { - return []; - } - return (array)$identifiers; - } - - /** - * Finds all tags for the given identifier. This function uses reverse tag - * index to search for tags. - * - * @param string $identifier Identifier to find tags by - * @return array Array with tags - */ - protected function findTagsByIdentifier($identifier) - { - $success = false; - $tags = wincache_ucache_get($this->identifierPrefix . 'ident_' . $identifier, $success); - return $success ? (array)$tags : []; - } - - /** - * Removes all cache entries of this cache - * - * @throws Exception - */ - public function flush() - { - if (!$this->cache instanceof FrontendInterface) { - throw new Exception('Yet no cache frontend has been set via setCache().', 1343331524); - } - $this->flushByTag('%WCBE%' . $this->cache->getIdentifier()); - } - - /** - * Removes all cache entries of this cache which are tagged by the specified - * tag. - * - * @param string $tag The tag the entries must have - */ - public function flushByTag($tag) - { - $identifiers = $this->findIdentifiersByTag($tag); - foreach ($identifiers as $identifier) { - $this->remove($identifier); - } - } - - /** - * Associates the identifier with the given tags - * - * @param string $entryIdentifier - * @param array $tags - */ - protected function addIdentifierToTags($entryIdentifier, array $tags) - { - // Get identifier-to-tag index to look for updates - $existingTags = $this->findTagsByIdentifier($entryIdentifier); - $existingTagsUpdated = false; - - foreach ($tags as $tag) { - // Update tag-to-identifier index - $identifiers = $this->findIdentifiersByTag($tag); - if (!in_array($entryIdentifier, $identifiers, true)) { - $identifiers[] = $entryIdentifier; - wincache_ucache_set($this->identifierPrefix . 'tag_' . $tag, $identifiers); - } - // Test if identifier-to-tag index needs update - if (!in_array($tag, $existingTags, true)) { - $existingTags[] = $tag; - $existingTagsUpdated = true; - } - } - - // Update identifier-to-tag index if needed - if ($existingTagsUpdated) { - wincache_ucache_set($this->identifierPrefix . 'ident_' . $entryIdentifier, $existingTags); - } - } - - /** - * Removes association of the identifier with the given tags - * - * @param string $entryIdentifier - */ - protected function removeIdentifierFromAllTags($entryIdentifier) - { - // Get tags for this identifier - $tags = $this->findTagsByIdentifier($entryIdentifier); - // Deassociate tags with this identifier - foreach ($tags as $tag) { - $identifiers = $this->findIdentifiersByTag($tag); - // Formally array_search() below should never return false due to - // the behavior of findTagsByIdentifier(). But if reverse index is - // corrupted, we still can get 'false' from array_search(). This is - // not a problem because we are removing this identifier from - // anywhere. - if (($key = array_search($entryIdentifier, $identifiers)) !== false) { - unset($identifiers[$key]); - if (!empty($identifiers)) { - wincache_ucache_set($this->identifierPrefix . 'tag_' . $tag, $identifiers); - } else { - wincache_ucache_delete($this->identifierPrefix . 'tag_' . $tag); - } - } - } - // Clear reverse tag index for this identifier - wincache_ucache_delete($this->identifierPrefix . 'ident_' . $entryIdentifier); - } - - /** - * Does nothing, as wincache does GC itself - */ - public function collectGarbage() - { - } -} diff --git a/typo3/sysext/core/Documentation/Changelog/12.0/Breaking-96107-DeprecatedFunctionalityRemoved.rst b/typo3/sysext/core/Documentation/Changelog/12.0/Breaking-96107-DeprecatedFunctionalityRemoved.rst index ba0d0212d4d7..c01c5ada6689 100644 --- a/typo3/sysext/core/Documentation/Changelog/12.0/Breaking-96107-DeprecatedFunctionalityRemoved.rst +++ b/typo3/sysext/core/Documentation/Changelog/12.0/Breaking-96107-DeprecatedFunctionalityRemoved.rst @@ -12,6 +12,7 @@ Description The following PHP classes that have previously been marked as deprecated for v11 and were now removed: - :php:`\TYPO3\CMS\Core\Cache\Backend\PdoBackend` +- :php:`\TYPO3\CMS\Core\Cache\Backend\WincacheBackend` - :php:`\TYPO3\CMS\Core\Database\QueryGenerator` - :php:`\TYPO3\CMS\Core\Database\QueryView` diff --git a/typo3/sysext/core/Tests/UnitDeprecated/Cache/Backend/WincacheBackendTest.php b/typo3/sysext/core/Tests/UnitDeprecated/Cache/Backend/WincacheBackendTest.php deleted file mode 100644 index 828a6119e447..000000000000 --- a/typo3/sysext/core/Tests/UnitDeprecated/Cache/Backend/WincacheBackendTest.php +++ /dev/null @@ -1,279 +0,0 @@ -<?php - -declare(strict_types=1); - -/* - * This file is part of the TYPO3 CMS project. - * - * It is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, either version 2 - * of the License, or any later version. - * - * For the full copyright and license information, please read the - * LICENSE.txt file that was distributed with this source code. - * - * The TYPO3 project - inspiring people to share! - */ - -namespace TYPO3\CMS\Core\Tests\UnitDeprecated\Cache\Backend; - -use TYPO3\CMS\Core\Cache\Backend\WincacheBackend; -use TYPO3\CMS\Core\Cache\Exception; -use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; -use TYPO3\CMS\Core\Utility\StringUtility; -use TYPO3\TestingFramework\Core\Unit\UnitTestCase; - -/** - * Testcase for the WinCache cache backend - * - * @requires extension wincache - */ -class WincacheBackendTest extends UnitTestCase -{ - /** - * @test - */ - public function setThrowsExceptionIfNoFrontEndHasBeenSet(): void - { - $this->expectException(Exception::class); - // @todo Add exception code with wincache extension - - $backend = new WincacheBackend('Testing'); - $data = 'Some data'; - $identifier = StringUtility::getUniqueId('MyIdentifier'); - $backend->set($identifier, $data); - } - - /** - * @test - */ - public function itIsPossibleToSetAndCheckExistenceInCache(): void - { - $backend = $this->setUpBackend(); - $data = 'Some data'; - $identifier = StringUtility::getUniqueId('MyIdentifier'); - $backend->set($identifier, $data); - $inCache = $backend->has($identifier); - self::assertTrue($inCache, 'WinCache backend failed to set and check entry'); - } - - /** - * @test - */ - public function itIsPossibleToSetAndGetEntry(): void - { - $backend = $this->setUpBackend(); - $data = 'Some data'; - $identifier = StringUtility::getUniqueId('MyIdentifier'); - $backend->set($identifier, $data); - $fetchedData = $backend->get($identifier); - self::assertEquals($data, $fetchedData, 'Wincache backend failed to set and retrieve data'); - } - - /** - * @test - */ - public function itIsPossibleToRemoveEntryFromCache(): void - { - $backend = $this->setUpBackend(); - $data = 'Some data'; - $identifier = StringUtility::getUniqueId('MyIdentifier'); - $backend->set($identifier, $data); - $backend->remove($identifier); - $inCache = $backend->has($identifier); - self::assertFalse($inCache, 'Failed to set and remove data from WinCache backend'); - } - - /** - * @test - */ - public function itIsPossibleToOverwriteAnEntryInTheCache(): void - { - $backend = $this->setUpBackend(); - $data = 'Some data'; - $identifier = StringUtility::getUniqueId('MyIdentifier'); - $backend->set($identifier, $data); - $otherData = 'some other data'; - $backend->set($identifier, $otherData); - $fetchedData = $backend->get($identifier); - self::assertEquals($otherData, $fetchedData, 'WinCache backend failed to overwrite and retrieve data'); - } - - /** - * @test - */ - public function findIdentifiersByTagFindsSetEntries(): void - { - $backend = $this->setUpBackend(); - $data = 'Some data'; - $identifier = StringUtility::getUniqueId('MyIdentifier'); - $backend->set($identifier, $data, ['UnitTestTag%tag1', 'UnitTestTag%tag2']); - $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tag1'); - self::assertEquals($identifier, $retrieved[0], 'Could not retrieve expected entry by tag.'); - $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tag2'); - self::assertEquals($identifier, $retrieved[0], 'Could not retrieve expected entry by tag.'); - } - - /** - * @test - */ - public function setRemovesTagsFromPreviousSet(): void - { - $backend = $this->setUpBackend(); - $data = 'Some data'; - $identifier = StringUtility::getUniqueId('MyIdentifier'); - $backend->set($identifier, $data, ['UnitTestTag%tag1', 'UnitTestTag%tagX']); - $backend->set($identifier, $data, ['UnitTestTag%tag3']); - $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tagX'); - self::assertEquals([], $retrieved, 'Found entry which should no longer exist.'); - } - - /** - * @test - */ - public function hasReturnsFalseIfTheEntryDoesntExist(): void - { - $backend = $this->setUpBackend(); - $identifier = StringUtility::getUniqueId('NonExistingIdentifier'); - $inCache = $backend->has($identifier); - self::assertFalse($inCache, '"has" did not return FALSE when checking on non existing identifier'); - } - - /** - * @test - */ - public function removeReturnsFalseIfTheEntryDoesntExist(): void - { - $backend = $this->setUpBackend(); - $identifier = StringUtility::getUniqueId('NonExistingIdentifier'); - $inCache = $backend->remove($identifier); - self::assertFalse($inCache, '"remove" did not return FALSE when checking on non existing identifier'); - } - - /** - * @test - */ - public function flushByTagRemovesCacheEntriesWithSpecifiedTag(): void - { - $backend = $this->setUpBackend(); - $data = 'some data' . microtime(); - $backend->set('BackendWincacheTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']); - $backend->set('BackendWincacheTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']); - $backend->set('BackendWincacheTest3', $data, ['UnitTestTag%test']); - $backend->flushByTag('UnitTestTag%special'); - self::assertTrue($backend->has('BackendWincacheTest1'), 'BackendWincacheTest1'); - self::assertFalse($backend->has('BackendWincacheTest2'), 'BackendWincacheTest2'); - self::assertTrue($backend->has('BackendWincacheTest3'), 'BackendWincacheTest3'); - } - - /** - * @test - */ - public function flushByTagsRemovesCacheEntriesWithSpecifiedTags(): void - { - $backend = $this->setUpBackend(); - $data = 'some data' . microtime(); - $backend->set('BackendWincacheTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']); - $backend->set('BackendWincacheTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']); - $backend->set('BackendWincacheTest3', $data, ['UnitTestTag%test']); - $backend->flushByTag('UnitTestTag%special', 'UnitTestTag%boring'); - self::assertTrue($backend->has('BackendWincacheTest1'), 'BackendWincacheTest1'); - self::assertFalse($backend->has('BackendWincacheTest2'), 'BackendWincacheTest2'); - self::assertTrue($backend->has('BackendWincacheTest3'), 'BackendWincacheTest3'); - } - - /** - * @test - */ - public function flushRemovesAllCacheEntries(): void - { - $backend = $this->setUpBackend(); - $data = 'some data' . microtime(); - $backend->set('BackendWincacheTest1', $data); - $backend->set('BackendWincacheTest2', $data); - $backend->set('BackendWincacheTest3', $data); - $backend->flush(); - self::assertFalse($backend->has('BackendWincacheTest1'), 'BackendWincacheTest1'); - self::assertFalse($backend->has('BackendWincacheTest2'), 'BackendWincacheTest2'); - self::assertFalse($backend->has('BackendWincacheTest3'), 'BackendWincacheTest3'); - } - - /** - * @test - */ - public function flushRemovesOnlyOwnEntries(): void - { - /** @var \PHPUnit\Framework\MockObject\MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thisCache */ - $thisCache = $this->createMock(FrontendInterface::class); - $thisCache->method('getIdentifier')->willReturn('thisCache'); - $thisBackend = new WincacheBackend('Testing'); - $thisBackend->setCache($thisCache); - - /** @var \PHPUnit\Framework\MockObject\MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thatCache */ - $thatCache = $this->createMock(FrontendInterface::class); - $thatCache->method('getIdentifier')->willReturn('thatCache'); - $thatBackend = new WincacheBackend('Testing'); - $thatBackend->setCache($thatCache); - $thisBackend->set('thisEntry', 'Hello'); - $thatBackend->set('thatEntry', 'World!'); - $thatBackend->flush(); - self::assertEquals('Hello', $thisBackend->get('thisEntry')); - self::assertFalse($thatBackend->has('thatEntry')); - } - - /** - * Check if we can store ~5 MB of data - * - * @test - */ - public function largeDataIsStored(): void - { - $backend = $this->setUpBackend(); - $data = str_repeat('abcde', 1024 * 1024); - $identifier = StringUtility::getUniqueId('tooLargeData'); - $backend->set($identifier, $data); - self::assertTrue($backend->has($identifier)); - self::assertEquals($backend->get($identifier), $data); - } - - /** - * @test - */ - public function setTagsOnlyOnceToIdentifier(): void - { - $identifier = StringUtility::getUniqueId('MyIdentifier'); - $tags = ['UnitTestTag%test', 'UnitTestTag%boring']; - - $backend = $this->setUpBackend(true); - $backend->_call('addIdentifierToTags', $identifier, $tags); - self::assertSame( - $tags, - $backend->_call('findTagsByIdentifier', $identifier) - ); - - $backend->_call('addIdentifierToTags', $identifier, $tags); - self::assertSame( - $tags, - $backend->_call('findTagsByIdentifier', $identifier) - ); - } - - /** - * Sets up the WinCache backend used for testing - * - * @param bool $accessible TRUE if backend should be encapsulated in accessible proxy otherwise FALSE. - * @return \TYPO3\TestingFramework\Core\AccessibleObjectInterface|WincacheBackend - */ - protected function setUpBackend(bool $accessible = false) - { - /** @var \PHPUnit\Framework\MockObject\MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cache */ - $cache = $this->createMock(FrontendInterface::class); - if ($accessible) { - $backend = $this->getAccessibleMock(WincacheBackend::class, ['dummy'], ['Testing']); - } else { - $backend = new WincacheBackend('Testing'); - } - $backend->setCache($cache); - return $backend; - } -} -- GitLab