Source for file memcached.php

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

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