X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=lib%2Fcache.php;h=bf0603c62d0ce15c1f1401351668a7d7b48946b6;hb=1fdc72f5956f00c736f7761aead4abd8da192eda;hp=d1ba65dab8b1506002cf3d6066342f2832cb1133;hpb=c5d23e27a6a34e02090ebcece60dfa5b7f814488;p=quix0rs-gnu-social.git diff --git a/lib/cache.php b/lib/cache.php index d1ba65dab8..bf0603c62d 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -30,15 +30,31 @@ /** * Interface for caching * - * An abstract interface for caching. + * An abstract interface for caching. Because we originally used the + * Memcache plugin directly, the interface uses a small subset of the + * Memcache interface. * + * @category Cache + * @package StatusNet + * @author Evan Prodromou + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ */ - class Cache { - var $_items = array(); + var $_items = array(); static $_inst = null; + const COMPRESSED = 1; + + /** + * Singleton constructor + * + * Use this to get the singleton instance of Cache. + * + * @return Cache cache object + */ static function instance() { if (is_null(self::$_inst)) { @@ -48,9 +64,20 @@ class Cache return self::$_inst; } + /** + * Create a cache key from input text + * + * Builds a cache key from input text. Helps to namespace + * the cache area (if shared with other applications or sites) + * and prevent conflicts. + * + * @param string $extra the real part of the key + * + * @return string full key + */ static function key($extra) { - $base_key = common_config('memcached', 'base'); + $base_key = common_config('cache', 'base'); if (empty($base_key)) { $base_key = common_keyize(common_config('site', 'name')); @@ -59,6 +86,64 @@ class Cache return 'statusnet:' . $base_key . ':' . $extra; } + /** + * Create a cache key for data dependent on code + * + * For cache elements that are dependent on changes in code, this creates + * a more-or-less fingerprint of the current running code and adds it to + * the cache key. In the case of an upgrade of core, or addition or + * removal of plugins, a new unique fingerprint is generated and used. + * + * There can still be problems with a) differences in versions of the + * plugins and b) people running code between official versions. This is + * usually a problem only for experienced users like developers, who know + * how to clear their cache. + * + * For sites that run code between versions (like the status.net cloud), + * there's an additional build number configuration setting. + * + * @param string $extra the real part of the key + * + * @return string full key + */ + + static function codeKey($extra) + { + static $prefix = null; + + if (empty($prefix)) { + + $plugins = StatusNet::getActivePlugins(); + $names = array(); + + foreach ($plugins as $plugin) { + $names[] = $plugin[0]; + } + + $names = array_unique($names); + asort($names); + + // Unique enough. + + $uniq = crc32(implode(',', $names)); + + $build = common_config('site', 'build'); + + $prefix = STATUSNET_VERSION.':'.$build.':'.$uniq; + } + + return Cache::key($prefix.':'.$extra); + } + + /** + * Make a string suitable for use as a key + * + * Useful for turning primary keys of tables into cache keys. + * + * @param string $str string to turn into a key + * + * @return string keyized string + */ static function keyize($str) { $str = strtolower($str); @@ -66,16 +151,23 @@ class Cache return $str; } + /** + * Get a value associated with a key + * + * The value should have been set previously. + * + * @param string $key Lookup key + * + * @return string retrieved value or null if unfound + */ function get($key) { - $value = null; - - if (!Event::handle('StartCacheGet', array(&$key, &$value))) { - if (array_key_exists($_items, $key)) { - common_log(LOG_INFO, 'Cache HIT for key ' . $key); - $value = $_items[$key]; - } else { - common_log(LOG_INFO, 'Cache MISS for key ' . $key); + $value = false; + + common_perf_counter('Cache::get', $key); + if (Event::handle('StartCacheGet', array(&$key, &$value))) { + if (array_key_exists($key, $this->_items)) { + $value = unserialize($this->_items[$key]); } Event::handle('EndCacheGet', array($key, &$value)); } @@ -83,31 +175,100 @@ class Cache return $value; } + /** + * Set the value associated with a key + * + * @param string $key The key to use for lookups + * @param string $value The value to store + * @param integer $flag Flags to use, may include Cache::COMPRESSED + * @param integer $expiry Expiry value, mostly ignored + * + * @return boolean success flag + */ function set($key, $value, $flag=null, $expiry=null) { $success = false; - if (!Event::handle('StartCacheSet', array(&$key, &$value, &$flag, &$expiry, &$success))) { - common_log(LOG_INFO, 'Setting cache value for key ' . $key); - $_items[$key] = $value; + common_perf_counter('Cache::set', $key); + if (Event::handle('StartCacheSet', array(&$key, &$value, &$flag, + &$expiry, &$success))) { + + $this->_items[$key] = serialize($value); + $success = true; - Event::handle('EndCacheSet', array($key, $value, $flag, $expiry)); + + Event::handle('EndCacheSet', array($key, $value, $flag, + $expiry)); } return $success; } + /** + * Atomically increment an existing numeric value. + * Existing expiration time should remain unchanged, if any. + * + * @param string $key The key to use for lookups + * @param int $step Amount to increment (default 1) + * + * @return mixed incremented value, or false if not set. + */ + function increment($key, $step=1) + { + $value = false; + common_perf_counter('Cache::increment', $key); + if (Event::handle('StartCacheIncrement', array(&$key, &$step, &$value))) { + // Fallback is not guaranteed to be atomic, + // and may original expiry value. + $value = $this->get($key); + if ($value !== false) { + $value += $step; + $ok = $this->set($key, $value); + $got = $this->get($key); + } + Event::handle('EndCacheIncrement', array($key, $step, $value)); + } + return $value; + } + + /** + * Delete the value associated with a key + * + * @param string $key Key to delete + * + * @return boolean success flag + */ function delete($key) { $success = false; - if (!Event::handle('StartCacheDelete', array(&$key, &$success))) { - common_log(LOG_INFO, 'Deleting cache value for key ' . $key); - unset($_items[$key]); + common_perf_counter('Cache::delete', $key); + if (Event::handle('StartCacheDelete', array(&$key, &$success))) { + if (array_key_exists($key, $this->_items)) { + unset($this->_items[$key]); + } $success = true; Event::handle('EndCacheDelete', array($key)); } return $success; } + + /** + * Close or reconnect any remote connections, such as to give + * daemon processes a chance to reconnect on a fresh socket. + * + * @return boolean success flag + */ + function reconnect() + { + $success = false; + + if (Event::handle('StartCacheReconnect', array(&$success))) { + $success = true; + Event::handle('EndCacheReconnect', array()); + } + + return $success; + } }