123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- <?php
- /**
- * [Kohana Cache](api/Kohana_Cache) Memcache driver,
- *
- * ### Supported cache engines
- *
- * * [Memcache](http://www.php.net/manual/en/book.memcache.php)
- * * [Memcached-tags](http://code.google.com/p/memcached-tags/)
- *
- * ### Configuration example
- *
- * Below is an example of a _memcache_ server configuration.
- *
- * 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,
- * 'instant_death' => TRUE,
- * 'failure_callback' => array('className', 'classMethod')
- * ),
- * // Second memcache server
- * array(
- * 'host' => '192.168.1.5',
- * 'port' => 22122,
- * 'persistent' => TRUE
- * )
- * ),
- * 'compression' => FALSE, // Use compression?
- * ),
- * )
- *
- * 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.
- *
- * #### General cache group configuration settings
- *
- * Below are the settings available to all types of cache driver.
- *
- * 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
- *
- * #### Memcache server configuration
- *
- * The following settings should be used when defining each memcache server
- *
- * 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__
- *
- * ### System requirements
- *
- * * Kohana 3.0.x
- * * PHP 5.2.4 or greater
- * * Memcache (plus Memcached-tags for native tagging support)
- * * Zlib
- *
- * @package Kohana/Cache
- * @category Base
- * @version 2.0
- * @author Kohana Team
- * @copyright (c) Kohana Team
- * @license https://koseven.ga/LICENSE.md
- */
- class Kohana_Cache_Memcache extends Cache implements Cache_Arithmetic {
- // 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;
- /**
- * The default configuration for the memcached server
- *
- * @var array
- */
- protected $_default_config = [];
- /**
- * Constructs the memcache Kohana_Cache object
- *
- * @param array $config configuration
- * @throws Cache_Exception
- */
- protected function __construct(array $config)
- {
- // Check for the memcache extention
- if ( ! extension_loaded('memcache'))
- {
- throw new Cache_Exception('Memcache PHP extention not loaded');
- }
- 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
- throw new Cache_Exception('No Memcache servers defined in configuration');
- }
- // Setup default server configuration
- $this->_default_config = [
- 'host' => 'localhost',
- 'port' => 11211,
- 'persistent' => FALSE,
- 'weight' => 1,
- 'timeout' => 1,
- 'retry_interval' => 15,
- 'status' => TRUE,
- 'instant_death' => TRUE,
- 'failure_callback' => [$this, '_failed_request'],
- ];
- // Add the memcache servers to the pool
- foreach ($servers as $server)
- {
- // Merge the defined config with defaults
- $server += $this->_default_config;
- if ( ! $this->_memcache->addServer($server['host'], $server['port'], $server['persistent'], $server['weight'], $server['timeout'], $server['retry_interval'], $server['status'], $server['failure_callback']))
- {
- throw new Cache_Exception('Memcache could not connect to host \':host\' using port \':port\'', [':host' => $server['host'], ':port' => $server['port']]);
- }
- }
- // Setup the flags
- $this->_flags = Arr::get($this->_config, 'compression', FALSE) ? MEMCACHE_COMPRESSED : FALSE;
- }
- /**
- * Retrieve a cached value entry by id.
- *
- * // Retrieve cache entry from memcache group
- * $data = Cache::instance('memcache')->get('foo');
- *
- * // Retrieve cache entry from memcache group and return 'bar' if miss
- * $data = Cache::instance('memcache')->get('foo', 'bar');
- *
- * @param string $id id of cache to entry
- * @param string $default default value to return if cache miss
- * @return mixed
- * @throws Cache_Exception
- */
- 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
- *
- * $data = 'bar';
- *
- * // Set 'bar' to 'foo' in memcache group for 10 minutes
- * if (Cache::instance('memcache')->set('foo', $data, 600))
- * {
- * // Cache was set successfully
- * return
- * }
- *
- * @param string $id id of cache entry
- * @param mixed $data data to set to cache
- * @param integer $lifetime lifetime in seconds, maximum value 2592000
- * @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
- *
- * // Delete the 'foo' cache entry immediately
- * Cache::instance('memcache')->delete('foo');
- *
- * // Delete the 'bar' cache entry after 30 seconds
- * Cache::instance('memcache')->delete('bar', 30);
- *
- * @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
- * @return boolean
- */
- public function delete($id, $timeout = 0)
- {
- // Delete the id
- return $this->_memcache->delete($this->_sanitize_id($id), $timeout);
- }
- /**
- * Delete all cache entries.
- *
- * Beware of using this method when
- * using shared memory cache systems, as it will wipe every
- * entry within the system for all clients.
- *
- * // 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`.
- *
- * @param string $hostname
- * @param integer $port
- * @return void|boolean
- * @since 3.0.8
- */
- public function _failed_request($hostname, $port)
- {
- if ( ! $this->_config['instant_death'])
- return;
- // Setup non-existent host
- $host = FALSE;
- // Get host settings from configuration
- foreach ($this->_config['servers'] as $server)
- {
- // Merge the defaults, since they won't always be set
- $server += $this->_default_config;
- // We're looking at the failed server
- if ($hostname == $server['host'] and $port == $server['port'])
- {
- // Server to disable, since it failed
- $host = $server;
- continue;
- }
- }
- if ( ! $host)
- return;
- else
- {
- return $this->_memcache->setServerParams(
- $host['host'],
- $host['port'],
- $host['timeout'],
- $host['retry_interval'],
- FALSE, // Server is offline
- [$this, '_failed_request'
- ]);
- }
- }
- /**
- * 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($this->_sanitize_id($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($this->_sanitize_id($id), $step);
- }
- }
|