3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
23 * This class impliments memcached based caching It'll generally be more
24 * usefull in a multi-server envirionment then the file based caching,
25 * (in a single server setup file based caching is actually faster)
27 class CacheMemcache
extends Cache
{
28 private $connection = false;
30 public function __construct() {
31 if (! function_exists('memcache_connect')) {
32 throw new CacheException("Memcache functions not available");
34 if (Config
::get('cache_host') == '' || Config
::get('cache_port') == '') {
35 throw new CacheException("You need to configure a cache server host and port to use the memcache backend");
37 $this->host
= Config
::get('cache_host');
38 $this->port
= Config
::get('cache_port');
41 private function isLocked($key) {
43 if ((@memcache_get
($this->connection
, $key . '.lock')) === false) {
49 private function createLock($key) {
51 // the interesting thing is that this could fail if the lock was created in the meantime..
52 // but we'll ignore that out of convenience
53 @memcache_add
($this->connection
, $key . '.lock', '', 0, 5);
56 private function removeLock($key) {
58 // suppress all warnings, if some other process removed it that's ok too
59 @memcache_delete
($this->connection
, $key . '.lock');
62 private function waitForLock($key) {
64 // 20 x 250 = 5 seconds
68 // 250 ms is a long time to sleep, but it does stop the server from burning all resources on polling locks..
71 } while ($cnt <= $tries && $this->isLocked());
72 if ($this->isLocked()) {
73 // 5 seconds passed, assume the owning process died off and remove it
74 $this->removeLock($key);
78 // I prefer lazy initalization since the cache isn't used every request
79 // so this potentially saves a lot of overhead
80 private function connect() {
81 if (! $this->connection
= @memcache_pconnect
($this->host
, $this->port
)) {
82 throw new CacheException("Couldn't connect to memcache server");
86 private function check() {
87 if (! $this->connection
) {
92 public function get($key, $expiration = false) {
95 // default to global cache time
96 $expiration = Config
::Get('cache_time');
98 if (($ret = @memcache_get
($this->connection
, $key)) === false) {
101 if (time() - $ret['time'] > $expiration) {
108 public function set($key, $value) {
110 // we store it with the cache_time default expiration so objects will atleast get cleaned eventually.
111 if (@memcache_set
($this->connection
, $key, array('time' => time(),
112 'data' => $value), false, Config
::Get('cache_time')) == false) {
113 throw new CacheException("Couldn't store data in cache");
117 public function delete($key) {
119 @memcache_delete
($this->connection
, $key);