Since the cache implementations aren't really meant to be 100% production ready,...
[shindig.git] / php / src / common / sample / CacheMemcache.php
blobd37effde2ea19e0e3a28b355ed060d2d88fff4c8
1 <?php
2 /**
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
18 * under the License.
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) {
42 $this->check();
43 if ((@memcache_get($this->connection, $key . '.lock')) === false) {
44 return false;
46 return true;
49 private function createLock($key) {
50 $this->check();
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) {
57 $this->check();
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) {
63 $this->check();
64 // 20 x 250 = 5 seconds
65 $tries = 20;
66 $cnt = 0;
67 do {
68 // 250 ms is a long time to sleep, but it does stop the server from burning all resources on polling locks..
69 usleep(250);
70 $cnt ++;
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) {
88 $this->connect();
92 public function get($key, $expiration = false) {
93 $this->check();
94 if (! $expiration) {
95 // default to global cache time
96 $expiration = Config::Get('cache_time');
98 if (($ret = @memcache_get($this->connection, $key)) === false) {
99 return false;
101 if (time() - $ret['time'] > $expiration) {
102 $this->delete($key);
103 return false;
105 return $ret['data'];
108 public function set($key, $value) {
109 $this->check();
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) {
118 $this->check();
119 @memcache_delete($this->connection, $key);