YII 框架 中 基于SAE的KV-DB的缓存实现.
支持超时, 写入时加锁.
锁冲突时旋转等待.
<?php/** * Cache implementation for saekvdb. * Pay attention to the limit of the sae kv db, * max key length : 200, * max value length : 4M. * * @author tq02ksu */class SAEKVCache extends CCache {/** * $kv holds the kv db connection * @var type */public $kv;/** * Key suffix of lock entry. * @var string */public $suffix_lock = 'l';/** * Key suffix of content entry. * @var string */public $suffix_content = 'c';/** * Key of expiration. * @var string */public $field_expiration = 'e';/** * Key of content. * @var string */public $field_content = 'c';public $max_spin_wait = 3000;public function gen_content_key($key) {$suffix = $this->suffix_content;return $key . $suffix;}public function gen_lock_key($key) {$suffix = $this->suffix_lock;return $key . $suffix;}/** * Initializes the application component. * This method overrides the parent implementation by setting default cache key prefix. */public function init() {parent::init();if ($this->kv === null) {$this->kv = new SaeKV();$this->kv->init();}}/** * Retrieves a value from cache with a specified key. * This method should be implemented by child classes to retrieve the data * from specific cache storage. The uniqueness and dependency are handled * in {@link get()} already. So only the implementation of data retrieval * is needed. * @param string $key a unique key identifying the cached value * @return string the value stored in cache, false if the value is not in the cache or expired. * @throws CException if this method is not overridden by child classes */protected function getValue($key) {$key_content = $this->gen_content_key($key);$field_expiration = $this->field_expiration;$field_content = $this->field_content;$val = $this->kv->get($key_content);// deal as a failure:if ($val === false) {return false;}$val = unserialize($val);if (array_key_exists($field_expiration, $val) && $val[$field_expiration] < time()) {// expired$this->deleteValue($key);return false;} else {// cache hint:return $val[$field_content];}}/** * Stores a value identified by a key in cache. * This method should be implemented by child classes to store the data * in specific cache storage. The uniqueness and dependency are handled * in {@link set()} already. So only the implementation of data storage * is needed. * * @param string $key the key identifying the value to be cached * @param string $value the value to be cached * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. * @return boolean true if the value is successfully stored into cache, false otherwise * @throws CException if this method is not overridden by child classes */protected function setValue($key, $value, $expire) {return $this->addOrSetValueByParam($key, $value, $expire, 'set');}/** * Stores a value identified by a key into cache if the cache does not contain this key. * This method should be implemented by child classes to store the data * in specific cache storage. The uniqueness and dependency are handled * in {@link add()} already. So only the implementation of data storage * is needed. * * @param string $key the key identifying the value to be cached * @param string $value the value to be cached * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. * @return boolean true if the value is successfully stored into cache, false otherwise * @throws CException if this method is not overridden by child classes */protected function addValue($key, $value, $expire) {return $this->addOrSetValueByParam($key, $value, $expire, 'add');}protected function addOrSetValueByParam($key, $value, $expire, $method) {$field_content = $this->field_content;$field_expiration = $this->field_expiration;$val = array($field_content => $value,);if ($expire > 0) {$val[$field_expiration] = time() + $expire;}$val = serialize($val);$key_content = $this->gen_content_key($key);$key_lock = $this->gen_lock_key($key);for ($i = 0; $i < $this->max_spin_wait; $i++) {if ($this->kv->add($key_lock, '')) {$success = $this->kv->$method($key_content, $val);$this->kv->delete($key_lock);return $success;}}return false;}/** * Deletes a value with the specified key from cache * This method should be implemented by child classes to delete the data from actual cache storage. * @param string $key the key of the value to be deleted * @return boolean if no error happens during deletion * @throws CException if this method is not overridden by child classes */protected function deleteValue($key) {$key_content = $this->gen_content_key($key);$key_lock = $this->gen_lock_key($key);for ($i = 0; $i < $this->max_spin_wait; $i++) {if ($this->kv->add($key_lock, '')) {$this->kv->delete($key_content);$this->kv->delete($key_lock);return true;}}return false;}/** * Deletes all values from cache. * Child classes may implement this method to realize the flush operation. * @return boolean whether the flush operation was successful. * @throws CException if this method is not overridden by child classes * @since 1.1.5 */protected function flushValues() {$success = true;$step = 100;for ($ret = $this->kv->pkrget('', $step); $ret !== false; $ret = $this->kv->pkrget('', $step)) {array_walk($ret, function( $value, $key ) use ($kv) { $success = $success && $kv->delete($key) ? true : false;});}return true;}}