/protected/components/ezcomponents/Cache/src/backends/memcache/memcache_backend.php

https://github.com/kamarulismail/kamarul-playground · PHP · 259 lines · 105 code · 26 blank · 128 comment · 13 complexity · e6359d01d40dc60743529d32a2695652 MD5 · raw file

  1. <?php
  2. /**
  3. * File containing the ezcCacheMemcacheBackend class.
  4. *
  5. * @package Cache
  6. * @version 1.5
  7. * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
  8. * @license http://ez.no/licenses/new_bsd New BSD License
  9. * @filesource
  10. */
  11. /**
  12. * This backend stores data in a Memcache.
  13. *
  14. * @apichange This class will be deprecated in the next major version of the
  15. * Cache component. Please do not use it directly, but use {@link
  16. * ezcCacheStorageMemcache} instead.
  17. *
  18. * @package Cache
  19. * @version 1.5
  20. */
  21. class ezcCacheMemcacheBackend extends ezcCacheMemoryBackend
  22. {
  23. /**
  24. * The compress threshold.
  25. *
  26. * Nearly 1MB (48,576B less).
  27. */
  28. const COMPRESS_THRESHOLD = 1000000;
  29. /**
  30. * Maximum length of a cache key for Memcached.
  31. */
  32. const MAX_KEY_LENGTH = 249;
  33. /**
  34. * Holds an instance to a Memcache object.
  35. *
  36. * @var resource
  37. */
  38. protected $memcache;
  39. /**
  40. * Holds the options for this class.
  41. *
  42. * @var ezcCacheStorageMemcacheOptions
  43. */
  44. protected $options;
  45. /**
  46. * Stores the connections to Memcached.
  47. *
  48. * @var array(string=>Memcache)
  49. */
  50. protected static $connections = array();
  51. /**
  52. * Keeps track of the number of backends using the same connection.
  53. *
  54. * This is to avoid that the dtor of a backend accedentally closes a
  55. * connection that is still in used by another backend.
  56. *
  57. * @var array(string=>int)
  58. */
  59. protected static $connectionCounter = array();
  60. /**
  61. * Stores the connection identifier.
  62. *
  63. * This is generated in the ctor and used in the dtor.
  64. *
  65. * @var string
  66. */
  67. protected $connectionIdentifier;
  68. /**
  69. * Constructs a new ezcCacheMemcacheBackend object.
  70. *
  71. * For options for this backend see {@link ezcCacheStorageMemcacheOptions}.
  72. *
  73. * @throws ezcBaseExtensionNotFoundException
  74. * If the PHP memcache and zlib extensions are not installed.
  75. * @throws ezcCacheMemcacheException
  76. * If the connection to the Memcache host did not succeed.
  77. *
  78. * @param array(string=>mixed) $options
  79. */
  80. public function __construct( array $options = array() )
  81. {
  82. if ( !ezcBaseFeatures::hasExtensionSupport( 'memcache' ) )
  83. {
  84. throw new ezcBaseExtensionNotFoundException( 'memcache', null, "PHP does not have Memcache support." );
  85. }
  86. if ( !ezcBaseFeatures::hasExtensionSupport( 'zlib' ) )
  87. {
  88. throw new ezcBaseExtensionNotFoundException( 'zlib', null, "PHP not configured with --with-zlib." );
  89. }
  90. $this->options = new ezcCacheStorageMemcacheOptions( $options );
  91. $this->connectionIdentifier = $this->options->host . ':' . $this->options->port;
  92. if ( !isset( self::$connections[$this->connectionIdentifier] ) )
  93. {
  94. self::$connections[$this->connectionIdentifier] = new Memcache();
  95. // Currently 0 backends use the connection
  96. self::$connectionCounter[$this->connectionIdentifier] = 0;
  97. }
  98. $this->memcache = self::$connections[$this->connectionIdentifier];
  99. // Now 1 backend uses it
  100. self::$connectionCounter[$this->connectionIdentifier]++;
  101. if ( $this->options->persistent === true )
  102. {
  103. if ( !@$this->memcache->pconnect( $this->options->host, $this->options->port, $this->options->ttl ) )
  104. {
  105. throw new ezcCacheMemcacheException( 'Could not connect to Memcache using a persistent connection.' );
  106. }
  107. }
  108. else
  109. {
  110. if ( !@$this->memcache->connect( $this->options->host, $this->options->port, $this->options->ttl ) )
  111. {
  112. throw new ezcCacheMemcacheException( 'Could not connect to Memcache.' );
  113. }
  114. }
  115. $this->memcache->setCompressThreshold( self::COMPRESS_THRESHOLD );
  116. }
  117. /**
  118. * Destructor for the Memcache backend.
  119. */
  120. public function __destruct()
  121. {
  122. self::$connectionCounter[$this->connectionIdentifier]--;
  123. // Save to ignore persistent connections, since close() does not affect them
  124. if ( self::$connectionCounter[$this->connectionIdentifier] === 0 )
  125. {
  126. $this->memcache->close();
  127. }
  128. }
  129. /**
  130. * Adds the $var data to the cache under the key $key. Returns true or
  131. * false depending on the success of the operation.
  132. *
  133. * @param string $key
  134. * @param mixed $var
  135. * @param int $expire
  136. * @return bool
  137. */
  138. public function store( $key, $var, $expire = 0 )
  139. {
  140. if ( strlen( $key ) > self::MAX_KEY_LENGTH )
  141. {
  142. throw new ezcCacheInvalidKeyException( $key, 'Length > ' . self::MAX_KEY_LENGTH . '.' );
  143. }
  144. // protect our data by wrapping it in an object
  145. $data = new ezcCacheMemoryVarStruct( $key, $var, $expire );
  146. $compressed = ( $this->options->compressed === true ) ? MEMCACHE_COMPRESSED : false;
  147. return $this->memcache->set( $key, $data, $compressed, $expire );
  148. }
  149. /**
  150. * Returns the data from the cache associated with key $key.
  151. *
  152. * @param mixed $key
  153. * @return mixed
  154. */
  155. public function fetch( $key )
  156. {
  157. if ( strlen( $key ) > self::MAX_KEY_LENGTH )
  158. {
  159. throw new ezcCacheInvalidKeyException( $key, 'Length > ' . self::MAX_KEY_LENGTH . '.' );
  160. }
  161. $data = $this->memcache->get( $key );
  162. return ( is_object( $data ) ) ? $data->var : false;
  163. }
  164. /**
  165. * Deletes the data from the cache associated with key $key. Returns true or
  166. * false depending on the success of the operation.
  167. *
  168. * The value $timeout specifies the timeout period in seconds for the delete
  169. * command.
  170. *
  171. * @param string $key
  172. * @param int $timeout
  173. * @return bool
  174. */
  175. public function delete( $key, $timeout = 0 )
  176. {
  177. if ( strlen( $key ) > self::MAX_KEY_LENGTH )
  178. {
  179. throw new ezcCacheInvalidKeyException( $key, 'Length > ' . self::MAX_KEY_LENGTH . '.' );
  180. }
  181. return $this->memcache->delete( $key, $timeout );
  182. }
  183. /**
  184. * Resets the complete backend.
  185. *
  186. * Marked private to not expose more of this interface to the user, since
  187. * this will be removed in future versions.
  188. *
  189. * @return void
  190. * @access private
  191. */
  192. public function reset()
  193. {
  194. // Kills whole memcache content
  195. $this->memcache->flush();
  196. }
  197. /**
  198. * Acquires a lock on the given $key.
  199. *
  200. * @param string $key
  201. * @param int $waitTime usleep()
  202. * @param int $maxTime seconds
  203. */
  204. public function acquireLock( $key, $waitTime, $maxTime )
  205. {
  206. if ( strlen( $key ) > self::MAX_KEY_LENGTH )
  207. {
  208. throw new ezcCacheInvalidKeyException( $key, 'Length > ' . self::MAX_KEY_LENGTH . '.' );
  209. }
  210. // add() does not replace and returns true on success. $maxTime is
  211. // obeyed by Memcache expiry.
  212. while ( $this->memcache->add( $key, $key, false, $maxTime ) === false )
  213. {
  214. // Wait for next check
  215. usleep( $waitTime );
  216. }
  217. }
  218. /**
  219. * Releases a lock on the given $key.
  220. *
  221. * @param string $key
  222. * @return void
  223. */
  224. public function releaseLock( $key )
  225. {
  226. if ( strlen( $key ) > self::MAX_KEY_LENGTH )
  227. {
  228. throw new ezcCacheInvalidKeyException( $key, 'Length > ' . self::MAX_KEY_LENGTH . '.' );
  229. }
  230. $this->memcache->delete( $key );
  231. }
  232. }
  233. ?>