`
tq02ksu
  • 浏览: 50409 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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;
	}

}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics