日期:2014-05-16  浏览次数:20559 次

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, $expi