3 ** This class abstracts PHP's PECL memcached
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.
21 function memcached() {
24 if (!function_exists('memcache_connect')) {
25 debugging("Memcached is set to true but the memcached extension is not installed");
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]);
38 // multi-host setup will share key space
39 foreach ($hosts as $host) {
41 $this->_cache
->addServer($host);
45 $this->prefix
= $CFG->dbname
.'|' . $CFG->prefix
. '|';
49 if (is_object($this->_cache
)) {
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);
65 $rec = $this->_cache
->get($this->prefix
. $key);
69 function delete($key) {
70 return $this->_cache
->delete($this->prefix
. $key);
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
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
96 * @return mixed on cache hit, NULL otherwise
98 function getforfill ($key) {
100 $rec = $this->_cache
->get($this->prefix
. $key);
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
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++
) {
114 $rec = $this->_cache
->get($this->prefix
. $key);
123 * Release the exclusive lock obtained by
124 * getforfill(). See getforfill()
130 function releaseforfill ($key) {
131 return $this->_cache
->delete($this->prefix
. $key . '_forfill');