2142d492 |
1 | <?php |
2 | /** |
3 | ** This class abstracts eaccelerator/turckmmcache |
4 | ** API to provide |
5 | ** |
6 | ** - get() |
7 | ** - set() |
8 | ** - delete() |
9 | ** - getforfill() |
10 | ** - releaseforfill() |
11 | ** |
12 | ** Author: Martin Langhoff <martin@catalyst.net.nz> |
13 | ** |
f917d0ea |
14 | ** Note: do NOT store booleans here. For compatibility with |
15 | ** memcached, a false value is indistinguisable from a |
16 | ** "not found in cache" response. |
2142d492 |
17 | **/ |
18 | |
19 | |
20 | class eaccelerator { |
21 | |
22 | function eaccelerator() { |
23 | global $CFG; |
24 | if ( function_exists('eaccelerator_get')) { |
85cab9d8 |
25 | $this->mode = 'eaccelerator'; |
2142d492 |
26 | } elseif (function_exists('mmcache_get')) { |
85cab9d8 |
27 | $this->mode = 'mmcache'; |
2142d492 |
28 | } else { |
29 | 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."); |
30 | } |
31 | |
2142d492 |
32 | $this->prefix = $CFG->dbname .'|' . $CFG->prefix . '|'; |
33 | } |
34 | |
35 | function status() { |
36 | if (isset($this->mode)) { |
37 | return true; |
38 | } |
39 | return false; |
40 | } |
41 | |
42 | function set($key, $value, $ttl=0) { |
43 | $set = $this->mode . '_put'; |
44 | $unlock = $this->mode . '_unlock'; |
45 | |
46 | // we may have acquired a lock via getforfill |
47 | // release if it exists |
48 | @$unlock($this->prefix . $key . '_forfill'); |
49 | |
50 | return $set($this->prefix . $key, serialize($value), $ttl); |
51 | } |
52 | |
53 | function get($key) { |
54 | $fn = $this->mode . '_get'; |
55 | $rec = $fn($this->prefix . $key); |
56 | if (is_null($rec)) { |
f917d0ea |
57 | return false; |
2142d492 |
58 | } |
59 | return unserialize($rec); |
60 | } |
61 | |
62 | function delete($key) { |
63 | $fn = $this->mode . '_rm'; |
64 | return $fn($this->prefix . $key); |
65 | } |
66 | |
67 | /** |
68 | * In the simple case, this function will |
69 | * get the cached value if available. If the entry |
70 | * is not cached, it will try to get an exclusive |
71 | * lock that announces that this process will |
72 | * populate the cache. |
73 | * |
74 | * If we fail to get the lock -- this means another |
75 | * process is doing it. |
76 | * so we wait (block) for a few microseconds while we wait for |
77 | * the cache to be filled or the lock to timeout. |
78 | * |
79 | * If you get a false from this call, you _must_ |
80 | * populate the cache ASAP or indicate that |
81 | * you won't by calling releaseforfill(). |
82 | * |
83 | * This technique forces serialisation and so helps deal |
84 | * with thundering herd scenarios where a lot of clients |
85 | * ask the for the same idempotent (and costly) operation. |
86 | * The implementation is based on suggestions in this message |
87 | * http://marc.theaimsgroup.com/?l=git&m=116562052506776&w=2 |
88 | * |
89 | * @param $key string |
f917d0ea |
90 | * @return mixed on cache hit, false otherwise |
2142d492 |
91 | */ |
92 | function getforfill ($key) { |
93 | $get = $this->mode . '_get'; |
94 | $lock = $this->mode . '_lock'; |
95 | |
96 | $rec = $get($this->prefix . $key); |
97 | if (!is_null($rec)) { |
98 | return unserialize($rec); |
99 | } |
100 | if ($lock($this->prefix . $key . '_forfill')) { |
101 | // we obtained the _forfill lock |
102 | // our caller will compute and set the value |
f917d0ea |
103 | return false; |
2142d492 |
104 | } |
105 | // someone else has the lock |
106 | // "block" till we can get the value |
107 | // actually, loop .05s waiting for it |
108 | for ($n=0;$n<5;$n++) { |
109 | usleep(10000); |
110 | $rec = $get($this->prefix . $key); |
111 | if (!is_null($rec)) { |
112 | return unserialize($rec); |
113 | } |
114 | } |
f917d0ea |
115 | return false; |
2142d492 |
116 | } |
117 | |
118 | /** |
119 | * Release the exclusive lock obtained by |
120 | * getforfill(). See getforfill() |
121 | * for more details. |
122 | * |
123 | * @param $key string |
124 | * @return bool |
125 | */ |
126 | function releaseforfill ($key) { |
127 | $unlock = $this->mode . '_unlock'; |
128 | return $unlock($this->prefix . $key . '_forfill'); |
129 | } |
130 | } |
131 | |
132 | ?> |