MDL-34011 Lesson module: fixed incorrect display of student attempt for short answer...
[moodle.git] / lib / memcached.class.php
blob35ac0f4f892056d310baa723d5f481f7132240e5
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 /**
19 * @package core
20 * @subpackage lib
21 * @copyright Martin Langhoff <martin@catalyst.net.nz>
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 defined('MOODLE_INTERNAL') || die();
27 /**
28 * This class abstracts PHP's PECL memcached
29 * API to provide
31 * - get()
32 * - set()
33 * - delete()
34 * - getforfill()
35 * - releaseforfill()
37 * Author: Martin Langhoff <martin@catalyst.net.nz>
39 * Note: do NOT store booleans here. With memcached, a false value
40 * is indistinguisable from a "not found in cache" response.
42 * @package moodlecore
43 * @copyright Martin Langhoff <martin@catalyst.net.nz>
44 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45 **/
46 class memcached {
48 function memcached() {
49 global $CFG;
51 if (!function_exists('memcache_connect')) {
52 debugging("Memcached is set to true but the memcached extension is not installed");
53 return false;
55 $this->_cache = new Memcache;
57 $hosts = explode(',', $CFG->memcachedhosts);
58 if (count($hosts) === 1 && !empty($CFG->memcachedpconn)) {
59 // the faster pconnect is only available
60 // for single-server setups
61 // NOTE: PHP-PECL client is buggy and pconnect()
62 // will segfault if the server is unavailable
63 $this->_cache->pconnect($hosts[0]);
64 } else {
65 // multi-host setup will share key space
66 foreach ($hosts as $host) {
67 $host = trim($host);
68 $this->_cache->addServer($host);
72 $this->prefix = $CFG->dbname .'|' . $CFG->prefix . '|';
75 function status() {
76 if (is_object($this->_cache)) {
77 return true;
79 return false;
82 function set($key, $value, $ttl=0) {
84 // we may have acquired a lock via getforfill
85 // release if it exists
86 @$this->_cache->delete($this->prefix . $key . '_forfill');
88 return $this->_cache->set($this->prefix . $key, $value, false);
91 function get($key) {
92 $rec = $this->_cache->get($this->prefix . $key);
93 return $rec;
96 function delete($key) {
97 return $this->_cache->delete($this->prefix . $key);
101 * In the simple case, this function will
102 * get the cached value if available. If the entry
103 * is not cached, it will try to get an exclusive
104 * lock that announces that this process will
105 * populate the cache.
107 * If we fail to get the lock -- this means another
108 * process is doing it.
109 * so we wait (block) for a few microseconds while we wait for
110 * the cache to be filled or the lock to timeout.
112 * If you get a false from this call, you _must_
113 * populate the cache ASAP or indicate that
114 * you won't by calling releaseforfill().
116 * This technique forces serialisation and so helps deal
117 * with thundering herd scenarios where a lot of clients
118 * ask the for the same idempotent (and costly) operation.
119 * The implementation is based on suggestions in this message
120 * http://marc.theaimsgroup.com/?l=git&m=116562052506776&w=2
122 * @param $key string
123 * @return mixed on cache hit, NULL otherwise
125 function getforfill ($key) {
127 $rec = $this->_cache->get($this->prefix . $key);
128 if ($rec) {
129 return $rec;
131 if ($this->_cache->add($this->prefix . $key . '_forfill', 'true', false, 1)) {
132 // we obtained the _forfill lock
133 // our caller will compute and set the value
134 return false;
136 // someone else has the lock
137 // "block" till we can get the value
138 // actually, loop .05s waiting for it
139 for ($n=0;$n<5;$n++) {
140 usleep(10000);
141 $rec = $this->_cache->get($this->prefix . $key);
142 if ($rec) {
143 return $rec;
146 return false;
150 * Release the exclusive lock obtained by
151 * getforfill(). See getforfill()
152 * for more details.
154 * @param $key string
155 * @return bool
157 function releaseforfill ($key) {
158 return $this->_cache->delete($this->prefix . $key . '_forfill');