[TASK] Improve TCA cache 14/54114/2
authorHelmut Hummel <typo3@helhum.io>
Sat, 9 Sep 2017 12:32:20 +0000 (14:32 +0200)
committerChristian Kuhn <lolli@schwarzbu.ch>
Mon, 11 Sep 2017 12:13:26 +0000 (14:13 +0200)
Currently TCA is cached as serialized string using
the core cache.

Simplify the cache retrieval by taking advantage of
the code cache by using requireOnce and previously
storing the cache as PHP file that returns an array.
This significantly improves performance
with opcode cache enabled.

The cache identifier is changed to avoid conflicts
with previously stored data.

Resolves: #82408
Releases: master, 8.7
Change-Id: I59210fa800d10c14d21aceb7416ea418988d6ca5
Reviewed-on: https://review.typo3.org/54114
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php
typo3/sysext/core/Tests/Unit/Utility/ExtensionManagementUtilityTest.php

index eace602..94f7deb 100644 (file)
@@ -1687,11 +1687,10 @@ tt_content.' . $key . $suffix . ' {
             $cacheIdentifier = static::getBaseTcaCacheIdentifier();
             /** @var $codeCache \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend */
             $codeCache = static::getCacheManager()->getCache('cache_core');
-            if ($codeCache->has($cacheIdentifier)) {
-                // substr is necessary, because the php frontend wraps php code around the cache value
-                $cacheData = unserialize(substr($codeCache->get($cacheIdentifier), 6, -2));
+            $cacheData = $codeCache->requireOnce($cacheIdentifier);
+            if ($cacheData) {
                 $GLOBALS['TCA'] = $cacheData['tca'];
-                GeneralUtility::setSingletonInstance(CategoryRegistry::class, $cacheData['categoryRegistry']);
+                GeneralUtility::setSingletonInstance(CategoryRegistry::class, unserialize($cacheData['categoryRegistry'], [CategoryRegistry::class]));
             } else {
                 static::buildBaseTcaFromSingleFiles();
                 static::createBaseTcaCacheFile();
@@ -1798,7 +1797,12 @@ tt_content.' . $key . $suffix . ' {
     {
         /** @var $codeCache \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend */
         $codeCache = self::getCacheManager()->getCache('cache_core');
-        $codeCache->set(static::getBaseTcaCacheIdentifier(), serialize(['tca' => $GLOBALS['TCA'], 'categoryRegistry' => CategoryRegistry::getInstance()]));
+        $codeCache->set(
+            static::getBaseTcaCacheIdentifier(),
+            'return '
+                . var_export(['tca' => $GLOBALS['TCA'], 'categoryRegistry' => serialize(CategoryRegistry::getInstance())], true)
+                . ';'
+        );
     }
 
     /**
@@ -1808,7 +1812,7 @@ tt_content.' . $key . $suffix . ' {
      */
     protected static function getBaseTcaCacheIdentifier()
     {
-        return 'tca_base_' . sha1(TYPO3_version . PATH_site . 'tca_with_category_registry' . serialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['runtimeActivatedPackages']));
+        return 'tca_base_' . sha1(TYPO3_version . PATH_site . 'tca_code' . serialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['runtimeActivatedPackages']));
     }
 
     /**
index 8dd5b01..bf15c4c 100644 (file)
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Core\Tests\Unit\Utility;
  */
 
 use TYPO3\CMS\Core\Cache\CacheManager;
-use TYPO3\CMS\Core\Cache\Frontend\AbstractFrontend;
+use TYPO3\CMS\Core\Cache\Frontend\PhpFrontend;
 use TYPO3\CMS\Core\Category\CategoryRegistry;
 use TYPO3\CMS\Core\Compatibility\LoadedExtensionsArray;
 use TYPO3\CMS\Core\Package\MetaData;
@@ -1284,7 +1284,7 @@ class ExtensionManagementUtilityTest extends \TYPO3\TestingFramework\Core\Unit\U
      */
     public function loadExtLocalconfRequiresCacheFileIfExistsAndCachingIsAllowed()
     {
-        $mockCache = $this->getMockBuilder(AbstractFrontend::class)
+        $mockCache = $this->getMockBuilder(PhpFrontend::class)
             ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
             ->disableOriginalConstructor()
             ->getMock();
@@ -1408,7 +1408,7 @@ class ExtensionManagementUtilityTest extends \TYPO3\TestingFramework\Core\Unit\U
         $uniqueStringInLocalconf = $this->getUniqueId('foo');
         file_put_contents($extLocalconfLocation, "<?php\n\n" . $uniqueStringInLocalconf . "\n\n?>");
         $GLOBALS['TYPO3_LOADED_EXT'] = new LoadedExtensionsArray($packageManager);
-        $mockCache = $this->getMockBuilder(AbstractFrontend::class)
+        $mockCache = $this->getMockBuilder(PhpFrontend::class)
             ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
             ->disableOriginalConstructor()
             ->getMock();
@@ -1431,7 +1431,7 @@ class ExtensionManagementUtilityTest extends \TYPO3\TestingFramework\Core\Unit\U
         $extensionName = $this->getUniqueId('foo');
         $packageManager = $this->createMockPackageManagerWithMockPackage($extensionName);
         $GLOBALS['TYPO3_LOADED_EXT'] = new LoadedExtensionsArray($packageManager);
-        $mockCache = $this->getMockBuilder(AbstractFrontend::class)
+        $mockCache = $this->getMockBuilder(PhpFrontend::class)
             ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
             ->disableOriginalConstructor()
             ->getMock();
@@ -1453,7 +1453,7 @@ class ExtensionManagementUtilityTest extends \TYPO3\TestingFramework\Core\Unit\U
      */
     public function createExtLocalconfCacheEntryWritesCacheEntryWithNoTags()
     {
-        $mockCache = $this->getMockBuilder(AbstractFrontend::class)
+        $mockCache = $this->getMockBuilder(PhpFrontend::class)
             ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
             ->disableOriginalConstructor()
             ->getMock();
@@ -1507,7 +1507,7 @@ class ExtensionManagementUtilityTest extends \TYPO3\TestingFramework\Core\Unit\U
      */
     public function loadBaseTcaRequiresCacheFileIfExistsAndCachingIsAllowed()
     {
-        $mockCache = $this->getMockBuilder(AbstractFrontend::class)
+        $mockCache = $this->getMockBuilder(PhpFrontend::class)
             ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
             ->disableOriginalConstructor()
             ->getMock();
@@ -1518,8 +1518,7 @@ class ExtensionManagementUtilityTest extends \TYPO3\TestingFramework\Core\Unit\U
             ->getMock();
         $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
         ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
-        $mockCache->expects($this->any())->method('has')->will($this->returnValue(true));
-        $mockCache->expects($this->once())->method('get')->willReturn('<?php ' . serialize(['tca' => [], 'categoryRegistry' => CategoryRegistry::getInstance()]) . '?>');
+        $mockCache->expects($this->once())->method('requireOnce')->willReturn(['tca' => [], 'categoryRegistry' => \serialize(CategoryRegistry::getInstance())]);
         ExtensionManagementUtilityAccessibleProxy::loadBaseTca(true);
     }
 
@@ -1540,7 +1539,7 @@ class ExtensionManagementUtilityTest extends \TYPO3\TestingFramework\Core\Unit\U
         $uniqueStringInTableConfiguration = $this->getUniqueId('table_configuration_');
         $tableConfiguration = '<?php return array(\'foo\' => \'' . $uniqueStringInTableConfiguration . '\'); ?>';
         file_put_contents($packagePath . 'Configuration/TCA/' . $uniqueTableName . '.php', $tableConfiguration);
-        $mockCache = $this->getMockBuilder(AbstractFrontend::class)
+        $mockCache = $this->getMockBuilder(PhpFrontend::class)
             ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
             ->disableOriginalConstructor()
             ->getMock();
@@ -1551,7 +1550,7 @@ class ExtensionManagementUtilityTest extends \TYPO3\TestingFramework\Core\Unit\U
             ->getMock();
         $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
         ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
-        $mockCache->expects($this->once())->method('has')->will($this->returnValue(false));
+        $mockCache->expects($this->once())->method('requireOnce')->will($this->returnValue(false));
         $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->stringContains($uniqueStringInTableConfiguration), $this->anything());
         ExtensionManagementUtility::loadBaseTca(true);
     }
@@ -1561,7 +1560,7 @@ class ExtensionManagementUtilityTest extends \TYPO3\TestingFramework\Core\Unit\U
      */
     public function loadBaseTcaWritesCacheEntryWithNoTags()
     {
-        $mockCache = $this->getMockBuilder(AbstractFrontend::class)
+        $mockCache = $this->getMockBuilder(PhpFrontend::class)
             ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
             ->disableOriginalConstructor()
             ->getMock();
@@ -1572,7 +1571,7 @@ class ExtensionManagementUtilityTest extends \TYPO3\TestingFramework\Core\Unit\U
             ->getMock();
         $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
         ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
-        $mockCache->expects($this->once())->method('has')->will($this->returnValue(false));
+        $mockCache->expects($this->once())->method('requireOnce')->will($this->returnValue(false));
         $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->anything(), $this->equalTo([]));
         ExtensionManagementUtilityAccessibleProxy::loadBaseTca();
     }
@@ -1616,7 +1615,7 @@ class ExtensionManagementUtilityTest extends \TYPO3\TestingFramework\Core\Unit\U
      */
     public function loadExtTablesRequiresCacheFileIfExistsAndCachingIsAllowed()
     {
-        $mockCache = $this->getMockBuilder(AbstractFrontend::class)
+        $mockCache = $this->getMockBuilder(PhpFrontend::class)
             ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
             ->disableOriginalConstructor()
             ->getMock();
@@ -1653,7 +1652,7 @@ class ExtensionManagementUtilityTest extends \TYPO3\TestingFramework\Core\Unit\U
                 'ext_tables.php' => $extTablesLocation
             ]
         ];
-        $mockCache = $this->getMockBuilder(AbstractFrontend::class)
+        $mockCache = $this->getMockBuilder(PhpFrontend::class)
             ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
             ->disableOriginalConstructor()
             ->getMock();
@@ -1677,7 +1676,7 @@ class ExtensionManagementUtilityTest extends \TYPO3\TestingFramework\Core\Unit\U
         $GLOBALS['TYPO3_LOADED_EXT'] = [
             $extensionName => [],
         ];
-        $mockCache = $this->getMockBuilder(AbstractFrontend::class)
+        $mockCache = $this->getMockBuilder(PhpFrontend::class)
             ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
             ->disableOriginalConstructor()
             ->getMock();
@@ -1699,7 +1698,7 @@ class ExtensionManagementUtilityTest extends \TYPO3\TestingFramework\Core\Unit\U
      */
     public function createExtTablesCacheEntryWritesCacheEntryWithNoTags()
     {
-        $mockCache = $this->getMockBuilder(AbstractFrontend::class)
+        $mockCache = $this->getMockBuilder(PhpFrontend::class)
             ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
             ->disableOriginalConstructor()
             ->getMock();