From dff7e17fa2c4459450277412c45f044b3690244b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Lorenzo=20Rodr=C3=ADguez?= Date: Thu, 21 Jan 2010 12:11:44 -0430 Subject: [PATCH] Adding atomic increment and decrement methods to cache engines, closes #234 --- cake/libs/cache.php | 86 +++++++++++++++++++ cake/libs/cache/apc.php | 32 +++++++ cake/libs/cache/memcache.php | 38 ++++++++ cake/libs/cache/xcache.php | 33 +++++++ cake/tests/cases/libs/cache/apc.test.php | 47 ++++++++++ cake/tests/cases/libs/cache/memcache.test.php | 47 ++++++++++ cake/tests/cases/libs/cache/xcache.test.php | 47 ++++++++++ 7 files changed, 330 insertions(+) diff --git a/cake/libs/cache.php b/cake/libs/cache.php index bf73cae60..512db1b16 100644 --- a/cake/libs/cache.php +++ b/cake/libs/cache.php @@ -328,6 +328,70 @@ class Cache { return $success; } +/** + * Increment a number under the key and return incremented value + * + * @param string $key Identifier for the data + * @param integer $offset How much to add + * @param string $config Optional - string configuration name + * @return mixed new value, or false if the data doesn't exist, is not integer, or if there was an error fetching it + * @access public + */ + function increment($key, $offset = 1, $config = null) { + $self =& Cache::getInstance(); + + if (!$config) { + $config = $self->__name; + } + $settings = $self->settings($config); + + if (empty($settings)) { + return null; + } + if (!$self->isInitialized($config)) { + return false; + } + $key = $self->_engines[$config]->key($key); + + if (!$key || is_resource($value)) { + return false; + } + $success = $_this->_Engine[$engine]->increment($settings['prefix'] . $key, $offset); + $self->set(); + return $success; + } +/** + * Decrement a number under the key and return decremented value + * + * @param string $key Identifier for the data + * @param integer $offset How much to substract + * @param string $config Optional - string configuration name + * @return mixed new value, or false if the data doesn't exist, is not integer, or if there was an error fetching it + * @access public + */ + function decrement($key, $offset = 1, $config = null) { + $self =& Cache::getInstance(); + + if (!$config) { + $config = $self->__name; + } + $settings = $self->settings($config); + + if (empty($settings)) { + return null; + } + if (!$self->isInitialized($config)) { + return false; + } + $key = $self->_engines[$config]->key($key); + + if (!$key || is_resource($value)) { + return false; + } + $success = $_this->_Engine[$engine]->increment($settings['prefix'] . $key, $offset); + $self->set(); + return $success; + } /** * Delete a key from the cache * @@ -498,6 +562,28 @@ class CacheEngine { trigger_error(sprintf(__('Method read() not implemented in %s', true), get_class($this)), E_USER_ERROR); } +/** + * Increment a number under the key and return incremented value + * + * @param string $key Identifier for the data + * @param integer $offset How much to add + * @return New incremented value, false otherwise + * @access public + */ + function increment($key, $offset = 1) { + trigger_error(sprintf(__('Method increment() not implemented in %s', true), get_class($this)), E_USER_ERROR); + } +/** + * Decrement a number under the key and return decremented value + * + * @param string $key Identifier for the data + * @param integer $value How much to substract + * @return New incremented value, false otherwise + * @access public + */ + function decrement($key, $offset = 1) { + trigger_error(sprintf(__('Method decrement() not implemented in %s', true), get_class($this)), E_USER_ERROR); + } /** * Delete a key from the cache * diff --git a/cake/libs/cache/apc.php b/cake/libs/cache/apc.php index acf438f32..e5b629544 100644 --- a/cake/libs/cache/apc.php +++ b/cake/libs/cache/apc.php @@ -74,6 +74,38 @@ class ApcEngine extends CacheEngine { return apc_fetch($key); } +/** + * Increments the value of an integer cached key + * + * @param string $key Identifier for the data + * @param integer $offset How much to increment + * @param integer $duration How long to cache the data, in seconds + * @return New incremented value, false otherwise + * @access public + */ + function increment($key, $offset = 1) { + if (!is_integer($offset) || $offset < 0) { + return false; + } + return apc_inc($key, $offset); + } + +/** + * Decrements the value of an integer cached key + * + * @param string $key Identifier for the data + * @param integer $offset How much to substract + * @param integer $duration How long to cache the data, in seconds + * @return New decremented value, false otherwise + * @access public + */ + function decrement($key, $offset = 1) { + if (!is_integer($offset) || $offset < 0) { + return false; + } + return apc_dec($key, $offset); + } + /** * Delete a key from the cache * diff --git a/cake/libs/cache/memcache.php b/cake/libs/cache/memcache.php index 485270339..d85590355 100644 --- a/cake/libs/cache/memcache.php +++ b/cake/libs/cache/memcache.php @@ -125,6 +125,44 @@ class MemcacheEngine extends CacheEngine { return $this->__Memcache->get($key); } +/** + * Increments the value of an integer cached key + * + * @param string $key Identifier for the data + * @param integer $offset How much to increment + * @param integer $duration How long to cache the data, in seconds + * @return New incremented value, false otherwise + * @access public + */ + function increment($key, $offset = 1) { + if ($this->settings['compress']) { + trigger_error(sprintf(__('Method increment() not implemented for compressed cache in %s', true), get_class($this)), E_USER_ERROR); + } + if (!is_integer($offset) || $offset < 0) { + return false; + } + return $this->__Memcache->increment($key, $offset); + } + +/** + * Decrements the value of an integer cached key + * + * @param string $key Identifier for the data + * @param integer $offset How much to substract + * @param integer $duration How long to cache the data, in seconds + * @return New decremented value, false otherwise + * @access public + */ + function decrement($key, $offset = 1) { + if ($this->settings['compress']) { + trigger_error(sprintf(__('Method decrement() not implemented for compressed cache in %s', true), get_class($this)), E_USER_ERROR); + } + if (!is_integer($offset) || $offset < 0) { + return false; + } + return $this->__Memcache->decrement($key, $offset); + } + /** * Delete a key from the cache * diff --git a/cake/libs/cache/xcache.php b/cake/libs/cache/xcache.php index ecdc08260..9d6fdb255 100644 --- a/cake/libs/cache/xcache.php +++ b/cake/libs/cache/xcache.php @@ -90,6 +90,39 @@ class XcacheEngine extends CacheEngine { return false; } +/** + * Increments the value of an integer cached key + * If the cache key is not an integer it will be treated as 0 + * + * @param string $key Identifier for the data + * @param integer $offset How much to increment + * @param integer $duration How long to cache the data, in seconds + * @return New incremented value, false otherwise + * @access public + */ + function increment($key, $offset = 1) { + if (!is_integer($offset) || $offset < 0) { + return false; + } + return xcache_inc($key, $offset); + } + +/** + * Decrements the value of an integer cached key. + * If the cache key is not an integer it will be treated as 0 + * + * @param string $key Identifier for the data + * @param integer $offset How much to substract + * @param integer $duration How long to cache the data, in seconds + * @return New decremented value, false otherwise + * @access public + */ + function decrement($key, $offset = 1) { + if (!is_integer($offset) || $offset < 0) { + return false; + } + return xcache_dec($key, $offset); + } /** * Delete a key from the cache * diff --git a/cake/tests/cases/libs/cache/apc.test.php b/cake/tests/cases/libs/cache/apc.test.php index 10f9593dd..7323e8385 100644 --- a/cake/tests/cases/libs/cache/apc.test.php +++ b/cake/tests/cases/libs/cache/apc.test.php @@ -140,5 +140,52 @@ class ApcEngineTest extends UnitTestCase { $result = Cache::delete('delete_test'); $this->assertTrue($result); } + +/** + * testDecrement method + * + * @access public + * @return void + */ + public function testDecrement() { + $result = Cache::write('test_decrement', 5); + $this->assertTrue($result); + + $result = Cache::decrement('test_decrement'); + $this->assertEqual(4, $result); + + $result = Cache::read('test_decrement'); + $this->assertEqual(4, $result); + + $result = Cache::decrement('test_decrement', 2); + $this->assertEqual(2, $result); + + $result = Cache::read('test_decrement'); + $this->assertEqual(2, $result); + + } + +/** + * testIncrement method + * + * @access public + * @return void + */ + public function testIncrement() { + $result = Cache::write('test_increment', 5); + $this->assertTrue($result); + + $result = Cache::increment('test_increment'); + $this->assertEqual(5, $result); + + $result = Cache::read('test_increment'); + $this->assertEqual(5, $result); + + $result = Cache::increment('test_increment', 2); + $this->assertEqual(7, $result); + + $result = Cache::read('test_increment'); + $this->assertEqual(7, $result); + } } ?> \ No newline at end of file diff --git a/cake/tests/cases/libs/cache/memcache.test.php b/cake/tests/cases/libs/cache/memcache.test.php index 99cc68ca1..470f43ebb 100644 --- a/cake/tests/cases/libs/cache/memcache.test.php +++ b/cake/tests/cases/libs/cache/memcache.test.php @@ -220,5 +220,52 @@ class MemcacheEngineTest extends CakeTestCase { $result = Cache::delete('delete_test'); $this->assertTrue($result); } + +/** + * testDecrement method + * + * @access public + * @return void + */ + public function testDecrement() { + $result = Cache::write('test_decrement', 5); + $this->assertTrue($result); + + $result = Cache::decrement('test_decrement'); + $this->assertEqual(4, $result); + + $result = Cache::read('test_decrement'); + $this->assertEqual(4, $result); + + $result = Cache::decrement('test_decrement', 2); + $this->assertEqual(2, $result); + + $result = Cache::read('test_decrement'); + $this->assertEqual(2, $result); + + } + +/** + * testIncrement method + * + * @access public + * @return void + */ + public function testIncrement() { + $result = Cache::write('test_increment', 5); + $this->assertTrue($result); + + $result = Cache::increment('test_increment'); + $this->assertEqual(5, $result); + + $result = Cache::read('test_increment'); + $this->assertEqual(5, $result); + + $result = Cache::increment('test_increment', 2); + $this->assertEqual(7, $result); + + $result = Cache::read('test_increment'); + $this->assertEqual(7, $result); + } } ?> \ No newline at end of file diff --git a/cake/tests/cases/libs/cache/xcache.test.php b/cake/tests/cases/libs/cache/xcache.test.php index f78955cb0..0d1e7c4fd 100644 --- a/cake/tests/cases/libs/cache/xcache.test.php +++ b/cake/tests/cases/libs/cache/xcache.test.php @@ -173,5 +173,52 @@ class XcacheEngineTest extends UnitTestCase { $result = Cache::clear(); $this->assertTrue($result); } + +/** + * testDecrement method + * + * @access public + * @return void + */ + public function testDecrement() { + $result = Cache::write('test_decrement', 5); + $this->assertTrue($result); + + $result = Cache::decrement('test_decrement'); + $this->assertEqual(4, $result); + + $result = Cache::read('test_decrement'); + $this->assertEqual(4, $result); + + $result = Cache::decrement('test_decrement', 2); + $this->assertEqual(2, $result); + + $result = Cache::read('test_decrement'); + $this->assertEqual(2, $result); + + } + +/** + * testIncrement method + * + * @access public + * @return void + */ + public function testIncrement() { + $result = Cache::write('test_increment', 5); + $this->assertTrue($result); + + $result = Cache::increment('test_increment'); + $this->assertEqual(5, $result); + + $result = Cache::read('test_increment'); + $this->assertEqual(5, $result); + + $result = Cache::increment('test_increment', 2); + $this->assertEqual(7, $result); + + $result = Cache::read('test_increment'); + $this->assertEqual(7, $result); + } } ?> \ No newline at end of file