Merge branch 'MDL-33441' of git://github.com/danpoltawski/moodle
[moodle.git] / lib / eaccelerator.class.php
blobbde70b9b5061c5e8a64a1dd7cf0d6e3ea917fc47
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 * This class abstracts eaccelerator/turckmmcache
20 * API to provide
22 * - get()
23 * - set()
24 * - delete()
25 * - getforfill()
26 * - releaseforfill()
28 * Note: do NOT store booleans here. For compatibility with
29 * memcached, a false value is indistinguisable from a
30 * "not found in cache" response.
32 * @package core
33 * @subpackage lib
34 * @copyright Martin Langhoff <martin@catalyst.net.nz>
35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38 defined('MOODLE_INTERNAL') || die();
40 /**
42 * @copyright Martin Langhoff <martin@catalyst.net.nz>
43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44 * @package moodlecore
46 class eaccelerator {
48 /**
49 * @todo Document this function
51 * @global object
53 function eaccelerator() {
54 global $CFG;
55 if ( function_exists('eaccelerator_get')) {
56 $this->mode = 'eaccelerator';
57 } elseif (function_exists('mmcache_get')) {
58 $this->mode = 'mmcache';
59 } else {
60 debugging("\$CFG->eaccelerator is set to true but the required functions are not available. You need to have either eaccelerator or turckmmcache extensions installed, compiled with the shmem keys option enabled.");
63 $this->prefix = $CFG->dbname .'|' . $CFG->prefix . '|';
66 /**
67 * The status of the eaccelerator, if it has been established
68 * this will return true
70 * @return bool
72 function status() {
73 if (isset($this->mode)) {
74 return true;
76 return false;
79 /**
80 * @todo Document this function
82 * @param string $key
83 * @param string $value
84 * @param int $ttl
85 * @return mixed
87 function set($key, $value, $ttl=0) {
88 $set = $this->mode . '_put';
89 $unlock = $this->mode . '_unlock';
91 // we may have acquired a lock via getforfill
92 // release if it exists
93 @$unlock($this->prefix . $key . '_forfill');
95 return $set($this->prefix . $key, serialize($value), $ttl);
98 /**
99 * @todo Document this function
101 * @param string $key
102 * @return string|bool String if success else false
104 function get($key) {
105 $fn = $this->mode . '_get';
106 $rec = $fn($this->prefix . $key);
107 if (is_null($rec)) {
108 return false;
110 return unserialize($rec);
114 * @todo Document this function
116 * @param string $key
117 * @return mixed
119 function delete($key) {
120 $fn = $this->mode . '_rm';
121 return $fn($this->prefix . $key);
125 * In the simple case, this function will
126 * get the cached value if available. If the entry
127 * is not cached, it will try to get an exclusive
128 * lock that announces that this process will
129 * populate the cache.
131 * If we fail to get the lock -- this means another
132 * process is doing it.
133 * so we wait (block) for a few microseconds while we wait for
134 * the cache to be filled or the lock to timeout.
136 * If you get a false from this call, you _must_
137 * populate the cache ASAP or indicate that
138 * you won't by calling releaseforfill().
140 * This technique forces serialisation and so helps deal
141 * with thundering herd scenarios where a lot of clients
142 * ask the for the same idempotent (and costly) operation.
143 * The implementation is based on suggestions in this message
144 * http://marc.theaimsgroup.com/?l=git&m=116562052506776&w=2
146 * @param $key string
147 * @return mixed on cache hit, false otherwise
149 function getforfill ($key) {
150 $get = $this->mode . '_get';
151 $lock = $this->mode . '_lock';
153 $rec = $get($this->prefix . $key);
154 if (!is_null($rec)) {
155 return unserialize($rec);
157 if ($lock($this->prefix . $key . '_forfill')) {
158 // we obtained the _forfill lock
159 // our caller will compute and set the value
160 return false;
162 // someone else has the lock
163 // "block" till we can get the value
164 // actually, loop .05s waiting for it
165 for ($n=0;$n<5;$n++) {
166 usleep(10000);
167 $rec = $get($this->prefix . $key);
168 if (!is_null($rec)) {
169 return unserialize($rec);
172 return false;
176 * Release the exclusive lock obtained by
177 * getforfill(). See getforfill()
178 * for more details.
180 * @param $key string
181 * @return bool
183 function releaseforfill ($key) {
184 $unlock = $this->mode . '_unlock';
185 return $unlock($this->prefix . $key . '_forfill');