[BUGFIX] Remove expired cache_treelist entries during runtime 31/59031/2
authorAlexander Schnitzler <git@alexanderschnitzler.de>
Mon, 26 Nov 2018 09:58:48 +0000 (10:58 +0100)
committerMarkus Klein <markus.klein@typo3.org>
Tue, 4 Dec 2018 19:28:05 +0000 (20:28 +0100)
When \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::getTreeList
checked for an existing cache_treelist entry, the given md5hash and the
expiry timestamp had been compared. As caches do not expire at all by
default, there a very few cases when an entry is actually expired.

However, if a cache entry has been expired, the cache entry hasn't been
removed and therefore the creation of a new cache entry with the same
md5hash identifier resulted in a duplicate entry exception.

To solve this, the affected, expired entry will be removed during runtime.

Releases: master, 8.7
Resolves: #86028
Resolves: #86491
Change-Id: If1a907607db29f7edd0fa77a8bb47a69bdfc0df9
Reviewed-on: https://review.typo3.org/59031
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/frontend/Classes/ContentObject/ContentObjectRenderer.php

index 3060c82..09dd9c0 100644 (file)
@@ -6806,30 +6806,36 @@ class ContentObjectRenderer
                 $tsfe->gr_list
             ];
             $requestHash = md5(serialize($parameters));
-            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
-                ->getQueryBuilderForTable('cache_treelist');
-            $cacheEntry = $queryBuilder->select('treelist')
+
+            $cacheTreeListConnection = GeneralUtility::makeInstance(ConnectionPool::class)
+                ->getConnectionForTable('cache_treelist');
+
+            $queryBuilder = $cacheTreeListConnection->createQueryBuilder();
+            $query = $queryBuilder->select('treelist', 'expires')
                 ->from('cache_treelist')
                 ->where(
                     $queryBuilder->expr()->eq(
                         'md5hash',
                         $queryBuilder->createNamedParameter($requestHash, \PDO::PARAM_STR)
-                    ),
-                    $queryBuilder->expr()->orX(
-                        $queryBuilder->expr()->gt(
-                            'expires',
-                            $queryBuilder->createNamedParameter($GLOBALS['EXEC_TIME'], \PDO::PARAM_INT)
-                        ),
-                        $queryBuilder->expr()->eq('expires', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
                     )
                 )
-                ->setMaxResults(1)
-                ->execute()
-                ->fetch();
+                ->setMaxResults(1);
+
+            $cacheEntry = $query->execute()->fetch();
+            $cacheEntryExists = is_array($cacheEntry);
+            $cacheEntryIsExpired = $cacheEntry['expires'] <= $GLOBALS['EXEC_TIME'];
 
-            if (is_array($cacheEntry)) {
-                // Cache hit
-                return $cacheEntry['treelist'];
+            if ($cacheEntryExists) {
+                if (!$cacheEntryIsExpired) {
+                    // Cache hit
+                    return $cacheEntry['treelist'];
+                }
+                $cacheTreeListConnection->delete(
+                    'cache_treelist',
+                    [
+                        'md5hash' => $requestHash
+                    ]
+                );
             }
             // If Id less than zero it means we should add the real id to list:
             if ($id < 0) {