PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/joomla/cache/storage/memcache.php

https://github.com/rietn/minima
PHP | 410 lines | 218 code | 70 blank | 122 comment | 43 complexity | d665784ae0c640ae6bbfc1917f9a14d3 MD5 | raw file
  1. <?php
  2. /**
  3. * @version $Id: memcache.php 20228 2011-01-10 00:52:54Z eddieajau $
  4. * @package Joomla.Framework
  5. * @subpackage Cache
  6. * @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE.txt
  8. */
  9. // No direct access
  10. defined('JPATH_BASE') or die;
  11. /**
  12. * Memcache cache storage handler
  13. *
  14. * @package Joomla.Framework
  15. * @subpackage Cache
  16. * @since 1.5
  17. */
  18. class JCacheStorageMemcache extends JCacheStorage
  19. {
  20. /**
  21. * @since 1.5
  22. */
  23. private static $_db = null;
  24. /**
  25. * @since 1.6
  26. */
  27. private $_persistent = false;
  28. /**
  29. * @since 1.6
  30. */
  31. private $_compress = 0;
  32. /**
  33. * Constructor
  34. *
  35. * @param array $options optional parameters
  36. * @since 1.5
  37. */
  38. public function __construct($options = array())
  39. {
  40. parent::__construct($options);
  41. if (self::$_db === null) {
  42. $this->getConnection();
  43. }
  44. }
  45. /**
  46. * return memcache connection object
  47. *
  48. * @return object memcache connection object
  49. * @since 1.5
  50. */
  51. private function getConnection()
  52. {
  53. if ((extension_loaded('memcache') && class_exists('Memcache')) != true ) {
  54. return false;
  55. }
  56. $config = JFactory::getConfig();
  57. $this->_persistent = $config->get('memcache_persist', true);
  58. $this->_compress = $config->get('memcache_compress', false) == false ? 0 : MEMCACHE_COMPRESSED;
  59. // This will be an array of loveliness
  60. // @todo: multiple servers
  61. //$servers = (isset($params['servers'])) ? $params['servers'] : array();
  62. $server=array();
  63. $server['host'] = $config->get('memcache_server_host', 'localhost');
  64. $server['port'] = $config->get('memcache_server_port', 11211);
  65. // Create the memcache connection
  66. self::$_db = new Memcache;
  67. self::$_db->addServer($server['host'], $server['port'], $this->_persistent);
  68. $memcachetest = @self::$_db->connect($server['host'], $server['port']);
  69. if ($memcachetest == false) {
  70. return JError::raiseError(404, "Could not connect to memcache server");
  71. }
  72. // memcahed has no list keys, we do our own accounting, initalise key index
  73. if (self::$_db->get($this->_hash.'-index') === false) {
  74. $empty = array();
  75. self::$_db->set($this->_hash.'-index', $empty , $this->_compress, 0);
  76. }
  77. return;
  78. }
  79. /**
  80. * Get cached data from memcache by id and group
  81. *
  82. * @param string $id The cache data id
  83. * @param string $group The cache data group
  84. * @param boolean $checkTime True to verify cache time expiration threshold
  85. * @return mixed Boolean false on failure or a cached data string
  86. * @since 1.5
  87. */
  88. public function get($id, $group, $checkTime = true)
  89. {
  90. $cache_id = $this->_getCacheId($id, $group);
  91. $back = self::$_db->get($cache_id);
  92. return $back;
  93. }
  94. /**
  95. * Get all cached data
  96. *
  97. * @return array data
  98. * @since 1.6
  99. */
  100. public function getAll()
  101. {
  102. parent::getAll();
  103. $keys = self::$_db->get($this->_hash.'-index');
  104. $secret = $this->_hash;
  105. $data = array();
  106. if (!empty($keys)){
  107. foreach ($keys as $key) {
  108. if (empty($key)) {
  109. continue;
  110. }
  111. $namearr=explode('-',$key->name);
  112. if ($namearr !== false && $namearr[0]==$secret && $namearr[1]=='cache') {
  113. $group = $namearr[2];
  114. if (!isset($data[$group])) {
  115. $item = new JCacheStorageHelper($group);
  116. } else {
  117. $item = $data[$group];
  118. }
  119. $item->updateSize($key->size/1024);
  120. $data[$group] = $item;
  121. }
  122. }
  123. }
  124. return $data;
  125. }
  126. /**
  127. * Store the data to memcache by id and group
  128. *
  129. * @param string $id The cache data id
  130. * @param string $group The cache data group
  131. * @param string $data The data to store in cache
  132. * @return boolean True on success, false otherwise
  133. * @since 1.5
  134. */
  135. public function store($id, $group, $data)
  136. {
  137. $cache_id = $this->_getCacheId($id, $group);
  138. if (!$this->lockindex()) {
  139. return false;
  140. }
  141. $index = self::$_db->get($this->_hash.'-index');
  142. if ($index === false) {
  143. $index = array();
  144. }
  145. $tmparr = new stdClass;
  146. $tmparr->name = $cache_id;
  147. $tmparr->size = strlen($data);
  148. $index[] = $tmparr;
  149. self::$_db->replace($this->_hash.'-index', $index , 0, 0);
  150. $this->unlockindex();
  151. // prevent double writes, write only if it doesn't exist else replace
  152. if (!self::$_db->replace($cache_id, $data, $this->_compress, $this->_lifetime)) {
  153. self::$_db->set($cache_id, $data, $this->_compress, $this->_lifetime);
  154. }
  155. return true;
  156. }
  157. /**
  158. * Remove a cached data entry by id and group
  159. *
  160. * @param string $id The cache data id
  161. * @param string $group The cache data group
  162. * @return boolean True on success, false otherwise
  163. * @since 1.5
  164. */
  165. public function remove($id, $group)
  166. {
  167. $cache_id = $this->_getCacheId($id, $group);
  168. if (!$this->lockindex()) {
  169. return false;
  170. }
  171. $index = self::$_db->get($this->_hash.'-index');
  172. if ($index === false) {
  173. $index = array();
  174. }
  175. foreach ($index as $key => $value) {
  176. if ($value->name == $cache_id) unset ($index[$key]);
  177. break;
  178. }
  179. self::$_db->replace($this->_hash.'-index', $index, 0, 0);
  180. $this->unlockindex();
  181. return self::$_db->delete($cache_id);
  182. }
  183. /**
  184. * Clean cache for a group given a mode.
  185. *
  186. * group mode : cleans all cache in the group
  187. * notgroup mode : cleans all cache not in the group
  188. *
  189. * @param string $group The cache data group
  190. * @param string $mode The mode for cleaning cache [group|notgroup]
  191. * @return boolean True on success, false otherwise
  192. * @since 1.5
  193. */
  194. public function clean($group, $mode = null)
  195. {
  196. if (!$this->lockindex()) {
  197. return false;
  198. }
  199. $index = self::$_db->get($this->_hash.'-index');
  200. if ($index === false) {
  201. $index = array();
  202. }
  203. $secret = $this->_hash;
  204. foreach ($index as $key=>$value) {
  205. if (strpos($value->name, $secret.'-cache-'.$group.'-')===0 xor $mode != 'group') {
  206. self::$_db->delete($value->name,0);
  207. unset ($index[$key]);
  208. }
  209. }
  210. self::$_db->replace($this->_hash.'-index', $index , 0, 0);
  211. $this->unlockindex();
  212. return true;
  213. }
  214. /**
  215. * Test to see if the cache storage is available.
  216. *
  217. * @return boolean True on success, false otherwise.
  218. */
  219. public static function test()
  220. {
  221. if ((extension_loaded('memcache') && class_exists('Memcache')) != true ) {
  222. return false;
  223. }
  224. $config = JFactory::getConfig();
  225. $host = $config->get('memcache_server_host', 'localhost');
  226. $port = $config->get('memcache_server_port', 11211);
  227. $memcache = new Memcache;
  228. $memcachetest = @$memcache->connect($host, $port);
  229. if (!$memcachetest) {
  230. return false;
  231. } else {
  232. return true;
  233. }
  234. }
  235. /**
  236. * Lock cached item - override parent as this is more efficient
  237. *
  238. * @param string $id The cache data id
  239. * @param string $group The cache data group
  240. * @param integer $locktime Cached item max lock time
  241. * @return boolean True on success, false otherwise.
  242. * @since 1.6
  243. */
  244. public function lock($id,$group,$locktime)
  245. {
  246. $returning = new stdClass();
  247. $returning->locklooped = false;
  248. $looptime = $locktime * 10;
  249. $cache_id = $this->_getCacheId($id, $group);
  250. if (!$this->lockindex()) {
  251. return false;
  252. }
  253. $index = self::$_db->get($this->_hash.'-index');
  254. if ($index === false) {
  255. $index = array();
  256. }
  257. $tmparr = new stdClass;
  258. $tmparr->name = $cache_id;
  259. $tmparr->size = 1;
  260. $index[] = $tmparr;
  261. self::$_db->replace($this->_hash.'-index', $index , 0, 0);
  262. $this->unlockindex();
  263. $data_lock = self::$_db->add($cache_id.'_lock', 1, false, $locktime);
  264. if ($data_lock === FALSE) {
  265. $lock_counter = 0;
  266. // loop until you find that the lock has been released. that implies that data get from other thread has finished
  267. while ($data_lock === FALSE) {
  268. if ($lock_counter > $looptime) {
  269. $returning->locked = false;
  270. $returning->locklooped = true;
  271. break;
  272. }
  273. usleep(100);
  274. $data_lock = self::$_db->add($cache_id.'_lock', 1, false, $locktime);
  275. $lock_counter++;
  276. }
  277. }
  278. $returning->locked = $data_lock;
  279. return $returning;
  280. }
  281. /**
  282. * Unlock cached item - override parent for cacheid compatibility with lock
  283. *
  284. * @param string $id The cache data id
  285. * @param string $group The cache data group
  286. * @param integer $locktime Cached item max lock time
  287. * @since 1.6
  288. * @return boolean True on success, false otherwise.
  289. */
  290. public function unlock($id,$group=null)
  291. {
  292. $unlock = false;
  293. $cache_id = $this->_getCacheId($id, $group).'_lock';
  294. if (!$this->lockindex()) return false;
  295. $index = self::$_db->get($this->_hash.'-index');
  296. if ($index === false) {$index = array();}
  297. foreach ($index as $key=>$value){
  298. if ($value->name == $cache_id) unset ($index[$key]);
  299. break;
  300. }
  301. self::$_db->replace($this->_hash.'-index', $index, 0, 0);
  302. $this->unlockindex();
  303. return self::$_db->delete($cache_id);
  304. }
  305. /**
  306. * Lock cache index
  307. *
  308. * @since 1.6
  309. * @return boolean True on success, false otherwise.
  310. */
  311. private function lockindex()
  312. {
  313. $looptime = 300;
  314. $data_lock = self::$_db->add($this->_hash.'-index_lock', 1, false, 30);
  315. if ($data_lock === FALSE) {
  316. $lock_counter = 0;
  317. // loop until you find that the lock has been released. that implies that data get from other thread has finished
  318. while ( $data_lock === FALSE ) {
  319. if ( $lock_counter > $looptime ) {
  320. return false;
  321. break;
  322. }
  323. usleep(100);
  324. $data_lock = self::$_db->add($this->_hash.'-index_lock', 1, false, 30);
  325. $lock_counter++;
  326. }
  327. }
  328. return true;
  329. }
  330. /**
  331. * Unlock cache index
  332. *
  333. * @return boolean True on success, false otherwise.
  334. * @since 1.6
  335. */
  336. private function unlockindex()
  337. {
  338. return self::$_db->delete($this->_hash.'-index_lock');
  339. }
  340. }