Updated the 19 build version to 20100611
[moodle.git] / lib / memcached.class.php
blobd58ce0c334f630c8dbf8ce57050d68197e174fd5
1 <?php
2 /**
3 ** This class abstracts PHP's PECL memcached
4 ** API to provide
5 **
6 ** - get()
7 ** - set()
8 ** - delete()
9 ** - getforfill()
10 ** - releaseforfill()
12 ** Author: Martin Langhoff <martin@catalyst.net.nz>
14 ** Note: do NOT store booleans here. With memcached, a false value
15 ** is indistinguisable from a "not found in cache" response.
16 **/
19 class memcached {
21 function memcached() {
22 global $CFG;
24 if (!function_exists('memcache_connect')) {
25 debugging("Memcached is set to true but the memcached extension is not installed");
26 return false;
28 $this->_cache = new Memcache;
30 $hosts = split(',', $CFG->memcachedhosts);
31 if (count($hosts) === 1 && !empty($CFG->memcachedpconn)) {
32 // the faster pconnect is only available
33 // for single-server setups
34 // NOTE: PHP-PECL client is buggy and pconnect()
35 // will segfault if the server is unavailable
36 $this->_cache->pconnect($hosts[0]);
37 } else {
38 // multi-host setup will share key space
39 foreach ($hosts as $host) {
40 $host = trim($host);
41 $this->_cache->addServer($host);
45 $this->prefix = $CFG->dbname .'|' . $CFG->prefix . '|';
48 function status() {
49 if (is_object($this->_cache)) {
50 return true;
52 return false;
55 function set($key, $value, $ttl=0) {
57 // we may have acquired a lock via getforfill
58 // release if it exists
59 @$this->_cache->delete($this->prefix . $key . '_forfill');
61 return $this->_cache->set($this->prefix . $key, $value, false);
64 function get($key) {
65 $rec = $this->_cache->get($this->prefix . $key);
66 return $rec;
69 function delete($key) {
70 return $this->_cache->delete($this->prefix . $key);
73 /**
74 * In the simple case, this function will
75 * get the cached value if available. If the entry
76 * is not cached, it will try to get an exclusive
77 * lock that announces that this process will
78 * populate the cache.
80 * If we fail to get the lock -- this means another
81 * process is doing it.
82 * so we wait (block) for a few microseconds while we wait for
83 * the cache to be filled or the lock to timeout.
85 * If you get a false from this call, you _must_
86 * populate the cache ASAP or indicate that
87 * you won't by calling releaseforfill().
89 * This technique forces serialisation and so helps deal
90 * with thundering herd scenarios where a lot of clients
91 * ask the for the same idempotent (and costly) operation.
92 * The implementation is based on suggestions in this message
93 * http://marc.theaimsgroup.com/?l=git&m=116562052506776&w=2
95 * @param $key string
96 * @return mixed on cache hit, NULL otherwise
98 function getforfill ($key) {
100 $rec = $this->_cache->get($this->prefix . $key);
101 if ($rec) {
102 return $rec;
104 if ($this->_cache->add($this->prefix . $key . '_forfill', 'true', false, 1)) {
105 // we obtained the _forfill lock
106 // our caller will compute and set the value
107 return false;
109 // someone else has the lock
110 // "block" till we can get the value
111 // actually, loop .05s waiting for it
112 for ($n=0;$n<5;$n++) {
113 usleep(10000);
114 $rec = $this->_cache->get($this->prefix . $key);
115 if ($rec) {
116 return $rec;
119 return false;
123 * Release the exclusive lock obtained by
124 * getforfill(). See getforfill()
125 * for more details.
127 * @param $key string
128 * @return bool
130 function releaseforfill ($key) {
131 return $this->_cache->delete($this->prefix . $key . '_forfill');