Details
Description
Since upgrading to Doctrine 1.2 my application has begun to get increasingly slower as hours elapse. I've pinpointed the cause to the new doctrine_cache_keys feature.
I've found at least three issues with this new method.
First
The key cache does not track enforce unique entries, thus multiple entries can be in the cache. See:
protected function _saveKey($key)
{
$keys = $this->fetch($this->_cacheKeyIndexKey);
$keys[] = $key;
return $this->save($this->_cacheKeyIndexKey, $keys, null, false);
}
public function _deleteKey($key)
{
$keys = $this->fetch($this->_cacheKeyIndexKey);
$key = array_search($key, $keys);
if ($key !== false) {
unset($keys[$key]);
return $this->save($this->_cacheKeyIndexKey, $keys, null, false);
}
return false;
}
Second
The doctrine_cache_key is being updated on every cache save or delete. With any caching strategy (APC, Memcached, Xcache) cache writes for the same key are (naturally) serialized. This leads to the "timebomb" situation described here: http://t3.dotgnu.info/blog/php/user-cache-timebomb.html
The problem is exarcerbated by the infinitely increasing size of the doctrine_cache_key array noted above. Depending on the caching engine, the lock time increases as well (APC & XCache free the previous entry inside the lock). This causes the application to spiral out of control, even with relatively trivial loads.
Personally, I don't think the "benefit" of having prefix/regex deletes is worth having this. Jon, you suggested having it disabled by default, but even with it enabled, this problem is reintroduced when someone decides to use it.
Third
For most (maybe all?) cache engines the doctrine_cache_key seems entirely unnecessary.
- APC
- apc_cache_info('user') returns the list of cache entries
- Memcached
- $memcache->getExtendedStats('cachedump', $slabId) can return the list of cache keys
- XCache
- According to the API docs xcache_list() behaves similar to apc_cache_info()
- DB
- a simple query can get this
- Array
- array_keys() ?
Summary
As this is currently broken for production use I intend to immediately fix both the first and second items above by preventing duplicate entries and disabling the doctrine_cache_keys behavior by default.
With more input/discussion I think the long term solution is to use the tools provided by the engines to get a list of keys, rather than maintain a list. I'd be willing to develop this as long as it is approved.
Issue Links
- relates to
-
DC-390
doctrine_cache_keys bigger than 1mb
-
I fixed the first issue in the following revision:
http://trac.doctrine-project.org/changeset/7070
cache_keys entries are now stored as the key of an array. This allows for simple uniqueness enforcement, as well as being significantly faster for deletion: array_key_exists is O(log n), array_search is O( n ).