Andrew's Web Libraries (AWL)
AwlCache.php
1<?php
2
10class AwlCache {
11 private static $m;
12 private static $servers;
13 private static $working;
14
18 function __construct() {
19 global $c;
20
21 if ( isset(self::$working) ) return;
22
23 self::$working = false;
24 if ( ! isset($c->memcache_servers) ) {
25 dbg_error_log('Cache', "memcache_servers isn't set, using NoCache dummy interface");
26 return;
27 } else if (! is_array($c->memcache_servers) ) {
28 dbg_error_log('Cache', "memcache_servers must be an array, using NoCache dummy interface");
29 return;
30 }
31
32 if (! class_exists('Memcached') ) {
33 dbg_error_log('Cache', "Memcached class isn't available, using NoCache dummy interface");
34 return;
35 }
36
37 dbg_error_log('Cache', 'Using Memcached interface connection');
38 self::$servers = $c->memcache_servers;
39 self::$m = new Memcached();
40 foreach( self::$servers AS $v ) {
41 dbg_error_log('Cache', 'Adding server '.$v);
42 $server = explode(',',$v);
43 if ( isset($server[2]) )
44 self::$m->addServer($server[0],$server[1],$server[2]);
45 else
46 self::$m->addServer($server[0],$server[1]);
47 }
48 self::$working = true;
49
50 // Hack to allow the regression tests to flush the cache at start
51 if ( isset($_SERVER['HTTP_X_DAVICAL_FLUSH_CACHE'])) $this->flush();
52 }
53
57 function isActive() {
58 return self::$working;
59 }
60
66 private function nskey( $namespace, $key ) {
67 return str_replace(' ', '%20', $namespace . (isset($key) ? '~~' . $key: '')); // for now.
68 }
69
75 function get( $namespace, $key ) {
76 if ( !self::$working ) return false;
77 $ourkey = self::nskey($namespace,$key);
78 $value = self::$m->get($ourkey);
79// var_dump($value);
80// if ( $value !== false ) dbg_error_log('Cache', 'Got value for cache key "'.$ourkey.'" - '.strlen(serialize($value)).' bytes');
81 return $value;
82 }
83
91 function set( $namespace, $key, $value, $expiry=864000 ) {
92 if ( !self::$working ) return false;
93 $ourkey = self::nskey($namespace,$key);
94 $nskey = self::nskey($namespace,null);
95 $cas_token = null;
96
97 if (defined('Memcached::GET_EXTENDED')) {
98 $result = self::$m->get( $nskey, null, Memcached::GET_EXTENDED);
99
100 if (is_array($result)) {
101 $keylist = $result['value'];
102 $cas_token = $result['cas'];
103 }
104 } else {
105 $keylist = self::$m->get( $nskey, null, $cas_token );
106 }
107
108 if ( isset($keylist) && is_array($keylist) ) {
109 if ( !isset($keylist[$ourkey]) ) {
110 $keylist[$ourkey] = 1;
111 $success = self::$m->cas( $cas_token, $nskey, $keylist );
112
113 $i=0;
114 while( !$success && $i++ < 10 && self::$m->getResultCode() == Memcached::RES_DATA_EXISTS ) {
115
116 if (defined('Memcached::GET_EXTENDED')) {
117 $result = self::$m->get( $nskey, null, Memcached::GET_EXTENDED);
118 if (is_array($result)) {
119 $keylist = $result['value'];
120 $cas_token = $result['cas'];
121 }
122 } else {
123 $keylist = self::$m->get( $nskey, null, $cas_token );
124 }
125
126 if ( $keylist === false ) return false;
127 if ( isset($keylist[$ourkey]) ) break;
128
129 $keylist[$ourkey] = 1;
130 $success = self::$m->cas( $cas_token, $nskey, $keylist );
131 }
132 if ( !$success ) return false;
133 }
134 }
135 else {
136 $keylist = array( $ourkey => 1 );
137 self::$m->set( $nskey, $keylist );
138 }
139// var_dump($value);
140// dbg_error_log('Cache', 'Setting value for cache key "'.$ourkey.'" - '.strlen(serialize($value)).' bytes');
141 return self::$m->set( $ourkey, $value, $expiry );
142 }
143
149 function delete( $namespace, $key ) {
150 if ( !self::$working ) return false;
151 $nskey = self::nskey($namespace,$key);
152 dbg_error_log('Cache', 'Deleting from cache key "'.$nskey.'"');
153
154 if ( isset($key) ) {
155 self::$m->delete( $nskey );
156 }
157 else {
158 if (defined('Memcached::GET_EXTENDED')) {
159 $result = self::$m->get( $nskey, null, Memcached::GET_EXTENDED);
160 if (is_array($result)) {
161 $keylist = $result['value'];
162 $cas_token = $result['cas'];
163 }
164 } else {
165 $keylist = self::$m->get( $nskey, null, $cas_token );
166 }
167 if ( isset($keylist) ) {
168 self::$m->delete( $nskey );
169 if ( is_array($keylist) ) {
170 foreach( $keylist AS $k => $v ) self::$m->delete( $k );
171 }
172 }
173 }
174 }
175
179 function flush( ) {
180 if ( !self::$working ) return false;
181 dbg_error_log('Cache', 'Flushing cache');
182 self::$m->flush();
183 }
184
185
189 function acquireLock( $something, $wait_for = 5 ) {
190 if ( !self::$working ) return $something;
191 $wait_until = time() + $wait_for;
192 while( self::$m->add('_lock_' . $something, 1, 5) === false && time() < $wait_until ) {
193 usleep(10000);
194 }
195 return $something;
196 }
197
198
202 function releaseLock( $something ) {
203 if ( !self::$working ) return;
204 self::$m->delete('_lock_' . $something);
205 }
206}
207
208
209function getCacheInstance() {
210 static $ourCacheInstance;
211
212 if ( !isset($ourCacheInstance) ) $ourCacheInstance = new AWLCache('Memcached');
213
214 return $ourCacheInstance;
215}
nskey( $namespace, $key)
Definition: AwlCache.php:66
releaseLock( $something)
Definition: AwlCache.php:202
__construct()
Definition: AwlCache.php:18
isActive()
Definition: AwlCache.php:57
acquireLock( $something, $wait_for=5)
Definition: AwlCache.php:189