/** * Read from cache. * @param string key * @return mixed|NULL */ public function read($key) { $key = $this->prefix . $key; $meta = $this->memcache->get($key); if (!$meta) { return NULL; } // meta structure: // array( // data => stored data // delta => relative (sliding) expiration // callbacks => array of callbacks (function, args) // ) // verify dependencies if (!empty($meta[self::META_CALLBACKS]) && !Cache::checkCallbacks($meta[self::META_CALLBACKS])) { $this->memcache->delete($key, 0); return NULL; } if (!empty($meta[self::META_DELTA])) { $this->memcache->replace($key, $meta, 0, $meta[self::META_DELTA] + time()); } return $meta[self::META_DATA]; }
/** * Read from cache. * @param string key * @return mixed|NULL */ public function read($key) { $this->_normalizeKey($key); $meta = apc_fetch($key); if (!$meta) { return NULL; } // meta structure: // array( // data => stored data // delta => relative (sliding) expiration // callbacks => array of callbacks (function, args) // ) // verify dependencies if (!empty($meta[self::META_CALLBACKS]) && !Cache::checkCallbacks($meta[self::META_CALLBACKS])) { apc_delete($key); return NULL; } if (!empty($meta[self::META_DELTA])) { apc_delete($key); apc_store($key, $meta, 0, $meta[self::META_DELTA] + time()); } return $meta[self::META_DATA]; }
/** * Verifies dependencies. * @param array * @return bool */ private function verify($meta) { do { if (!empty($meta[self::META_DELTA])) { // meta[file] was added by readMetaAndLock() if (filemtime($meta[self::FILE]) + $meta[self::META_DELTA] < time()) { break; } touch($meta[self::FILE]); } elseif (!empty($meta[self::META_EXPIRE]) && $meta[self::META_EXPIRE] < time()) { break; } if (!empty($meta[self::META_CALLBACKS]) && !Cache::checkCallbacks($meta[self::META_CALLBACKS])) { break; } if (!empty($meta[self::META_ITEMS])) { foreach ($meta[self::META_ITEMS] as $depFile => $time) { $m = $this->readMetaAndLock($depFile, LOCK_SH); if ($m[self::META_TIME] !== $time || $m && !$this->verify($m)) { break 2; } } } return TRUE; } while (FALSE); $this->delete($meta[self::FILE], $meta[self::HANDLE]); // meta[handle] & meta[file] was added by readMetaAndLock() return FALSE; }
function read($key) { $key = $this->prefix . $key; $meta = $this->memcache->get($key); if (!$meta) { return NULL; } if (!empty($meta[self::META_CALLBACKS]) && !Cache::checkCallbacks($meta[self::META_CALLBACKS])) { $this->memcache->delete($key, 0); return NULL; } if (!empty($meta[self::META_DELTA])) { $this->memcache->replace($key, $meta, 0, $meta[self::META_DELTA] + time()); } return $meta[self::META_DATA]; }
/** * Verifies dependencies. * * @param array * * @return bool */ protected function verify($meta) { do { if (!empty($meta[self::META_DELTA])) { $this->client->send('expire', [$this->formatEntryKey($meta[self::KEY]), $meta[self::META_DELTA]]); } elseif (!empty($meta[self::META_EXPIRE]) && $meta[self::META_EXPIRE] < time()) { break; } if (!empty($meta[self::META_CALLBACKS]) && !Cache::checkCallbacks($meta[self::META_CALLBACKS])) { break; } if (!empty($meta[self::META_ITEMS])) { foreach ($meta[self::META_ITEMS] as $itemKey => $time) { $m = $this->readMeta($itemKey); if ($m[self::META_TIME] !== $time || $m && !$this->verify($m)) { break 2; } } } return TRUE; } while (FALSE); $this->remove($meta[self::KEY]); // meta[handle] & meta[file] was added by readMetaAndLock() return FALSE; }
/** * Reads from cache in bulk. * @param string key * @return array key => value pairs, missing items are omitted */ public function bulkRead(array $keys) { $prefixedKeys = array_map(function ($key) { return urlencode($this->prefix . $key); }, $keys); $keys = array_combine($prefixedKeys, $keys); $metas = $this->memcached->getMulti($prefixedKeys); $result = []; $deleteKeys = []; foreach ($metas as $prefixedKey => $meta) { if (!empty($meta[self::META_CALLBACKS]) && !Cache::checkCallbacks($meta[self::META_CALLBACKS])) { $deleteKeys[] = $prefixedKey; } else { $result[$keys[$prefixedKey]] = $meta[self::META_DATA]; } if (!empty($meta[self::META_DELTA])) { $this->memcached->replace($prefixedKey, $meta, $meta[self::META_DELTA] + time()); } } if (!empty($deleteKeys)) { $this->memcached->deleteMulti($deleteKeys, 0); } return $result; }