home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 June / ENTER.ISO / files / xampp-win32-1.4.5-installer.exe / xampp / shm.php < prev    next >
Encoding:
PHP Script  |  2004-03-24  |  8.6 KB  |  277 lines

  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PEAR :: Cache                                                        |
  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. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: shm.php,v 1.3 2003/01/04 11:54:46 mj Exp $
  20.  
  21. require_once 'Cache/Container.php';
  22.  
  23. /**
  24. * Stores cache data into shared memory.
  25. *
  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.
  30. *
  31. * @author   Ulf Wendel <ulf.wendel@phpdoc.de>
  32. * @version  $Id: shm.php,v 1.3 2003/01/04 11:54:46 mj Exp $
  33. * @package  Cache
  34. */
  35. class Cache_Container_shm extends Cache_Container {
  36.     /**
  37.     * Key of the semaphore used to sync the SHM access
  38.     * 
  39.     * @var  int
  40.     */
  41.     var $sem_key = NULL;
  42.  
  43.     /**
  44.     * Permissions of the semaphore used to sync the SHM access
  45.     * 
  46.     * @var  int
  47.     */
  48.     var $sem_perm = 0644;
  49.  
  50.     /**
  51.     * Semaphore handler
  52.     * 
  53.     * @var  resource
  54.     */
  55.     var $sem_id = NULL;
  56.  
  57.     /**
  58.     * Key of the shared memory block used to store cache data
  59.     *
  60.     * @var  int
  61.     */
  62.     var $shm_key = NULL;
  63.  
  64.     /**
  65.     * Size of the shared memory block used
  66.     * 
  67.     * Note: the container does only use _one_ shm block no more!
  68.     * 
  69.     * @var  int
  70.     */        
  71.     var $shm_size = 131072;
  72.  
  73.     /**
  74.     * Permissions of the shared memory block
  75.     * 
  76.     * @var  int
  77.     */
  78.     var $shm_perm = 0644;
  79.  
  80.     /**
  81.     * Shared memory handler
  82.     * 
  83.     * @var resource
  84.     */
  85.     var $shm_id = NULL;
  86.  
  87.     /**
  88.     * Hash of cache entries
  89.     * 
  90.     * Used by the garbage collection to find old entries.
  91.     *
  92.     * @var  array
  93.     */
  94.     var $entries = array();
  95.  
  96.     /**
  97.     * Number of bytes consumed by the cache
  98.     * 
  99.     * @var  int
  100.     */
  101.     var $total_size = 0;
  102.  
  103.     /**
  104.     * Creates a shared memory container
  105.     *
  106.     * @param array    shm_key, sem_key, shm_size, sem_perm, shm_perm
  107.     */    
  108.     function Cache_Container_shm($options = '') {
  109.         if (is_array($options))
  110.             $this->setOptions($options, array_merge($this->allowed_options, 
  111.                                                     array('shm_key',  'sem_key', 
  112.                                                           'shm_size', 'sem_perm',
  113.                                                           'shm_perm'
  114.                                                          )
  115.                                         )
  116.                                );
  117.  
  118.         // Cache::Container high- and lowwater defaults should be overridden if
  119.         // not already done by the user
  120.         if (!isset($options['highwater'])) 
  121.             $this->highwater = round(0.75 * 131072);
  122.         if (!isset($options['lowwater']))
  123.             $this->lowwater = round(0.5 * 131072);
  124.  
  125.         if (!isset($options['shm_size']))
  126.             $this->shm_size = 131072;
  127.  
  128.         //get SHM and Semaphore handles
  129.         if (!($this->shm_id = shmop_open($this->shm_key, 'c', $this->shm_perm, $this->shm_size)))
  130.             new Cache_Error("Can't open SHM segment '{$this->shm_key}', size '{$this->shm_size}'.",
  131.                             __FILE__,
  132.                             __LINE__
  133.                            );
  134.  
  135.         if (!($this->sem_id = sem_get($this->sem_key, 1, $this->sem_perm)))
  136.             new Cache_Error("Can't get semaphore '{$this->sem_key}' using perms '{$this->sem_perm}'.",
  137.                             __FILE__,
  138.                             __LINE__
  139.                            );
  140.  
  141.     } // end constructor
  142.  
  143.     function fetch($id, $group) {
  144.         sem_acquire($this->sem_id);
  145.  
  146.         $cachedata = shmop_read($this->shm_id, 0, $this->shm_size);
  147.  
  148.         sem_release($this->sem_id);
  149.  
  150.         $cachedata = $this->decode($cachedata);
  151.  
  152.         if (!isset($cachedata[$group][$id]))
  153.             return array(NULL, NULL, NULL);
  154.         else 
  155.             $cachedata = $cachedata[$group][$id];
  156.  
  157.         return array($cachedata['expire'],
  158.                      $cachedata['cachedata'],
  159.                      $cachedata['userdata']
  160.                     );
  161.     } // end func fetch
  162.  
  163.     function save($id, $data, $expire, $group, $userdata) {
  164.         $this->flushPreload($id, $group);
  165.  
  166.         sem_acquire($this->sem_id);
  167.  
  168.         $cachedata = $this->decode(shmop_read($this->shm_id, 0, $this->shm_size));
  169.         $cachedata[$group][$id] = array('expire'    => $this->getExpiresAbsolute($expire),
  170.                                         'cachedata' => $data,
  171.                                         'userdata'  => $userdata,
  172.                                         'changed'   => time()
  173.                                        );
  174.  
  175.         if (strlen($newdata = $this->encode($cachedata)) > $this->shm_size)
  176.             $cachedata = $this->garbageCollection(time(), $cachedata);
  177.  
  178.         shmop_write($this->shm_id, $newdata, 0);
  179.  
  180.         sem_release($this->sem_id);
  181.  
  182.         return true;
  183.     } // end func save
  184.  
  185.     function remove($id, $group) {
  186.         $this->flushPreload($id, $group);
  187.  
  188.         sem_acquire($this->sem_id);
  189.  
  190.         $cachedata = $this->decode(shmop_read($this->shm_id, 0, $this->shm_size));
  191.         unset($cachedata[$group][$id]);
  192.         shmop_write($this->shm_id, $this->encode($cachedata), 0);
  193.  
  194.         sem_release($this->sem_id);
  195.     } // end func remove
  196.  
  197.     function flush($group = '') {
  198.         $this->flushPreload();
  199.  
  200.         sem_acquire($this->sem_id);
  201.  
  202.         shmop_write($this->shm_id, $this->encode(array()), 0);
  203.  
  204.         sem_release($this->sem_id);
  205.     } // end func flush
  206.  
  207.     function idExists($id, $group) {
  208.         sem_acquire($this->sem_id);
  209.  
  210.         $cachedata = shm_read($this->shm_id, 0, $this->shm_size);
  211.  
  212.         sem_release($this->sem_id);
  213.  
  214.         $cachedata = $this->decode($cachedata);
  215.  
  216.         return isset($cachedata[$group][$id]);
  217.     } // end func isExists
  218.  
  219.     function garbageCollection($maxlifetime, $cachedata = array()) {
  220.         if ($lock = empty($cachedata)) {
  221.             sem_acquire($this->sem_id);
  222.             $cachedata = $this->decode(shmop_read($this->shm_id, 0, $this->shm_size));
  223.         }
  224.  
  225.         $this->doGarbageCollection($maxlifetime, &$cachedata);
  226.         if ($this->total_size > $this->highwater) {
  227.             krsort($this->entries);
  228.             reset($this->entries);
  229.  
  230.             while ($this->total_size > $this->lowwater && list($size, $entries) = each($this->entries)) {
  231.                 reset($entries);
  232.  
  233.                 while (list($k, $entry) = each($entries)) {
  234.                     unset($cachedata[$entry['group']][$entry['id']]);
  235.                     $this->total_size -= $size;
  236.                 }
  237.             }
  238.         }
  239.  
  240.         if ($lock)
  241.             sem_release($this->sem_id);
  242.  
  243.         $this->entries = array();
  244.         $this->total_size = 0;
  245.  
  246.         return $cachedata;           
  247.     } // end func garbageCollection
  248.  
  249.     function doGarbageCollection($maxlifetime, &$cachedata) {
  250.         $changed = time() - $maxlifetime;
  251.         $removed = 0;
  252.  
  253.         reset($cachedata);
  254.  
  255.         while (list($group, $groupdata) = each($cachedata)) {
  256.             reset($groupdata);
  257.  
  258.             while (list($id, $data) = each($groupdata)) {
  259.                 if ($data['expire'] < time() || $data['changed'] < $changed) {
  260.                     unset($cachedata[$group][$id]);
  261.                 }
  262.             }
  263.  
  264.             // ugly but simple to implement :/
  265.             $size = strlen($this->encode($data));
  266.             $this->entries[$size][] = array('group' => $group,
  267.                                             'id'    => $id
  268.                                            );
  269.  
  270.             $this->total_size += $size;
  271.         }
  272.  
  273.         return $removed;
  274.     }  // end func doGarbageCollection
  275. } // end class Cache_Container_shm
  276. ?>
  277.