Jelajahi Sumber

Cache files should be properly cleaned, even if their ids will put them after 'internal-metadatas' file

Ondřej Machulda 11 tahun lalu
induk
melakukan
1a2d1cd4bb
2 mengubah file dengan 59 tambahan dan 9 penghapusan
  1. 15 9
      library/Zend/Cache/Backend/File.php
  2. 44 0
      tests/Zend/Cache/FileBackendTest.php

+ 15 - 9
library/Zend/Cache/Backend/File.php

@@ -675,14 +675,17 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
             // On some systems it is impossible to distinguish between empty match and an error.
             return true;
         }
+        $metadataFiles = array();
         foreach ($glob as $file)  {
             if (is_file($file)) {
                 $fileName = basename($file);
                 if ($this->_isMetadatasFile($fileName)) {
-                    // in CLEANING_MODE_ALL, we drop anything, even remainings old metadatas files
-                    if ($mode != Zend_Cache::CLEANING_MODE_ALL) {
-                        continue;
+                    // In CLEANING_MODE_ALL, we drop anything, even remainings old metadatas files.
+                    // To do that, we need to save the list of the metadata files first.
+                    if ($mode == Zend_Cache::CLEANING_MODE_ALL) {
+                        $metadataFiles[] = $file;
                     }
+                    continue;
                 }
                 $id = $this->_fileNameToId($fileName);
                 $metadatas = $this->_getMetadatas($id);
@@ -691,12 +694,7 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
                 }
                 switch ($mode) {
                     case Zend_Cache::CLEANING_MODE_ALL:
-                        $res = $this->remove($id);
-                        if (!$res) {
-                            // in this case only, we accept a problem with the metadatas file drop
-                            $res = $this->_remove($file);
-                        }
-                        $result = $result && $res;
+                        $result = $result && $this->remove($id);
                         break;
                     case Zend_Cache::CLEANING_MODE_OLD:
                         if (time() > $metadatas['expire']) {
@@ -753,6 +751,14 @@ class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_B
                 }
             }
         }
+
+        // cycle through metadataFiles and delete orphaned ones
+        foreach ($metadataFiles as $file) {
+            if (file_exists($file)) {
+                $result = $this->_remove($file) && $result;
+            }
+        }
+
         return $result;
     }
 

+ 44 - 0
tests/Zend/Cache/FileBackendTest.php

@@ -142,7 +142,18 @@ class Zend_Cache_FileBackendTest extends Zend_Cache_CommonExtendedBackendTest {
 
     public function testCleanModeAllWithHashedDirectoryStructure()
     {
+        // clean files created in setUp (without hashed directory level) first
+        $this->assertTrue($this->_instance->clean('all'));
+
+        // set the hashed directory mode
         $this->_instance->setOption('hashed_directory_level', 2);
+
+        // save the data again
+        $this->_instance->save('bar : data to cache', 'bar');
+        $this->_instance->save('bar2 : data to cache', 'bar2');
+        $this->_instance->save('bar3 : data to cache', 'bar3');
+
+        // now delete them
         $this->assertTrue($this->_instance->clean('all'));
         $this->assertFalse($this->_instance->test('bar'));
         $this->assertFalse($this->_instance->test('bar2'));
@@ -155,4 +166,37 @@ class Zend_Cache_FileBackendTest extends Zend_Cache_CommonExtendedBackendTest {
         $this->assertFalse($res);
     }
 
+    public function testShouldProperlyCleanCacheNoMatterTheCacheId()
+    {
+        // the 'zzz' and 'ďťň' keys will be sorted after internal-metadatas file
+        $keys = array(
+            '9230de5449e0c818ed4804587ed422d5',
+            'zzz',
+            'Zend_LocaleC_cs_CZ_date_',
+            'ďťň'
+        );
+
+        foreach ($keys as $key) {
+            $this->_instance->save('data to cache', $key);
+        }
+
+        $this->assertTrue($this->_instance->clean(Zend_Cache::CLEANING_MODE_ALL));
+    }
+
+    /**
+     * The CLEANING_MODE_ALL should delete also old orphaned metadatafiles
+     */
+    public function testShouldDeleteOldMetadataFiles()
+    {
+        // simulate orphaned metadata file
+        $fn = $this->_cache_dir
+            . DIRECTORY_SEPARATOR
+            . 'zend_cache---internal-metadatas---7a38619e110f03740970cbcd5310f33f';
+        $file = fopen($fn, 'a+');
+        fclose($file);
+
+        $this->assertTrue(file_exists($fn));
+        $this->assertTrue($this->_instance->clean(Zend_Cache::CLEANING_MODE_ALL));
+        $this->assertFalse(file_exists($fn));
+    }
 }