MemcacheEngine.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. <?php
  2. /**
  3. * Memcache storage engine for cache
  4. *
  5. *
  6. * PHP 5
  7. *
  8. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  9. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  10. *
  11. * Licensed under The MIT License
  12. * For full copyright and license information, please see the LICENSE.txt
  13. * Redistributions of files must retain the above copyright notice.
  14. *
  15. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  16. * @link http://cakephp.org CakePHP(tm) Project
  17. * @package Cake.Cache.Engine
  18. * @since CakePHP(tm) v 1.2.0.4933
  19. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  20. */
  21. /**
  22. * Memcache storage engine for cache. Memcache has some limitations in the amount of
  23. * control you have over expire times far in the future. See MemcacheEngine::write() for
  24. * more information.
  25. *
  26. * @package Cake.Cache.Engine
  27. * @deprecated You should use the Memcached adapter instead.
  28. */
  29. class MemcacheEngine extends CacheEngine {
  30. /**
  31. * Contains the compiled group names
  32. * (prefixed with the global configuration prefix)
  33. *
  34. * @var array
  35. */
  36. protected $_compiledGroupNames = array();
  37. /**
  38. * Memcache wrapper.
  39. *
  40. * @var Memcache
  41. */
  42. protected $_Memcache = null;
  43. /**
  44. * Settings
  45. *
  46. * - servers = string or array of memcache servers, default => 127.0.0.1. If an
  47. * array MemcacheEngine will use them as a pool.
  48. * - compress = boolean, default => false
  49. *
  50. * @var array
  51. */
  52. public $settings = array();
  53. /**
  54. * Initialize the Cache Engine
  55. *
  56. * Called automatically by the cache frontend
  57. * To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
  58. *
  59. * @param array $settings array of setting for the engine
  60. * @return boolean True if the engine has been successfully initialized, false if not
  61. */
  62. public function init($settings = array()) {
  63. if (!class_exists('Memcache')) {
  64. return false;
  65. }
  66. if (!isset($settings['prefix'])) {
  67. $settings['prefix'] = Inflector::slug(APP_DIR) . '_';
  68. }
  69. $settings += array(
  70. 'engine' => 'Memcache',
  71. 'servers' => array('127.0.0.1'),
  72. 'compress' => false,
  73. 'persistent' => true
  74. );
  75. parent::init($settings);
  76. if ($this->settings['compress']) {
  77. $this->settings['compress'] = MEMCACHE_COMPRESSED;
  78. }
  79. if (is_string($this->settings['servers'])) {
  80. $this->settings['servers'] = array($this->settings['servers']);
  81. }
  82. if (!isset($this->_Memcache)) {
  83. $return = false;
  84. $this->_Memcache = new Memcache();
  85. foreach ($this->settings['servers'] as $server) {
  86. list($host, $port) = $this->_parseServerString($server);
  87. if ($this->_Memcache->addServer($host, $port, $this->settings['persistent'])) {
  88. $return = true;
  89. }
  90. }
  91. return $return;
  92. }
  93. return true;
  94. }
  95. /**
  96. * Parses the server address into the host/port. Handles both IPv6 and IPv4
  97. * addresses and Unix sockets
  98. *
  99. * @param string $server The server address string.
  100. * @return array Array containing host, port
  101. */
  102. protected function _parseServerString($server) {
  103. if ($server[0] === 'u') {
  104. return array($server, 0);
  105. }
  106. if (substr($server, 0, 1) === '[') {
  107. $position = strpos($server, ']:');
  108. if ($position !== false) {
  109. $position++;
  110. }
  111. } else {
  112. $position = strpos($server, ':');
  113. }
  114. $port = 11211;
  115. $host = $server;
  116. if ($position !== false) {
  117. $host = substr($server, 0, $position);
  118. $port = substr($server, $position + 1);
  119. }
  120. return array($host, $port);
  121. }
  122. /**
  123. * Write data for key into cache. When using memcache as your cache engine
  124. * remember that the Memcache pecl extension does not support cache expiry times greater
  125. * than 30 days in the future. Any duration greater than 30 days will be treated as never expiring.
  126. *
  127. * @param string $key Identifier for the data
  128. * @param mixed $value Data to be cached
  129. * @param integer $duration How long to cache the data, in seconds
  130. * @return boolean True if the data was successfully cached, false on failure
  131. * @see http://php.net/manual/en/memcache.set.php
  132. */
  133. public function write($key, $value, $duration) {
  134. if ($duration > 30 * DAY) {
  135. $duration = 0;
  136. }
  137. return $this->_Memcache->set($key, $value, $this->settings['compress'], $duration);
  138. }
  139. /**
  140. * Read a key from the cache
  141. *
  142. * @param string $key Identifier for the data
  143. * @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
  144. */
  145. public function read($key) {
  146. return $this->_Memcache->get($key);
  147. }
  148. /**
  149. * Increments the value of an integer cached key
  150. *
  151. * @param string $key Identifier for the data
  152. * @param integer $offset How much to increment
  153. * @return New incremented value, false otherwise
  154. * @throws CacheException when you try to increment with compress = true
  155. */
  156. public function increment($key, $offset = 1) {
  157. if ($this->settings['compress']) {
  158. throw new CacheException(
  159. __d('cake_dev', 'Method %s not implemented for compressed cache in %s', 'increment()', __CLASS__)
  160. );
  161. }
  162. return $this->_Memcache->increment($key, $offset);
  163. }
  164. /**
  165. * Decrements the value of an integer cached key
  166. *
  167. * @param string $key Identifier for the data
  168. * @param integer $offset How much to subtract
  169. * @return New decremented value, false otherwise
  170. * @throws CacheException when you try to decrement with compress = true
  171. */
  172. public function decrement($key, $offset = 1) {
  173. if ($this->settings['compress']) {
  174. throw new CacheException(
  175. __d('cake_dev', 'Method %s not implemented for compressed cache in %s', 'decrement()', __CLASS__)
  176. );
  177. }
  178. return $this->_Memcache->decrement($key, $offset);
  179. }
  180. /**
  181. * Delete a key from the cache
  182. *
  183. * @param string $key Identifier for the data
  184. * @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
  185. */
  186. public function delete($key) {
  187. return $this->_Memcache->delete($key);
  188. }
  189. /**
  190. * Delete all keys from the cache
  191. *
  192. * @param boolean $check
  193. * @return boolean True if the cache was successfully cleared, false otherwise
  194. */
  195. public function clear($check) {
  196. if ($check) {
  197. return true;
  198. }
  199. foreach ($this->_Memcache->getExtendedStats('slabs') as $slabs) {
  200. foreach (array_keys($slabs) as $slabId) {
  201. if (!is_numeric($slabId)) {
  202. continue;
  203. }
  204. foreach ($this->_Memcache->getExtendedStats('cachedump', $slabId) as $stats) {
  205. if (!is_array($stats)) {
  206. continue;
  207. }
  208. foreach (array_keys($stats) as $key) {
  209. if (strpos($key, $this->settings['prefix']) === 0) {
  210. $this->_Memcache->delete($key);
  211. }
  212. }
  213. }
  214. }
  215. }
  216. return true;
  217. }
  218. /**
  219. * Connects to a server in connection pool
  220. *
  221. * @param string $host host ip address or name
  222. * @param integer $port Server port
  223. * @return boolean True if memcache server was connected
  224. */
  225. public function connect($host, $port = 11211) {
  226. if ($this->_Memcache->getServerStatus($host, $port) === 0) {
  227. if ($this->_Memcache->connect($host, $port)) {
  228. return true;
  229. }
  230. return false;
  231. }
  232. return true;
  233. }
  234. /**
  235. * Returns the `group value` for each of the configured groups
  236. * If the group initial value was not found, then it initializes
  237. * the group accordingly.
  238. *
  239. * @return array
  240. */
  241. public function groups() {
  242. if (empty($this->_compiledGroupNames)) {
  243. foreach ($this->settings['groups'] as $group) {
  244. $this->_compiledGroupNames[] = $this->settings['prefix'] . $group;
  245. }
  246. }
  247. $groups = $this->_Memcache->get($this->_compiledGroupNames);
  248. if (count($groups) !== count($this->settings['groups'])) {
  249. foreach ($this->_compiledGroupNames as $group) {
  250. if (!isset($groups[$group])) {
  251. $this->_Memcache->set($group, 1, false, 0);
  252. $groups[$group] = 1;
  253. }
  254. }
  255. ksort($groups);
  256. }
  257. $result = array();
  258. $groups = array_values($groups);
  259. foreach ($this->settings['groups'] as $i => $group) {
  260. $result[] = $group . $groups[$i];
  261. }
  262. return $result;
  263. }
  264. /**
  265. * Increments the group value to simulate deletion of all keys under a group
  266. * old values will remain in storage until they expire.
  267. *
  268. * @return boolean success
  269. */
  270. public function clearGroup($group) {
  271. return (bool)$this->_Memcache->increment($this->settings['prefix'] . $group);
  272. }
  273. }