[BUGFIX] Mitigate race condition on cache flush 94/28594/2
authorHelmut Hummel <helmut.hummel@typo3.org>
Fri, 21 Mar 2014 10:05:09 +0000 (11:05 +0100)
committerChristian Kuhn <lolli@schwarzbu.ch>
Fri, 21 Mar 2014 15:22:44 +0000 (16:22 +0100)
When file caches are flushed, the cache directory
is also deleted.

Now when a second request comes in and creates
the caches it happens that the cache directory of
a given cache is still there for this cache when
calling setCache in the SimpleFileBackend,
but is deleted by the first request afterwards.

Now the cache directory for the second request
does not exist and setting cache entries will fail.

Mitigate this by immediately recreating
the cache directory.

Resolves: #57136
Releases: 6.2
Change-Id: I3c4c5c63c6c754447549285d9718798272f9e585
Reviewed-on: https://review.typo3.org/28594
Reviewed-by: Ernesto Baschny
Reviewed-by: Thomas Maroschik
Reviewed-by: Pascal Dürsteler
Reviewed-by: Markus Klein
Tested-by: Markus Klein
Reviewed-by: Christian Kuhn
Tested-by: Christian Kuhn
typo3/sysext/core/Classes/Cache/Backend/SimpleFileBackend.php
typo3/sysext/core/Classes/Utility/GeneralUtility.php

index 9467a66..cee2d31 100644 (file)
@@ -312,8 +312,7 @@ class SimpleFileBackend extends \TYPO3\CMS\Core\Cache\Backend\AbstractBackend im
         * @api
         */
        public function flush() {
-               \TYPO3\CMS\Core\Utility\GeneralUtility::flushDirectory($this->cacheDirectory);
-               $this->createFinalCacheDirectory($this->cacheDirectory);
+               \TYPO3\CMS\Core\Utility\GeneralUtility::flushDirectory($this->cacheDirectory, TRUE);
        }
 
        /**
index 922b4d1..2285f3a 100644 (file)
@@ -2851,14 +2851,18 @@ Connection: close
         * to prevent race conditions on concurrent processes accessing the same directory.
         *
         * @param string $directory The directory to be renamed and flushed
+        * @param bool $keepOriginalDirectory Whether to only empty the directory and not remove it
         * @return boolean Whether the action was successful
         */
-       static public function flushDirectory($directory) {
+       static public function flushDirectory($directory, $keepOriginalDirectory = FALSE) {
                $result = FALSE;
 
                if (is_dir($directory)) {
                        $temporaryDirectory = rtrim($directory, '/') . '.' . uniqid('remove') . '/';
                        if (rename($directory, $temporaryDirectory)) {
+                               if ($keepOriginalDirectory) {
+                                       self::mkdir($directory);
+                               }
                                clearstatcache();
                                $result = self::rmdir($temporaryDirectory, TRUE);
                        }