Source for file Ethna_Plugin_Cachemanager_Memcache.php

Documentation is available at Ethna_Plugin_Cachemanager_Memcache.php

  1. <?php
  2. // vim: foldmethod=marker tabstop=4 shiftwidth=4 autoindent
  3. /**
  4.  *  Ethna_Plugin_Cachemanager_Memcache.php
  5.  *
  6.  *  - Point Cutしたいと思った!
  7.  *  - キャッシュキーには250文字までしか使用できないので注意して下さい
  8.  *
  9.  *  @todo   ネームスペース/キャッシュキー長のエラーハンドリング
  10.  *
  11.  *  @author     Masaki Fujimoto <fujimoto@php.net>
  12.  *  @package    Ethna
  13.  *  @version    $Id$
  14.  */
  15.  
  16. /**
  17.  *  キャッシュマネージャクラス(memcache版)
  18.  *
  19.  *  @author     Masaki Fujimoto <fujimoto@php.net>
  20.  *  @access     public
  21.  *  @package    Ethna
  22.  */
  23. {
  24.     /**#@+  @access private */
  25.  
  26.     /** @var    object  MemCache    MemCacheオブジェクト */
  27.     var $memcache null;
  28.  
  29.     /** @var bool 圧縮フラグ */
  30.     var $compress true;
  31.  
  32.     /**#@-*/
  33.  
  34.     /**
  35.      *  Ethna_Plugin_Cachemanager_Memcacheクラスのコンストラクタ
  36.      *
  37.      *  @access public
  38.      */
  39.     function Ethna_Plugin_Cachemanager_Memcache(&$controller)
  40.     {
  41.         parent::Ethna_Plugin_Cachemanager($controller);
  42.         $this->memcache_pool array();
  43.     }
  44.  
  45.     /**
  46.      *  memcacheキャッシュオブジェクトを生成、取得する
  47.      *
  48.      *  @access protected
  49.      */
  50.     function _getMemcache($cache_key$namespace null)
  51.     {
  52.         $retry $this->config->get('memcache_retry');
  53.         if ($retry == ""{
  54.             $retry 3;
  55.         }
  56.         $timeout $this->config->get('memcache_timeout');
  57.         if ($timeout == ""{
  58.             $timeout 3;
  59.         }
  60.         $r false;
  61.  
  62.         list($host$port$this->_getMemcacheInfo($cache_key$namespace);
  63.         if (isset($this->memcache_pool["$host:$port"])) {
  64.             // activate
  65.             $this->memcache $this->memcache_pool["$host:$port"];
  66.             return $this->memcache;
  67.         }
  68.         $this->memcache_pool["$host:$port"=new MemCache();
  69.  
  70.         while ($retry 0{
  71.             if ($this->config->get('memcache_use_pconnect')) {
  72.                 $r $this->memcache_pool["$host:$port"]->pconnect($host$port$timeout);
  73.             else {
  74.                 $r $this->memcache_pool["$host:$port"]->connect($host$port$timeout);
  75.             }
  76.             if ($r{
  77.                 break;
  78.             }
  79.             sleep(1);
  80.             $retry--;
  81.         }
  82.         if ($r == false{
  83.             trigger_error("memcache: connection failed");
  84.             $this->memcache_pool["$host:$port"null;
  85.         }
  86.  
  87.         $this->memcache $this->memcache_pool["$host:$port"];
  88.         return $this->memcache;
  89.     }
  90.  
  91.     /**
  92.      *  memcache接続情報を取得する
  93.      *
  94.      *  @access protected
  95.      *  @todo   $cache_keyから$indexを決める方法を変更できるようにする
  96.      */
  97.     function _getMemcacheInfo($cache_key$namespace)
  98.     {
  99.         $namespace is_null($namespace$this->namespace $namespace;
  100.  
  101.         $memcache_info $this->config->get('memcache');
  102.         $default_memcache_host $this->config->get('memcache_host');
  103.         if ($default_memcache_host == ""{
  104.             $default_memcache_host "localhost";
  105.         }
  106.         $default_memcache_port $this->config->get('memcache_port');
  107.         if ($default_memcache_port == ""{
  108.             $default_memcache_port 11211;
  109.         }
  110.         if ($memcache_info == null || isset($memcache_info[$namespace]== false{
  111.             return array($default_memcache_host$default_memcache_port);
  112.         }
  113.  
  114.         // namespace/cache_keyで接続先を決定
  115.         $n count($memcache_info[$namespace]);
  116.  
  117.         $index $cache_key $n;
  118.         return array(
  119.             isset($memcache_info[$namespace][$index]['memcache_host']?
  120.                 $memcache_info[$namespace][$index]['memcache_host':
  121.                 'localhost',
  122.             isset($memcache_info[$namespace][$index]['memcache_port']?
  123.                 $memcache_info[$namespace][$index]['memcache_port':
  124.                 11211,
  125.         );
  126.  
  127.         // for safe
  128.         return array($default_memcache_host$default_memcache_port);
  129.     }
  130.  
  131.     /**
  132.      *  キャッシュに設定された値を取得する
  133.      *
  134.      *  キャッシュに値が設定されている場合はキャッシュ値
  135.      *  が戻り値となる。キャッシュに値が無い場合やlifetime
  136.      *  を過ぎている場合、エラーが発生した場合はEthna_Error
  137.      *  オブジェクトが戻り値となる。
  138.      *
  139.      *  @access public
  140.      *  @param  string  $key        キャッシュキー
  141.      *  @param  int     $lifetime   キャッシュ有効期間
  142.      *  @param  string  $namespace  キャッシュネームスペース
  143.      *  @return array   キャッシュ値
  144.      */
  145.     function get($key$lifetime null$namespace null)
  146.     {
  147.         $this->_getMemcache($key$namespace);
  148.         if ($this->memcache == null{
  149.             return Ethna::raiseError('memcache server not available'E_CACHE_NO_VALUE);
  150.         }
  151.  
  152.         $namespace is_null($namespace$this->namespace $namespace;
  153.  
  154.         $cache_key $this->_getCacheKey($namespace$key);
  155.         if ($cache_key == null{
  156.             return Ethna::raiseError('invalid cache key (too long?)'E_CACHE_NO_VALUE);
  157.         }
  158.  
  159.         $value $this->memcache->get($cache_key);
  160.         if ($value == null{
  161.             return Ethna::raiseError('no such cache'E_CACHE_NO_VALUE);
  162.         }
  163.         $time $value['time'];
  164.         $data $value['data'];
  165.  
  166.         // ライフタイムチェック
  167.         if (is_null($lifetime== false{
  168.             if (($time+$lifetimetime()) {
  169.                 return Ethna::raiseError('lifetime expired'E_CACHE_EXPIRED);
  170.             }
  171.         }
  172.  
  173.         return $data;
  174.     }
  175.  
  176.     /**
  177.      *  キャッシュの最終更新日時を取得する
  178.      *
  179.      *  @access public
  180.      *  @param  string  $key        キャッシュキー
  181.      *  @param  string  $namespace  キャッシュネームスペース
  182.      *  @return int     最終更新日時(unixtime)
  183.      */
  184.     function getLastModified($key$namespace null)
  185.     {
  186.         $this->_getMemcache($key$namespace);
  187.         if ($this->memcache == null{
  188.             return Ethna::raiseError('memcache server not available'E_CACHE_NO_VALUE);
  189.         }
  190.  
  191.         $namespace is_null($namespace$this->namespace $namespace;
  192.  
  193.         $cache_key $this->_getCacheKey($namespace$key);
  194.         if ($cache_key == null{
  195.             return Ethna::raiseError('invalid cache key (too long?)'E_CACHE_NO_VALUE);
  196.         }
  197.  
  198.         $value $this->memcache->get($cache_key);
  199.  
  200.         return $value['time'];
  201.     }
  202.  
  203.     /**
  204.      *  値がキャッシュされているかどうかを取得する
  205.      *
  206.      *  @access public
  207.      *  @param  string  $key        キャッシュキー
  208.      *  @param  int     $lifetime   キャッシュ有効期間
  209.      *  @param  string  $namespace  キャッシュネームスペース
  210.      */
  211.     function isCached($key$lifetime null$namespace null)
  212.     {
  213.         $r $this->get($key$lifetime$namespace);
  214.  
  215.         return Ethna::isError($rfalsetrue;
  216.     }
  217.  
  218.     /**
  219.      *  キャッシュに値を設定する
  220.      *
  221.      *  @access public
  222.      *  @param  string  $key        キャッシュキー
  223.      *  @param  mixed   $value      キャッシュ値
  224.      *  @param  int     $timestamp  キャッシュ最終更新時刻(unixtime)
  225.      *  @param  string  $namespace  キャッシュネームスペース
  226.      */
  227.     function set($key$value$timestamp null$namespace null)
  228.     {
  229.         $this->_getMemcache($key$namespace);
  230.         if ($this->memcache == null{
  231.             return Ethna::raiseError('memcache server not available'E_CACHE_NO_VALUE);
  232.         }
  233.  
  234.         $namespace is_null($namespace$this->namespace $namespace;
  235.  
  236.         $cache_key $this->_getCacheKey($namespace$key);
  237.         if ($cache_key == null{
  238.             return Ethna::raiseError('invalid cache key (too long?)'E_CACHE_NO_VALUE);
  239.         }
  240.  
  241.         $time $timestamp $timestamp time();
  242.         $this->memcache->set($cache_keyarray('time' => $time'data' => $value)$this->compress MEMCACHE_COMPRESSED null);
  243.     }
  244.  
  245.     /**
  246.      *  キャッシュ値を削除する
  247.      *
  248.      *  @access public
  249.      *  @param  string  $key        キャッシュキー
  250.      *  @param  string  $namespace  キャッシュネームスペース
  251.      */
  252.     function clear($key$namespace null)
  253.     {
  254.         $this->_getMemcache($key$namespace);
  255.         if ($this->memcache == null{
  256.             return Ethna::raiseError('memcache server not available'E_CACHE_NO_VALUE);
  257.         }
  258.  
  259.         $namespace is_null($namespace$this->namespace $namespace;
  260.  
  261.         $cache_key $this->_getCacheKey($namespace$key);
  262.         if ($cache_key == null{
  263.             return Ethna::raiseError('invalid cache key (too long?)'E_CACHE_NO_VALUE);
  264.         }
  265.  
  266.         $this->memcache->delete($cache_key-1);
  267.     }
  268.  
  269.     /**
  270.      *  キャッシュデータをロックする
  271.      *
  272.      *  @access public
  273.      *  @param  string  $key        キャッシュキー
  274.      *  @param  int     $timeout    ロックタイムアウト
  275.      *  @param  string  $namespace  キャッシュネームスペース
  276.      *  @return bool    true:成功 false:失敗
  277.      */
  278.     function lock($key$timeout 5$namespace null)
  279.     {
  280.         $this->_getMemcache($key$namespace);
  281.         if ($this->memcache == null{
  282.             return Ethna::raiseError('memcache server not available'E_CACHE_LOCK_ERROR);
  283.         }
  284.  
  285.         // ロック用キャッシュデータを利用する
  286.         $namespace is_null($namespace$this->namespace $namespace;
  287.         $cache_key "lock::" $this->_getCacheKey($namespace$key);
  288.         $lock_lifetime 30;
  289.  
  290.         do {
  291.             $r $this->memcache->add($cache_keytruefalse$lock_lifetime);
  292.             if ($r != false{
  293.                 break;
  294.             }
  295.             sleep(1);
  296.             $timeout--;
  297.         while ($timeout 0);
  298.  
  299.         if ($r == false{
  300.             return Ethna::raiseError('lock timeout'E_CACHE_LOCK_TIMEOUT);
  301.         }
  302.  
  303.         return true;
  304.     }
  305.  
  306.     /**
  307.      *  キャッシュデータのロックを解除する
  308.      *
  309.      *  @access public
  310.      *  @param  string  $key        キャッシュキー
  311.      *  @param  string  $namespace  キャッシュネームスペース
  312.      *  @return bool    true:成功 false:失敗
  313.      */
  314.     function unlock($key$namespace null)
  315.     {
  316.         $this->_getMemcache($key$namespace);
  317.         if ($this->memcache == null{
  318.             return Ethna::raiseError('memcache server not available'E_CACHE_LOCK_ERROR);
  319.         }
  320.  
  321.         $namespace is_null($namespace$this->namespace $namespace;
  322.         $cache_key "lock::" $this->_getCacheKey($namespace$key);
  323.  
  324.         $this->memcache->delete($cache_key-1);
  325.     }
  326.  
  327.     /**
  328.      *  ネームスペースからキャッシュキーを生成する
  329.      *
  330.      *  @access private
  331.      */
  332.     function _getCacheKey($namespace$key)
  333.     {
  334.         // 少し乱暴だけど...
  335.         $key str_replace(":""_"$key);
  336.         $cache_key $namespace "::" $key;
  337.         if (strlen($cache_key250{
  338.             return null;
  339.         }
  340.         return $cache_key;
  341.     }
  342.  
  343.     /**
  344.      * 圧縮フラグを立てる
  345.      *
  346.      * MySQLなどいくつかの子クラスで有効
  347.      * 
  348.      * @access public
  349.      * @param bool $flag フラグ
  350.      */
  351.     function setCompress($flag{
  352.         $this->compress $flag;
  353.     }
  354. }
  355. ?>

Documentation generated on Fri, 11 Nov 2011 04:00:08 +0900 by phpDocumentor 1.4.3