Cache
[ class tree: Cache ] [ index: Cache ] [ all elements ]

Source for file shm.php

Documentation is available at shm.php

  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.6 2005/05/25 10:00:41 dufuz 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.6 2005/05/25 10:00:41 dufuz Exp $
  33. @package  Cache
  34. */
  35. {
  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.     {
  110.         if (is_array($options)) {
  111.             $this->setOptions($optionsarray_merge($this->allowed_options
  112.                                                     array('shm_key',  'sem_key'
  113.                                                           'shm_size''sem_perm',
  114.                                                           'shm_perm'
  115.                                                          )
  116.                                         )
  117.                                );
  118.         }
  119.         // Cache::Container high- and lowwater defaults should be overridden if
  120.         // not already done by the user
  121.         if (!isset($options['highwater'])) 
  122.             $this->highwater = round(0.75 * 131072);
  123.         }
  124.         if (!isset($options['lowwater'])) {
  125.             $this->lowwater = round(0.5 * 131072);
  126.         }
  127.         if (!isset($options['shm_size'])) {
  128.             $this->shm_size = 131072;
  129.         }
  130.         //get SHM and Semaphore handles
  131.         if (!($this->shm_id = shmop_open($this->shm_key'c'$this->shm_perm$this->shm_size))) {
  132.             new Cache_Error("Can't open SHM segment '{$this->shm_key}', size '{$this->shm_size}'.",
  133.                             __FILE__,
  134.                             __LINE__
  135.                            );
  136.         }
  137.         if (!($this->sem_id = sem_get($this->sem_key1$this->sem_perm))) {
  138.             new Cache_Error("Can't get semaphore '{$this->sem_key}' using perms '{$this->sem_perm}'.",
  139.                             __FILE__,
  140.                             __LINE__
  141.                            );
  142.         }
  143.     } // end constructor
  144.     function fetch($id, $group)
  145.     {
  146.         sem_acquire($this->sem_id);
  147.  
  148.         $cachedata = shmop_read($this->shm_id0$this->shm_size);
  149.  
  150.         sem_release($this->sem_id);
  151.  
  152.         $cachedata $this->decode($cachedata);
  153.  
  154.         if (!isset($cachedata[$group][$id])) {
  155.             return array(null, null, null);
  156.         } else {
  157.             $cachedata = $cachedata[$group][$id];
  158.         }
  159.         return array($cachedata['expire'],
  160.                      $cachedata['cachedata'],
  161.                      $cachedata['userdata']
  162.                     );
  163.     } // end func fetch
  164.     function save($id, $data, $expire, $group, $userdata)
  165.     {
  166.         $this->flushPreload($id$group);
  167.  
  168.         sem_acquire($this->sem_id);
  169.  
  170.         $cachedata $this->decode(shmop_read($this->shm_id0$this->shm_size));
  171.         $cachedata[$group][$id= array('expire'    => $this->getExpiresAbsolute($expire),
  172.                                         'cachedata' => $data,
  173.                                         'userdata'  => $userdata,
  174.                                         'changed'   => time()
  175.                                        );
  176.  
  177.         if (strlen($newdata $this->encode($cachedata)) $this->shm_size{
  178.             $cachedata = $this->garbageCollection(time()$cachedata);
  179.         }
  180.         shmop_write($this->shm_id$newdata0);
  181.  
  182.         sem_release($this->sem_id);
  183.  
  184.         return true;
  185.     } // end func save
  186.     function remove($id, $group)
  187.     {
  188.         $this->flushPreload($id$group);
  189.  
  190.         sem_acquire($this->sem_id);
  191.  
  192.         $cachedata $this->decode(shmop_read($this->shm_id0$this->shm_size));
  193.         unset($cachedata[$group][$id]);
  194.         shmop_write($this->shm_id$this->encode($cachedata)0);
  195.  
  196.         sem_release($this->sem_id);
  197.     } // end func remove
  198.     function flush($group = '')
  199.     {
  200.         $this->flushPreload();
  201.  
  202.         sem_acquire($this->sem_id);
  203.  
  204.         shmop_write($this->shm_id$this->encode(array())0);
  205.  
  206.         sem_release($this->sem_id);
  207.     } // end func flush
  208.     function idExists($id, $group)
  209.     {
  210.         sem_acquire($this->sem_id);
  211.  
  212.         $cachedata = shm_read($this->shm_id0$this->shm_size);
  213.  
  214.         sem_release($this->sem_id);
  215.  
  216.         $cachedata $this->decode($cachedata);
  217.  
  218.         return isset($cachedata[$group][$id]);
  219.     } // end func isExists
  220.     function garbageCollection($maxlifetime, $cachedata = array())
  221.     {
  222.         if ($lock = empty($cachedata)) {
  223.             sem_acquire($this->sem_id);
  224.             $cachedata $this->decode(shmop_read($this->shm_id0$this->shm_size));
  225.         }
  226.  
  227.         $this->doGarbageCollection($maxlifetime$cachedata);
  228.         if ($this->total_size > $this->highwater{
  229.             krsort($this->entries);
  230.             reset($this->entries);
  231.  
  232.             while ($this->total_size > $this->lowwater && list($size$entries= each($this->entries)) {
  233.                 reset($entries);
  234.  
  235.                 while (list($k, $entry) = each($entries)) {
  236.                     unset($cachedata[$entry['group']][$entry['id']]);
  237.                     $this->total_size -= $size;
  238.                 }
  239.             }
  240.         }
  241.  
  242.         if ($lock) {
  243.             sem_release($this->sem_id);
  244.         }
  245.         $this->entries = array();
  246.         $this->total_size = 0;
  247.  
  248.         return $cachedata;           
  249.     } // end func garbageCollection
  250.     function doGarbageCollection($maxlifetime, &$cachedata)
  251.     {
  252.         $changed = time() - $maxlifetime;
  253.         $removed = 0;
  254.  
  255.         reset($cachedata);
  256.  
  257.         while (list($group, $groupdata) = each($cachedata)) {
  258.             reset($groupdata);
  259.  
  260.             while (list($id, $data) = each($groupdata)) {
  261.                 if ($data['expire'] < time() || $data['changed'] < $changed) {
  262.                     unset($cachedata[$group][$id]);
  263.                 }
  264.             }
  265.  
  266.             // ugly but simple to implement :/
  267.             $size = strlen($this->encode($data));
  268.             $this->entries[$size][= array(
  269.                 'group' => $group,
  270.                 'id'    => $id
  271.             );
  272.  
  273.             $this->total_size += $size;
  274.         }
  275.  
  276.         return $removed;
  277.     }  // end func doGarbageCollection
  278. } // end class Cache_Container_shm

Documentation generated on Mon, 11 Mar 2019 15:25:51 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.