[BUGFIX] Make ReferenceIndex caching optional 84/53384/5
authorBenni Mack <benni@typo3.org>
Mon, 3 Jul 2017 13:21:03 +0000 (15:21 +0200)
committerMarkus Klein <markus.klein@typo3.org>
Tue, 17 Oct 2017 21:35:20 +0000 (23:35 +0200)
The runtime caches used in the ReferenceIndex class
added in TYPO3 8.7.2 should not be added by default
but included on a per-runtime basis when extensions
would use the ReferenceIndex. Otherwise this issue
might lead to side-effects.

For master/9.0 the caches are enabled by default.

Relates: #78634
Resolves: #81771
Releases: master, 8.7
Change-Id: If7ca173d93c05658bce5f57c38842555a439d2ea
Reviewed-on: https://review.typo3.org/53384
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein <markus.klein@typo3.org>
typo3/sysext/backend/Classes/Command/ReferenceIndexUpdateCommand.php
typo3/sysext/core/Classes/DataHandling/DataHandler.php
typo3/sysext/core/Classes/Database/ReferenceIndex.php
typo3/sysext/core/Classes/Database/RelationHandler.php
typo3/sysext/core/Classes/Resource/Index/FileIndexRepository.php
typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php
typo3/sysext/impexp/Classes/Export.php
typo3/sysext/lowlevel/Classes/Controller/DatabaseIntegrityController.php

index 31c6c8a..b516e5e 100644 (file)
@@ -56,6 +56,7 @@ class ReferenceIndexUpdateCommand extends Command
 
         /** @var ReferenceIndex $referenceIndex */
         $referenceIndex = GeneralUtility::makeInstance(ReferenceIndex::class);
+        $referenceIndex->enableRuntimeCache();
         $referenceIndex->updateIndex($isTestOnly, $isSilent);
     }
 }
index 7e8844c..ff269b5 100644 (file)
@@ -4145,6 +4145,7 @@ class DataHandler implements LoggerAwareInterface
                     if (@is_file($copyDestName)) {
                         /** @var ReferenceIndex $sysRefObj */
                         $sysRefObj = GeneralUtility::makeInstance(ReferenceIndex::class);
+                        $sysRefObj->enableRuntimeCache();
                         $error = $sysRefObj->setReferenceValue($rteFileRecord['hash'], PathUtility::stripPathSitePrefix($copyDestName), false, true);
                         if ($error) {
                             $this->newlog(ReferenceIndex::class . '::setReferenceValue(): ' . $error, 1);
@@ -5256,6 +5257,7 @@ class DataHandler implements LoggerAwareInterface
         // Use reference index object to find files in fields:
         /** @var ReferenceIndex $refIndexObj */
         $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
+        $refIndexObj->enableRuntimeCache();
         $files = $refIndexObj->getRelations_procFiles($dataValue, $dsArr['TCEforms']['config'], $PA['uid']);
         // Traverse files and delete them if the field is a regular file field (and not a file_reference field)
         if (is_array($files) && $dsArr['TCEforms']['config']['internal_type'] === 'file') {
@@ -7260,6 +7262,7 @@ class DataHandler implements LoggerAwareInterface
         if (BackendUtility::isTableWorkspaceEnabled($table)) {
             $refIndexObj->setWorkspaceId($this->BE_USER->workspace);
         }
+        $refIndexObj->enableRuntimeCache();
         $refIndexObj->updateRefIndexTable($table, $id);
     }
 
index 01b3c0d..5720305 100644 (file)
@@ -151,6 +151,12 @@ class ReferenceIndex implements LoggerAwareInterface
     protected $runtimeCache = null;
 
     /**
+     * Enables $runtimeCache and $recordCache
+     * @var bool
+     */
+    protected $useRuntimeCache = false;
+
+    /**
      * Constructor
      */
     public function __construct()
@@ -216,7 +222,7 @@ class ReferenceIndex implements LoggerAwareInterface
 
         // Fetch tableRelationFields and save them in cache if not there yet
         $cacheId = static::$cachePrefixTableRelationFields . $tableName;
-        if (!$this->runtimeCache->has($cacheId)) {
+        if (!$this->useRuntimeCache || !$this->runtimeCache->has($cacheId)) {
             $tableRelationFields = $this->fetchTableRelationFields($tableName);
             $this->runtimeCache->set($cacheId, $tableRelationFields);
         } else {
@@ -1477,6 +1483,10 @@ class ReferenceIndex implements LoggerAwareInterface
      * - Relations may change during indexing, which is why only the origin record is cached and all relations are re-process even when repeating
      *   indexing of the same origin record
      *
+     * Please note that the cache is disabled by default but can be enabled using $this->enableRuntimeCaches()
+     * due to possible side-effects while handling references that were changed during one single
+     * request.
+     *
      * @param string $tableName
      * @param int $uid
      * @return array|false
@@ -1484,13 +1494,15 @@ class ReferenceIndex implements LoggerAwareInterface
     protected function getRecordRawCached(string $tableName, int $uid)
     {
         $recordCacheId = $tableName . ':' . $uid;
-        if (!isset($this->recordCache[$recordCacheId])) {
+        if (!$this->useRuntimeCache || !isset($this->recordCache[$recordCacheId])) {
 
             // Fetch fields of the table which might contain relations
             $cacheId = static::$cachePrefixTableRelationFields . $tableName;
-            if (!$this->runtimeCache->has($cacheId)) {
+            if (!$this->useRuntimeCache || !$this->runtimeCache->has($cacheId)) {
                 $tableRelationFields = $this->fetchTableRelationFields($tableName);
-                $this->runtimeCache->set($cacheId, $tableRelationFields);
+                if ($this->useRuntimeCache) {
+                    $this->runtimeCache->set($cacheId, $tableRelationFields);
+                }
             } else {
                 $tableRelationFields = $this->runtimeCache->get($cacheId);
             }
@@ -1580,6 +1592,24 @@ class ReferenceIndex implements LoggerAwareInterface
     }
 
     /**
+     * Enables the runtime-based caches
+     * Could lead to side effects, depending if the reference index instance is run multiple times
+     * while records would be changed.
+     */
+    public function enableRuntimeCache()
+    {
+        $this->useRuntimeCache = true;
+    }
+
+    /**
+     * Disables the runtime-based cache
+     */
+    public function disableRuntimeCache()
+    {
+        $this->useRuntimeCache = false;
+    }
+
+    /**
      * Returns the current BE user.
      *
      * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
index 07e7379..b507456 100644 (file)
@@ -1312,6 +1312,7 @@ class RelationHandler
             if (BackendUtility::isTableWorkspaceEnabled($table)) {
                 $refIndexObj->setWorkspaceId($this->getWorkspaceId());
             }
+            $refIndexObj->enableRuntimeCache();
             $statisticsArray = $refIndexObj->updateRefIndexTable($table, $id);
         }
         return $statisticsArray;
index 1f44acc..d7ffd22 100644 (file)
@@ -553,6 +553,7 @@ class FileIndexRepository implements SingletonInterface
     {
         /** @var $refIndexObj ReferenceIndex */
         $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
+        $refIndexObj->enableRuntimeCache();
         $refIndexObj->updateRefIndexTable($this->table, $id);
     }
 
index cd9a393..63ec1c4 100644 (file)
@@ -148,6 +148,7 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface
     {
         $this->configurationManager = $configurationManager;
         $this->referenceIndex = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ReferenceIndex::class);
+        $this->referenceIndex->enableRuntimeCache();
         $this->aggregateRootObjects = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
         $this->deletedEntities = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
         $this->changedEntities = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
index cdbf8ee..d1b837c 100644 (file)
@@ -324,6 +324,7 @@ class Export extends ImportExport
                         $this->dat['header']['pid_lookup'][$row['pid']][$table][$row['uid']] = 1;
                         // Initialize reference index object:
                         $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
+                        $refIndexObj->enableRuntimeCache();
                         // Yes to workspace overlays for exporting....
                         $refIndexObj->WSOL = true;
                         $relations = $refIndexObj->getRelations($table, $row);
index 6e8a8df..d8934a9 100644 (file)
@@ -318,6 +318,7 @@ class DatabaseIntegrityController
             $testOnly = (bool)GeneralUtility::_GP('_check');
             // Call the functionality
             $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
+            $refIndexObj->enableRuntimeCache();
             list(, $bodyContent) = $refIndexObj->updateIndex($testOnly);
             $this->view->assign('content', str_replace('##LF##', '<br />', $bodyContent));
         }