2010-08-21 04:43:03 +00:00
< ? php defined ( 'SYSPATH' ) or die ( 'No direct script access.' );
/**
* [ Kohana Cache ]( api / Kohana_Cache ) Memcache driver ,
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* ### Supported cache engines
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* * [ Memcache ]( http :// www . php . net / manual / en / book . memcache . php )
* * [ Memcached - tags ]( http :// code . google . com / p / memcached - tags / )
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* ### Configuration example
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* Below is an example of a _memcache_ server configuration .
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* return array (
* 'default' => array ( // Default group
* 'driver' => 'memcache' , // using Memcache driver
* 'servers' => array ( // Available server definitions
* // First memcache server server
* array (
* 'host' => 'localhost' ,
* 'port' => 11211 ,
* 'persistent' => FALSE
* 'weight' => 1 ,
* 'timeout' => 1 ,
* 'retry_interval' => 15 ,
* 'status' => TRUE ,
2011-05-13 06:00:25 +00:00
* 'instant_death' => TRUE ,
2010-08-21 04:43:03 +00:00
* 'failure_callback' => array ( 'className' , 'classMethod' )
* ),
* // Second memcache server
* array (
* 'host' => '192.168.1.5' ,
* 'port' => 22122 ,
* 'persistent' => TRUE
* )
* ),
* 'compression' => FALSE , // Use compression?
* ),
* )
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* In cases where only one cache group is required , if the group is named `default` there is
* no need to pass the group name when instantiating a cache instance .
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* #### General cache group configuration settings
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* Below are the settings available to all types of cache driver .
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* Name | Required | Description
* -------------- | -------- | ---------------------------------------------------------------
* driver | __YES__ | ( _string_ ) The driver type to use
* servers | __YES__ | ( _array_ ) Associative array of server details , must include a __host__ key . ( see _Memcache server configuration_ below )
* compression | __NO__ | ( _boolean_ ) Use data compression when caching
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* #### Memcache server configuration
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* The following settings should be used when defining each memcache server
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* Name | Required | Description
* ---------------- | -------- | ---------------------------------------------------------------
* host | __YES__ | ( _string_ ) The host of the memcache server , i . e . __localhost__ ; or __127 . 0.0 . 1__ ; or __memcache . domain . tld__
* port | __NO__ | ( _integer_ ) Point to the port where memcached is listening for connections . Set this parameter to 0 when using UNIX domain sockets . Default __11211__
* persistent | __NO__ | ( _boolean_ ) Controls the use of a persistent connection . Default __TRUE__
* weight | __NO__ | ( _integer_ ) Number of buckets to create for this server which in turn control its probability of it being selected . The probability is relative to the total weight of all servers . Default __1__
* timeout | __NO__ | ( _integer_ ) Value in seconds which will be used for connecting to the daemon . Think twice before changing the default value of 1 second - you can lose all the advantages of caching if your connection is too slow . Default __1__
* retry_interval | __NO__ | ( _integer_ ) Controls how often a failed server will be retried , the default value is 15 seconds . Setting this parameter to - 1 disables automatic retry . Default __15__
* status | __NO__ | ( _boolean_ ) Controls if the server should be flagged as online . Default __TRUE__
* failure_callback | __NO__ | ( _ [ callback ]( http :// www . php . net / manual / en / language . pseudo - types . php #language.types.callback)_) Allows the user to specify a callback function to run upon encountering an error. The callback is run before failover is attempted. The function takes two parameters, the hostname and port of the failed server. Default __NULL__
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* ### System requirements
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* * Kohana 3.0 . x
* * PHP 5.2 . 4 or greater
* * Memcache ( plus Memcached - tags for native tagging support )
* * Zlib
2012-11-09 12:18:50 +00:00
*
2011-05-13 06:00:25 +00:00
* @ package Kohana / Cache
* @ category Base
2010-08-21 04:43:03 +00:00
* @ version 2.0
* @ author Kohana Team
2012-11-09 12:18:50 +00:00
* @ copyright ( c ) 2009 - 2012 Kohana Team
2010-08-21 04:43:03 +00:00
* @ license http :// kohanaphp . com / license
*/
2012-11-09 12:18:50 +00:00
class Kohana_Cache_Memcache extends Cache implements Cache_Arithmetic {
2010-08-21 04:43:03 +00:00
// Memcache has a maximum cache lifetime of 30 days
const CACHE_CEILING = 2592000 ;
/**
* Memcache resource
*
* @ var Memcache
*/
protected $_memcache ;
/**
* Flags to use when storing values
*
* @ var string
*/
protected $_flags ;
2011-05-13 06:00:25 +00:00
/**
* The default configuration for the memcached server
*
* @ var array
*/
protected $_default_config = array ();
2010-08-21 04:43:03 +00:00
/**
* Constructs the memcache Kohana_Cache object
*
2012-11-09 12:18:50 +00:00
* @ param array $config configuration
* @ throws Cache_Exception
2010-08-21 04:43:03 +00:00
*/
protected function __construct ( array $config )
{
// Check for the memcache extention
if ( ! extension_loaded ( 'memcache' ))
{
2012-11-09 12:18:50 +00:00
throw new Cache_Exception ( 'Memcache PHP extention not loaded' );
2010-08-21 04:43:03 +00:00
}
parent :: __construct ( $config );
// Setup Memcache
$this -> _memcache = new Memcache ;
// Load servers from configuration
$servers = Arr :: get ( $this -> _config , 'servers' , NULL );
if ( ! $servers )
{
// Throw an exception if no server found
2012-11-09 12:18:50 +00:00
throw new Cache_Exception ( 'No Memcache servers defined in configuration' );
2010-08-21 04:43:03 +00:00
}
// Setup default server configuration
2011-05-13 06:00:25 +00:00
$this -> _default_config = array (
'host' => 'localhost' ,
'port' => 11211 ,
'persistent' => FALSE ,
'weight' => 1 ,
'timeout' => 1 ,
'retry_interval' => 15 ,
'status' => TRUE ,
'instant_death' => TRUE ,
'failure_callback' => array ( $this , '_failed_request' ),
2010-08-21 04:43:03 +00:00
);
// Add the memcache servers to the pool
foreach ( $servers as $server )
{
// Merge the defined config with defaults
2011-05-13 06:00:25 +00:00
$server += $this -> _default_config ;
2010-08-21 04:43:03 +00:00
if ( ! $this -> _memcache -> addServer ( $server [ 'host' ], $server [ 'port' ], $server [ 'persistent' ], $server [ 'weight' ], $server [ 'timeout' ], $server [ 'retry_interval' ], $server [ 'status' ], $server [ 'failure_callback' ]))
{
2012-11-09 12:18:50 +00:00
throw new Cache_Exception ( 'Memcache could not connect to host \':host\' using port \':port\'' , array ( ':host' => $server [ 'host' ], ':port' => $server [ 'port' ]));
2010-08-21 04:43:03 +00:00
}
}
// Setup the flags
$this -> _flags = Arr :: get ( $this -> _config , 'compression' , FALSE ) ? MEMCACHE_COMPRESSED : FALSE ;
}
/**
* Retrieve a cached value entry by id .
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* // Retrieve cache entry from memcache group
* $data = Cache :: instance ( 'memcache' ) -> get ( 'foo' );
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* // Retrieve cache entry from memcache group and return 'bar' if miss
* $data = Cache :: instance ( 'memcache' ) -> get ( 'foo' , 'bar' );
*
2012-11-09 12:18:50 +00:00
* @ param string $id id of cache to entry
* @ param string $default default value to return if cache miss
2010-08-21 04:43:03 +00:00
* @ return mixed
2012-11-09 12:18:50 +00:00
* @ throws Cache_Exception
2010-08-21 04:43:03 +00:00
*/
public function get ( $id , $default = NULL )
{
// Get the value from Memcache
$value = $this -> _memcache -> get ( $this -> _sanitize_id ( $id ));
// If the value wasn't found, normalise it
if ( $value === FALSE )
{
$value = ( NULL === $default ) ? NULL : $default ;
}
// Return the value
return $value ;
}
/**
* Set a value to cache with id and lifetime
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* $data = 'bar' ;
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* // Set 'bar' to 'foo' in memcache group for 10 minutes
* if ( Cache :: instance ( 'memcache' ) -> set ( 'foo' , $data , 600 ))
* {
* // Cache was set successfully
* return
* }
*
2012-11-09 12:18:50 +00:00
* @ param string $id id of cache entry
* @ param mixed $data data to set to cache
* @ param integer $lifetime lifetime in seconds , maximum value 2592000
2010-08-21 04:43:03 +00:00
* @ return boolean
*/
public function set ( $id , $data , $lifetime = 3600 )
{
// If the lifetime is greater than the ceiling
if ( $lifetime > Cache_Memcache :: CACHE_CEILING )
{
// Set the lifetime to maximum cache time
$lifetime = Cache_Memcache :: CACHE_CEILING + time ();
}
// Else if the lifetime is greater than zero
elseif ( $lifetime > 0 )
{
$lifetime += time ();
}
// Else
else
{
// Normalise the lifetime
$lifetime = 0 ;
}
// Set the data to memcache
return $this -> _memcache -> set ( $this -> _sanitize_id ( $id ), $data , $this -> _flags , $lifetime );
}
/**
* Delete a cache entry based on id
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* // Delete the 'foo' cache entry immediately
* Cache :: instance ( 'memcache' ) -> delete ( 'foo' );
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* // Delete the 'bar' cache entry after 30 seconds
* Cache :: instance ( 'memcache' ) -> delete ( 'bar' , 30 );
*
2012-11-09 12:18:50 +00:00
* @ param string $id id of entry to delete
* @ param integer $timeout timeout of entry , if zero item is deleted immediately , otherwise the item will delete after the specified value in seconds
2010-08-21 04:43:03 +00:00
* @ return boolean
*/
public function delete ( $id , $timeout = 0 )
{
// Delete the id
return $this -> _memcache -> delete ( $this -> _sanitize_id ( $id ), $timeout );
}
/**
* Delete all cache entries .
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* Beware of using this method when
* using shared memory cache systems , as it will wipe every
* entry within the system for all clients .
2012-11-09 12:18:50 +00:00
*
2010-08-21 04:43:03 +00:00
* // Delete all cache entries in the default group
* Cache :: instance ( 'memcache' ) -> delete_all ();
*
* @ return boolean
*/
public function delete_all ()
{
$result = $this -> _memcache -> flush ();
// We must sleep after flushing, or overwriting will not work!
// @see http://php.net/manual/en/function.memcache-flush.php#81420
sleep ( 1 );
return $result ;
}
/**
* Callback method for Memcache :: failure_callback to use if any Memcache call
* on a particular server fails . This method switches off that instance of the
* server if the configuration setting `instant_death` is set to `TRUE` .
*
2012-11-09 12:18:50 +00:00
* @ param string $hostname
* @ param integer $port
2010-08-21 04:43:03 +00:00
* @ return void | boolean
* @ since 3.0 . 8
*/
2011-05-13 06:00:25 +00:00
public function _failed_request ( $hostname , $port )
2010-08-21 04:43:03 +00:00
{
if ( ! $this -> _config [ 'instant_death' ])
2012-11-09 12:18:50 +00:00
return ;
2010-08-21 04:43:03 +00:00
// Setup non-existent host
$host = FALSE ;
// Get host settings from configuration
foreach ( $this -> _config [ 'servers' ] as $server )
{
2011-05-13 06:00:25 +00:00
// Merge the defaults, since they won't always be set
$server += $this -> _default_config ;
// We're looking at the failed server
2010-08-21 04:43:03 +00:00
if ( $hostname == $server [ 'host' ] and $port == $server [ 'port' ])
{
2011-05-13 06:00:25 +00:00
// Server to disable, since it failed
2010-08-21 04:43:03 +00:00
$host = $server ;
continue ;
}
}
if ( ! $host )
return ;
else
{
return $this -> _memcache -> setServerParams (
$host [ 'host' ],
$host [ 'port' ],
$host [ 'timeout' ],
$host [ 'retry_interval' ],
2011-05-13 06:00:25 +00:00
FALSE , // Server is offline
2010-08-21 04:43:03 +00:00
array ( $this , '_failed_request'
));
}
}
2012-11-09 12:18:50 +00:00
/**
* Increments a given value by the step value supplied .
* Useful for shared counters and other persistent integer based
* tracking .
*
* @ param string id of cache entry to increment
* @ param int step value to increment by
* @ return integer
* @ return boolean
*/
public function increment ( $id , $step = 1 )
{
return $this -> _memcache -> increment ( $id , $step );
}
/**
* Decrements a given value by the step value supplied .
* Useful for shared counters and other persistent integer based
* tracking .
*
* @ param string id of cache entry to decrement
* @ param int step value to decrement by
* @ return integer
* @ return boolean
*/
public function decrement ( $id , $step = 1 )
{
return $this -> _memcache -> decrement ( $id , $step );
}
2010-08-21 04:43:03 +00:00
}