fix git cvs drift
[moodle.git] / lib / eaccelerator.class.php
CommitLineData
2142d492 1<?php
2142d492 2
11e1f828
MH
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.
14//
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/>.
17
18/**
19 * This class abstracts eaccelerator/turckmmcache
20 * API to provide
21 *
22 * - get()
23 * - set()
24 * - delete()
25 * - getforfill()
26 * - releaseforfill()
27 *
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.
31 *
32 * @copyright Martin Langhoff <martin@catalyst.net.nz>
33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34 * @package moodlecore
35 */
2142d492 36
11e1f828
MH
37/**
38 *
39 * @copyright Martin Langhoff <martin@catalyst.net.nz>
40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41 * @package moodlecore
42 */
2142d492 43class eaccelerator {
44
11e1f828
MH
45 /**
46 * @todo Document this function
47 *
48 * @global object
49 */
2142d492 50 function eaccelerator() {
51 global $CFG;
52 if ( function_exists('eaccelerator_get')) {
85cab9d8 53 $this->mode = 'eaccelerator';
2142d492 54 } elseif (function_exists('mmcache_get')) {
85cab9d8 55 $this->mode = 'mmcache';
2142d492 56 } else {
57 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.");
58 }
59
2142d492 60 $this->prefix = $CFG->dbname .'|' . $CFG->prefix . '|';
61 }
62
11e1f828
MH
63 /**
64 * The status of the eaccelerator, if it has been established
65 * this will return true
66 *
67 * @return bool
68 */
2142d492 69 function status() {
70 if (isset($this->mode)) {
71 return true;
72 }
73 return false;
74 }
75
11e1f828
MH
76 /**
77 * @todo Document this function
78 *
79 * @param string $key
80 * @param string $value
81 * @param int $ttl
82 * @return mixed
83 */
2142d492 84 function set($key, $value, $ttl=0) {
85 $set = $this->mode . '_put';
86 $unlock = $this->mode . '_unlock';
87
88 // we may have acquired a lock via getforfill
89 // release if it exists
90 @$unlock($this->prefix . $key . '_forfill');
91
92 return $set($this->prefix . $key, serialize($value), $ttl);
93 }
94
11e1f828
MH
95 /**
96 * @todo Document this function
97 *
98 * @param string $key
99 * @return string|bool String if success else false
100 */
2142d492 101 function get($key) {
102 $fn = $this->mode . '_get';
103 $rec = $fn($this->prefix . $key);
104 if (is_null($rec)) {
f917d0ea 105 return false;
2142d492 106 }
107 return unserialize($rec);
108 }
11e1f828
MH
109
110 /**
111 * @todo Document this function
112 *
113 * @param string $key
114 * @return mixed
115 */
2142d492 116 function delete($key) {
117 $fn = $this->mode . '_rm';
118 return $fn($this->prefix . $key);
119 }
120
121 /**
122 * In the simple case, this function will
123 * get the cached value if available. If the entry
124 * is not cached, it will try to get an exclusive
125 * lock that announces that this process will
126 * populate the cache.
127 *
128 * If we fail to get the lock -- this means another
129 * process is doing it.
130 * so we wait (block) for a few microseconds while we wait for
131 * the cache to be filled or the lock to timeout.
132 *
133 * If you get a false from this call, you _must_
134 * populate the cache ASAP or indicate that
135 * you won't by calling releaseforfill().
136 *
137 * This technique forces serialisation and so helps deal
138 * with thundering herd scenarios where a lot of clients
139 * ask the for the same idempotent (and costly) operation.
140 * The implementation is based on suggestions in this message
141 * http://marc.theaimsgroup.com/?l=git&m=116562052506776&w=2
142 *
143 * @param $key string
f917d0ea 144 * @return mixed on cache hit, false otherwise
2142d492 145 */
146 function getforfill ($key) {
147 $get = $this->mode . '_get';
148 $lock = $this->mode . '_lock';
149
150 $rec = $get($this->prefix . $key);
151 if (!is_null($rec)) {
152 return unserialize($rec);
153 }
154 if ($lock($this->prefix . $key . '_forfill')) {
155 // we obtained the _forfill lock
156 // our caller will compute and set the value
f917d0ea 157 return false;
2142d492 158 }
159 // someone else has the lock
160 // "block" till we can get the value
161 // actually, loop .05s waiting for it
162 for ($n=0;$n<5;$n++) {
163 usleep(10000);
164 $rec = $get($this->prefix . $key);
165 if (!is_null($rec)) {
166 return unserialize($rec);
167 }
168 }
f917d0ea 169 return false;
2142d492 170 }
171
172 /**
173 * Release the exclusive lock obtained by
174 * getforfill(). See getforfill()
175 * for more details.
176 *
177 * @param $key string
178 * @return bool
179 */
180 function releaseforfill ($key) {
181 $unlock = $this->mode . '_unlock';
182 return $unlock($this->prefix . $key . '_forfill');
183 }
184}
185
186?>