Source for file memcache.php

Documentation is available at memcache.php

  1. <?php
  2. /**
  3.  * @package     Joomla.Platform
  4.  * @subpackage  Cache
  5.  *
  6.  * @copyright   Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7.  * @license     GNU General Public License version 2 or later; see LICENSE
  8.  */
  9.  
  10. defined('JPATH_PLATFORM'or die;
  11.  
  12. /**
  13.  * Memcache cache storage handler
  14.  *
  15.  * @package     Joomla.Platform
  16.  * @subpackage  Cache
  17.  * @see         http://php.net/manual/en/book.memcache.php
  18.  * @since       11.1
  19.  */
  20. {
  21.     /**
  22.      * Memcache connection object
  23.      *
  24.      * @var    Memcache 
  25.      * @since  11.1
  26.      */
  27.     protected static $_db null;
  28.  
  29.     /**
  30.      * Persistent session flag
  31.      *
  32.      * @var    boolean 
  33.      * @since  11.1
  34.      */
  35.     protected $_persistent = false;
  36.  
  37.     /**
  38.      * Payload compression level
  39.      *
  40.      * @var    integer 
  41.      * @since  11.1
  42.      */
  43.     protected $_compress = 0;
  44.  
  45.     /**
  46.      * Constructor
  47.      *
  48.      * @param   array  $options  Optional parameters.
  49.      *
  50.      * @since   11.1
  51.      */
  52.     public function __construct($options array())
  53.     {
  54.         parent::__construct($options);
  55.         if (self::$_db === null)
  56.         {
  57.             $this->getConnection();
  58.         }
  59.     }
  60.  
  61.     /**
  62.      * Return memcache connection object
  63.      *
  64.      * @return  object   memcache connection object
  65.      *
  66.      * @since   11.1
  67.      * @throws  RuntimeException
  68.      */
  69.     protected function getConnection()
  70.     {
  71.         if ((extension_loaded('memcache'&& class_exists('Memcache')) != true)
  72.         {
  73.             return false;
  74.         }
  75.  
  76.         $config JFactory::getConfig();
  77.         $this->_persistent = $config->get('memcache_persist'true);
  78.         $this->_compress = $config->get('memcache_compress'false== false MEMCACHE_COMPRESSED;
  79.  
  80.         /*
  81.          * This will be an array of loveliness
  82.          * @todo: multiple servers
  83.          * $servers    = (isset($params['servers'])) ? $params['servers'] : array();
  84.          */
  85.         $server array();
  86.         $server['host'$config->get('memcache_server_host''localhost');
  87.         $server['port'$config->get('memcache_server_port'11211);
  88.  
  89.         // Create the memcache connection
  90.         self::$_db new Memcache;
  91.         self::$_db->addServer($server['host']$server['port']$this->_persistent);
  92.  
  93.         $memcachetest @self::$_db->connect($server['host']$server['port']);
  94.         if ($memcachetest == false)
  95.         {
  96.             throw new RuntimeException('Could not connect to memcache server'404);
  97.         }
  98.  
  99.         // Memcahed has no list keys, we do our own accounting, initialise key index
  100.         if (self::$_db->get($this->_hash . '-index'=== false)
  101.         {
  102.             $empty array();
  103.             self::$_db->set($this->_hash . '-index'$empty$this->_compress0);
  104.         }
  105.  
  106.         return;
  107.     }
  108.  
  109.     /**
  110.      * Get cached data from memcache by id and group
  111.      *
  112.      * @param   string   $id         The cache data id
  113.      * @param   string   $group      The cache data group
  114.      * @param   boolean  $checkTime  True to verify cache time expiration threshold
  115.      *
  116.      * @return  mixed  Boolean false on failure or a cached data string
  117.      *
  118.      * @since   11.1
  119.      */
  120.     public function get($id$group$checkTime true)
  121.     {
  122.         $cache_id $this->_getCacheId($id$group);
  123.         $back self::$_db->get($cache_id);
  124.         return $back;
  125.     }
  126.  
  127.     /**
  128.      * Get all cached data
  129.      *
  130.      * @return  array    data
  131.      *
  132.      * @since   11.1
  133.      */
  134.     public function getAll()
  135.     {
  136.         parent::getAll();
  137.  
  138.         $keys self::$_db->get($this->_hash . '-index');
  139.         $secret $this->_hash;
  140.  
  141.         $data array();
  142.  
  143.         if (!empty($keys))
  144.         {
  145.             foreach ($keys as $key)
  146.             {
  147.                 if (empty($key))
  148.                 {
  149.                     continue;
  150.                 }
  151.                 $namearr explode('-'$key->name);
  152.  
  153.                 if ($namearr !== false && $namearr[0== $secret && $namearr[1== 'cache')
  154.                 {
  155.  
  156.                     $group $namearr[2];
  157.  
  158.                     if (!isset($data[$group]))
  159.                     {
  160.                         $item new JCacheStorageHelper($group);
  161.                     }
  162.                     else
  163.                     {
  164.                         $item $data[$group];
  165.                     }
  166.  
  167.                     $item->updateSize($key->size 1024);
  168.  
  169.                     $data[$group$item;
  170.                 }
  171.             }
  172.         }
  173.  
  174.         return $data;
  175.     }
  176.  
  177.     /**
  178.      * Store the data to memcache by id and group
  179.      *
  180.      * @param   string  $id     The cache data id
  181.      * @param   string  $group  The cache data group
  182.      * @param   string  $data   The data to store in cache
  183.      *
  184.      * @return  boolean  True on success, false otherwise
  185.      *
  186.      * @since   11.1
  187.      */
  188.     public function store($id$group$data)
  189.     {
  190.         $cache_id $this->_getCacheId($id$group);
  191.  
  192.         if (!$this->lockindex())
  193.         {
  194.             return false;
  195.         }
  196.  
  197.         $index self::$_db->get($this->_hash . '-index');
  198.         if ($index === false)
  199.         {
  200.             $index array();
  201.         }
  202.  
  203.         $tmparr new stdClass;
  204.         $tmparr->name $cache_id;
  205.         $tmparr->size strlen($data);
  206.  
  207.         $config JFactory::getConfig();
  208.         $lifetime = (int) $config->get('cachetime'15);
  209.         if ($this->_lifetime == $lifetime)
  210.         {
  211.             $this->_lifetime = $lifetime 60;
  212.         }
  213.  
  214.         $index[$tmparr;
  215.         self::$_db->replace($this->_hash . '-index'$index00);
  216.         $this->unlockindex();
  217.  
  218.         // Prevent double writes, write only if it doesn't exist else replace
  219.         if (!self::$_db->replace($cache_id$data$this->_compress$this->_lifetime))
  220.         {
  221.             self::$_db->set($cache_id$data$this->_compress$this->_lifetime);
  222.         }
  223.  
  224.         return true;
  225.     }
  226.  
  227.     /**
  228.      * Remove a cached data entry by id and group
  229.      *
  230.      * @param   string  $id     The cache data id
  231.      * @param   string  $group  The cache data group
  232.      *
  233.      * @return  boolean  True on success, false otherwise
  234.      *
  235.      * @since   11.1
  236.      */
  237.     public function remove($id$group)
  238.     {
  239.         $cache_id $this->_getCacheId($id$group);
  240.  
  241.         if (!$this->lockindex())
  242.         {
  243.             return false;
  244.         }
  245.  
  246.         $index self::$_db->get($this->_hash . '-index');
  247.         if ($index === false)
  248.         {
  249.             $index array();
  250.         }
  251.  
  252.         foreach ($index as $key => $value)
  253.         {
  254.             if ($value->name == $cache_id)
  255.             {
  256.                 unset($index[$key]);
  257.             }
  258.             break;
  259.         }
  260.         self::$_db->replace($this->_hash . '-index'$index00);
  261.         $this->unlockindex();
  262.  
  263.         return self::$_db->delete($cache_id);
  264.     }
  265.  
  266.     /**
  267.      * Clean cache for a group given a mode.
  268.      *
  269.      * @param   string  $group  The cache data group
  270.      * @param   string  $mode   The mode for cleaning cache [group|notgroup]
  271.      *  group mode    : cleans all cache in the group
  272.      *  notgroup mode : cleans all cache not in the group
  273.      *
  274.      * @return  boolean  True on success, false otherwise
  275.      *
  276.      * @since   11.1
  277.      */
  278.     public function clean($group$mode null)
  279.     {
  280.         if (!$this->lockindex())
  281.         {
  282.             return false;
  283.         }
  284.  
  285.         $index self::$_db->get($this->_hash . '-index');
  286.         if ($index === false)
  287.         {
  288.             $index array();
  289.         }
  290.  
  291.         $secret $this->_hash;
  292.         foreach ($index as $key => $value)
  293.         {
  294.  
  295.             if (strpos($value->name$secret '-cache-' $group '-'=== xor $mode != 'group')
  296.             {
  297.                 self::$_db->delete($value->name0);
  298.                 unset($index[$key]);
  299.             }
  300.         }
  301.         self::$_db->replace($this->_hash . '-index'$index00);
  302.         $this->unlockindex();
  303.         return true;
  304.     }
  305.  
  306.     /**
  307.      * Test to see if the cache storage is available.
  308.      *
  309.      * @return  boolean  True on success, false otherwise.
  310.      *
  311.      * @since   12.1
  312.      */
  313.     public static function isSupported()
  314.     {
  315.         if ((extension_loaded('memcache'&& class_exists('Memcache')) != true)
  316.         {
  317.             return false;
  318.         }
  319.  
  320.         $config JFactory::getConfig();
  321.         $host $config->get('memcache_server_host''localhost');
  322.         $port $config->get('memcache_server_port'11211);
  323.  
  324.         $memcache new Memcache;
  325.         $memcachetest @$memcache->connect($host$port);
  326.  
  327.         if (!$memcachetest)
  328.         {
  329.             return false;
  330.         }
  331.         else
  332.         {
  333.             return true;
  334.         }
  335.     }
  336.  
  337.     /**
  338.      * Lock cached item - override parent as this is more efficient
  339.      *
  340.      * @param   string   $id        The cache data id
  341.      * @param   string   $group     The cache data group
  342.      * @param   integer  $locktime  Cached item max lock time
  343.      *
  344.      * @return  boolean  True on success, false otherwise.
  345.      *
  346.      * @since   11.1
  347.      */
  348.     public function lock($id$group$locktime)
  349.     {
  350.         $returning new stdClass;
  351.         $returning->locklooped false;
  352.  
  353.         $looptime $locktime 10;
  354.  
  355.         $cache_id $this->_getCacheId($id$group);
  356.  
  357.         if (!$this->lockindex())
  358.         {
  359.             return false;
  360.         }
  361.  
  362.         $index self::$_db->get($this->_hash . '-index');
  363.         if ($index === false)
  364.         {
  365.             $index array();
  366.         }
  367.  
  368.         $tmparr new stdClass;
  369.         $tmparr->name $cache_id;
  370.         $tmparr->size 1;
  371.         $index[$tmparr;
  372.         self::$_db->replace($this->_hash . '-index'$index00);
  373.         $this->unlockindex();
  374.  
  375.         $data_lock self::$_db->add($cache_id '_lock'1false$locktime);
  376.  
  377.         if ($data_lock === false)
  378.         {
  379.  
  380.             $lock_counter 0;
  381.  
  382.             // Loop until you find that the lock has been released.
  383.             // That implies that data get from other thread has finished
  384.             while ($data_lock === false)
  385.             {
  386.  
  387.                 if ($lock_counter $looptime)
  388.                 {
  389.                     $returning->locked false;
  390.                     $returning->locklooped true;
  391.                     break;
  392.                 }
  393.  
  394.                 usleep(100);
  395.                 $data_lock self::$_db->add($cache_id '_lock'1false$locktime);
  396.                 $lock_counter++;
  397.             }
  398.  
  399.         }
  400.         $returning->locked $data_lock;
  401.  
  402.         return $returning;
  403.     }
  404.  
  405.     /**
  406.      * Unlock cached item - override parent for cacheid compatibility with lock
  407.      *
  408.      * @param   string  $id     The cache data id
  409.      * @param   string  $group  The cache data group
  410.      *
  411.      * @return  boolean  True on success, false otherwise.
  412.      *
  413.      * @since   11.1
  414.      */
  415.     public function unlock($id$group null)
  416.     {
  417.         $cache_id $this->_getCacheId($id$group'_lock';
  418.  
  419.         if (!$this->lockindex())
  420.         {
  421.             return false;
  422.         }
  423.  
  424.         $index self::$_db->get($this->_hash . '-index');
  425.         if ($index === false)
  426.         {
  427.             $index array();
  428.         }
  429.  
  430.         foreach ($index as $key => $value)
  431.         {
  432.             if ($value->name == $cache_id)
  433.             {
  434.                 unset($index[$key]);
  435.             }
  436.             break;
  437.         }
  438.         self::$_db->replace($this->_hash . '-index'$index00);
  439.         $this->unlockindex();
  440.  
  441.         return self::$_db->delete($cache_id);
  442.     }
  443.  
  444.     /**
  445.      * Lock cache index
  446.      *
  447.      * @return  boolean  True on success, false otherwise.
  448.      *
  449.      * @since   11.1
  450.      */
  451.     protected function lockindex()
  452.     {
  453.         $looptime 300;
  454.         $data_lock self::$_db->add($this->_hash . '-index_lock'1false30);
  455.  
  456.         if ($data_lock === false)
  457.         {
  458.  
  459.             $lock_counter 0;
  460.  
  461.             // Loop until you find that the lock has been released.  that implies that data get from other thread has finished
  462.             while ($data_lock === false)
  463.             {
  464.                 if ($lock_counter $looptime)
  465.                 {
  466.                     return false;
  467.                     break;
  468.                 }
  469.  
  470.                 usleep(100);
  471.                 $data_lock self::$_db->add($this->_hash . '-index_lock'1false30);
  472.                 $lock_counter++;
  473.             }
  474.         }
  475.  
  476.         return true;
  477.     }
  478.  
  479.     /**
  480.      * Unlock cache index
  481.      *
  482.      * @return  boolean  True on success, false otherwise.
  483.      *
  484.      * @since   11.1
  485.      */
  486.     protected function unlockindex()
  487.     {
  488.         return self::$_db->delete($this->_hash . '-index_lock');
  489.     }
  490. }

Documentation generated on Tue, 19 Nov 2013 15:07:46 +0100 by phpDocumentor 1.4.3