2 // +----------------------------------------------------------------------+
4 // +----------------------------------------------------------------------+
5 // | Copyright (c) 1997-2003 The PHP Group |
6 // +----------------------------------------------------------------------+
7 // | This source file is subject to version 2.0 of the PHP license, |
8 // | that is bundled with this package in the file LICENSE, and is |
9 // | available at through the world-wide-web at |
10 // | http://www.php.net/license/2_02.txt. |
11 // | If you did not receive a copy of the PHP license and are unable to |
12 // | obtain it through the world-wide-web, please send a note to |
13 // | license@php.net so we can mail you a copy immediately. |
14 // +----------------------------------------------------------------------+
15 // | Authors: Ulf Wendel <ulf.wendel@phpdoc.de> |
16 // | Sebastian Bergmann <sb@sebastian-bergmann.de> |
17 // +----------------------------------------------------------------------+
19 // $Id: shm.php 186977 2005-05-25 10:00:41Z dufuz $
21 require_once 'Cache/Container.php';
24 * Stores cache data into shared memory.
26 * Well, this is not a very efficient implementation. Indeed it's much
27 * slower than the file container as far as my tests showed. Files are
28 * cached by most operating systems and it will be hard to write a faster
29 * caching algorithm using PHP.
31 * @author Ulf Wendel <ulf.wendel@phpdoc.de>
32 * @version $Id: shm.php 186977 2005-05-25 10:00:41Z dufuz $
35 class Cache_Container_shm extends Cache_Container
38 * Key of the semaphore used to sync the SHM access
45 * Permissions of the semaphore used to sync the SHM access
59 * Key of the shared memory block used to store cache data
66 * Size of the shared memory block used
68 * Note: the container does only use _one_ shm block no more!
72 var $shm_size = 131072;
75 * Permissions of the shared memory block
82 * Shared memory handler
89 * Hash of cache entries
91 * Used by the garbage collection to find old entries.
95 var $entries = array();
98 * Number of bytes consumed by the cache
105 * Creates a shared memory container
107 * @param array shm_key, sem_key, shm_size, sem_perm, shm_perm
109 function Cache_Container_shm($options = '')
111 if (is_array($options)) {
112 $this->setOptions($options, array_merge($this->allowed_options,
113 array('shm_key', 'sem_key',
114 'shm_size', 'sem_perm',
120 // Cache::Container high- and lowwater defaults should be overridden if
121 // not already done by the user
122 if (!isset($options['highwater'])) {
123 $this->highwater = round(0.75 * 131072);
125 if (!isset($options['lowwater'])) {
126 $this->lowwater = round(0.5 * 131072);
128 if (!isset($options['shm_size'])) {
129 $this->shm_size = 131072;
131 //get SHM and Semaphore handles
132 if (!($this->shm_id = shmop_open($this->shm_key, 'c', $this->shm_perm, $this->shm_size))) {
133 new Cache_Error("Can't open SHM segment '{$this->shm_key}', size '{$this->shm_size}'.",
138 if (!($this->sem_id = sem_get($this->sem_key, 1, $this->sem_perm))) {
139 new Cache_Error("Can't get semaphore '{$this->sem_key}' using perms '{$this->sem_perm}'.",
146 function fetch($id, $group)
148 sem_acquire($this->sem_id);
150 $cachedata = shmop_read($this->shm_id, 0, $this->shm_size);
152 sem_release($this->sem_id);
154 $cachedata = $this->decode($cachedata);
156 if (!isset($cachedata[$group][$id])) {
157 return array(null, null, null);
159 $cachedata = $cachedata[$group][$id];
161 return array($cachedata['expire'],
162 $cachedata['cachedata'],
163 $cachedata['userdata']
167 function save($id, $data, $expire, $group, $userdata)
169 $this->flushPreload($id, $group);
171 sem_acquire($this->sem_id);
173 $cachedata = $this->decode(shmop_read($this->shm_id, 0, $this->shm_size));
174 $cachedata[$group][$id] = array('expire' => $this->getExpiresAbsolute($expire),
175 'cachedata' => $data,
176 'userdata' => $userdata,
180 if (strlen($newdata = $this->encode($cachedata)) > $this->shm_size) {
181 $cachedata = $this->garbageCollection(time(), $cachedata);
183 shmop_write($this->shm_id, $newdata, 0);
185 sem_release($this->sem_id);
190 function remove($id, $group)
192 $this->flushPreload($id, $group);
194 sem_acquire($this->sem_id);
196 $cachedata = $this->decode(shmop_read($this->shm_id, 0, $this->shm_size));
197 unset($cachedata[$group][$id]);
198 shmop_write($this->shm_id, $this->encode($cachedata), 0);
200 sem_release($this->sem_id);
203 function flush($group = '')
205 $this->flushPreload();
207 sem_acquire($this->sem_id);
209 shmop_write($this->shm_id, $this->encode(array()), 0);
211 sem_release($this->sem_id);
214 function idExists($id, $group)
216 sem_acquire($this->sem_id);
218 $cachedata = shm_read($this->shm_id, 0, $this->shm_size);
220 sem_release($this->sem_id);
222 $cachedata = $this->decode($cachedata);
224 return isset($cachedata[$group][$id]);
225 } // end func isExists
227 function garbageCollection($maxlifetime, $cachedata = array())
229 if ($lock = empty($cachedata)) {
230 sem_acquire($this->sem_id);
231 $cachedata = $this->decode(shmop_read($this->shm_id, 0, $this->shm_size));
234 $this->doGarbageCollection($maxlifetime, $cachedata);
235 if ($this->total_size > $this->highwater) {
236 krsort($this->entries);
237 reset($this->entries);
239 while ($this->total_size > $this->lowwater && list($size, $entries) = each($this->entries)) {
242 while (list($k, $entry) = each($entries)) {
243 unset($cachedata[$entry['group']][$entry['id']]);
244 $this->total_size -= $size;
250 sem_release($this->sem_id);
252 $this->entries = array();
253 $this->total_size = 0;
256 } // end func garbageCollection
258 function doGarbageCollection($maxlifetime, &$cachedata)
260 $changed = time() - $maxlifetime;
265 while (list($group, $groupdata) = each($cachedata)) {
268 while (list($id, $data) = each($groupdata)) {
269 if ($data['expire'] < time() || $data['changed'] < $changed) {
270 unset($cachedata[$group][$id]);
274 // ugly but simple to implement :/
275 $size = strlen($this->encode($data));
276 $this->entries[$size][] = array(
281 $this->total_size += $size;
285 } // end func doGarbageCollection
286 } // end class Cache_Container_shm