Issues

ZF-11640: SQLite backend fails using ":memory:" database

Description

With default "automatic_cleaning_factor" (10, from Core) and "automatic_vacuum_factor" (10, from Backend_Sqlite), the SQLite cache backend, using in-memory databases (":memory:") will fail 1 time out of 100 (100 = 10 * 10, 1%) when attempting a "clean()" operation.


$failures = 0; $attempts = 100000;
foreach (range(1, $attempts) as $i) {
    $cache = Zend_Cache::factory(
        'Core', 'Sqlite',
        array(),
        array('cache_db_complete_path' => ':memory:') // in-memory database
    );
    $success = $cache->save('cache_data', $id = 'cache_id');
    $failures += ($success ? 0 : 1);
}
printf('Failures: %d (%.1f %%)', $failures, ($failures / $attempts) * 100);
(100000 attempts)
Failures: 1008 (1.0 %)

The problem comes from Sqlite::_automaticVacuum(), where a call to "sqlite_close()" will remove all tables from the database, but the value of "$this->_structureChecked", set by "$this->_checkAndBuildStructure()", in "clean()" (previous to the "automaticVacuum" call), *will still be "true"*. So the SQLite backend will re-open a new connection, but the *tables will not be created again*. Thus the occasional "table not found" errors while "_query()"ing, 1 time out of 100.

Disabling automatic vacuum "patches" the immediate problem, but a real fix would look a little bit more like this :

diff --git a/Zend/Cache/Backend/Sqlite.php b/Zend/Cache/Backend/Sqlite.php
index 5b964a1..427f13d 100644
--- a/Zend/Cache/Backend/Sqlite.php
+++ b/Zend/Cache/Backend/Sqlite.php
@@ -68,7 +68,7 @@ class Zend_Cache_Backend_Sqlite extends Zend_Cache_Backend implements Zend_Cache
     private $_db = null;
 
     /**
-     * Boolean to store if the structure has benn checked or not
+     * Boolean to store if the structure has been checked or not
      *
      * @var boolean $_structureChecked
      */
@@ -531,6 +531,7 @@ class Zend_Cache_Backend_Sqlite extends Zend_Cache_Backend implements Zend_Cache
             if ($rand == 1) {
                 $this->_query('VACUUM');
                 @sqlite_close($this->_getConnection());
+                $this->_structureChecked = false;
             }
         }
     }

(Sorry about the in-line patch, could not figure out how to attach it and the Contributors Guide was down.)

Comments

There is no need to close db connection after VACUUM

fixed in r24347 (trunk) and r24348 (1.11 branch)