[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Joomla! Content Management System 4 * 5 * @copyright (C) 2012 Open Source Matters, Inc. <https://www.joomla.org> 6 * @license GNU General Public License version 2 or later; see LICENSE.txt 7 */ 8 9 namespace Joomla\CMS\Cache\Storage; 10 11 \defined('JPATH_PLATFORM') or die; 12 13 use Joomla\CMS\Cache\Cache; 14 use Joomla\CMS\Cache\CacheStorage; 15 use Joomla\CMS\Cache\Exception\CacheConnectingException; 16 use Joomla\CMS\Factory; 17 18 /** 19 * Memcached cache storage handler 20 * 21 * @link https://www.php.net/manual/en/book.memcached.php 22 * @since 3.0.0 23 */ 24 class MemcachedStorage extends CacheStorage 25 { 26 /** 27 * Memcached connection object 28 * 29 * @var \Memcached 30 * @since 3.0.0 31 */ 32 protected static $_db = null; 33 34 /** 35 * Payload compression level 36 * 37 * @var integer 38 * @since 3.0.0 39 */ 40 protected $_compress = 0; 41 42 /** 43 * Constructor 44 * 45 * @param array $options Optional parameters. 46 * 47 * @since 3.0.0 48 */ 49 public function __construct($options = array()) 50 { 51 parent::__construct($options); 52 53 $this->_compress = Factory::getApplication()->get('memcached_compress', false) ? \Memcached::OPT_COMPRESSION : 0; 54 55 if (static::$_db === null) 56 { 57 $this->getConnection(); 58 } 59 } 60 61 /** 62 * Create the Memcached connection 63 * 64 * @return void 65 * 66 * @since 3.0.0 67 * @throws \RuntimeException 68 */ 69 protected function getConnection() 70 { 71 if (!static::isSupported()) 72 { 73 throw new \RuntimeException('Memcached Extension is not available'); 74 } 75 76 $app = Factory::getApplication(); 77 78 $host = $app->get('memcached_server_host', 'localhost'); 79 $port = $app->get('memcached_server_port', 11211); 80 81 82 // Create the memcached connection 83 if ($app->get('memcached_persist', true)) 84 { 85 static::$_db = new \Memcached($this->_hash); 86 $servers = static::$_db->getServerList(); 87 88 if ($servers && ($servers[0]['host'] != $host || $servers[0]['port'] != $port)) 89 { 90 static::$_db->resetServerList(); 91 $servers = array(); 92 } 93 94 if (!$servers) 95 { 96 static::$_db->addServer($host, $port); 97 } 98 } 99 else 100 { 101 static::$_db = new \Memcached; 102 static::$_db->addServer($host, $port); 103 } 104 105 static::$_db->setOption(\Memcached::OPT_COMPRESSION, $this->_compress); 106 107 $stats = static::$_db->getStats(); 108 $result = !empty($stats["$host:$port"]) && $stats["$host:$port"]['pid'] > 0; 109 110 if (!$result) 111 { 112 // Null out the connection to inform the constructor it will need to attempt to connect if this class is instantiated again 113 static::$_db = null; 114 115 throw new CacheConnectingException('Could not connect to memcached server'); 116 } 117 } 118 119 /** 120 * Get a cache_id string from an id/group pair 121 * 122 * @param string $id The cache data id 123 * @param string $group The cache data group 124 * 125 * @return string The cache_id string 126 * 127 * @since 1.7.0 128 */ 129 protected function _getCacheId($id, $group) 130 { 131 $prefix = Cache::getPlatformPrefix(); 132 $length = \strlen($prefix); 133 $cache_id = parent::_getCacheId($id, $group); 134 135 if ($length) 136 { 137 // Memcached use suffix instead of prefix 138 $cache_id = substr($cache_id, $length) . strrev($prefix); 139 } 140 141 return $cache_id; 142 } 143 144 /** 145 * Check if the cache contains data stored by ID and group 146 * 147 * @param string $id The cache data ID 148 * @param string $group The cache data group 149 * 150 * @return boolean 151 * 152 * @since 3.7.0 153 */ 154 public function contains($id, $group) 155 { 156 static::$_db->get($this->_getCacheId($id, $group)); 157 158 return static::$_db->getResultCode() !== \Memcached::RES_NOTFOUND; 159 } 160 161 /** 162 * Get cached data by ID and group 163 * 164 * @param string $id The cache data ID 165 * @param string $group The cache data group 166 * @param boolean $checkTime True to verify cache time expiration threshold 167 * 168 * @return mixed Boolean false on failure or a cached data object 169 * 170 * @since 3.0.0 171 */ 172 public function get($id, $group, $checkTime = true) 173 { 174 return static::$_db->get($this->_getCacheId($id, $group)); 175 } 176 177 /** 178 * Get all cached data 179 * 180 * @return mixed Boolean false on failure or a cached data object 181 * 182 * @since 3.0.0 183 */ 184 public function getAll() 185 { 186 $keys = static::$_db->get($this->_hash . '-index'); 187 $secret = $this->_hash; 188 189 $data = array(); 190 191 if (\is_array($keys)) 192 { 193 foreach ($keys as $key) 194 { 195 if (empty($key)) 196 { 197 continue; 198 } 199 200 $namearr = explode('-', $key->name); 201 202 if ($namearr !== false && $namearr[0] == $secret && $namearr[1] === 'cache') 203 { 204 $group = $namearr[2]; 205 206 if (!isset($data[$group])) 207 { 208 $item = new CacheStorageHelper($group); 209 } 210 else 211 { 212 $item = $data[$group]; 213 } 214 215 $item->updateSize($key->size); 216 217 $data[$group] = $item; 218 } 219 } 220 } 221 222 return $data; 223 } 224 225 /** 226 * Store the data to cache by ID and group 227 * 228 * @param string $id The cache data ID 229 * @param string $group The cache data group 230 * @param string $data The data to store in cache 231 * 232 * @return boolean 233 * 234 * @since 3.0.0 235 */ 236 public function store($id, $group, $data) 237 { 238 $cache_id = $this->_getCacheId($id, $group); 239 240 if (!$this->lockindex()) 241 { 242 return false; 243 } 244 245 $index = static::$_db->get($this->_hash . '-index'); 246 247 if (!\is_array($index)) 248 { 249 $index = array(); 250 } 251 252 $tmparr = new \stdClass; 253 $tmparr->name = $cache_id; 254 $tmparr->size = \strlen($data); 255 256 $index[] = $tmparr; 257 static::$_db->set($this->_hash . '-index', $index, 0); 258 $this->unlockindex(); 259 260 static::$_db->set($cache_id, $data, $this->_lifetime); 261 262 return true; 263 } 264 265 /** 266 * Remove a cached data entry by ID and group 267 * 268 * @param string $id The cache data ID 269 * @param string $group The cache data group 270 * 271 * @return boolean 272 * 273 * @since 3.0.0 274 */ 275 public function remove($id, $group) 276 { 277 $cache_id = $this->_getCacheId($id, $group); 278 279 if (!$this->lockindex()) 280 { 281 return false; 282 } 283 284 $index = static::$_db->get($this->_hash . '-index'); 285 286 if (\is_array($index)) 287 { 288 foreach ($index as $key => $value) 289 { 290 if ($value->name == $cache_id) 291 { 292 unset($index[$key]); 293 static::$_db->set($this->_hash . '-index', $index, 0); 294 break; 295 } 296 } 297 } 298 299 $this->unlockindex(); 300 301 return static::$_db->delete($cache_id); 302 } 303 304 /** 305 * Clean cache for a group given a mode. 306 * 307 * group mode : cleans all cache in the group 308 * notgroup mode : cleans all cache not in the group 309 * 310 * @param string $group The cache data group 311 * @param string $mode The mode for cleaning cache [group|notgroup] 312 * 313 * @return boolean 314 * 315 * @since 3.0.0 316 */ 317 public function clean($group, $mode = null) 318 { 319 if (!$this->lockindex()) 320 { 321 return false; 322 } 323 324 $index = static::$_db->get($this->_hash . '-index'); 325 326 if (\is_array($index)) 327 { 328 $prefix = $this->_hash . '-cache-' . $group . '-'; 329 330 foreach ($index as $key => $value) 331 { 332 if (strpos($value->name, $prefix) === 0 xor $mode !== 'group') 333 { 334 static::$_db->delete($value->name); 335 unset($index[$key]); 336 } 337 } 338 339 static::$_db->set($this->_hash . '-index', $index, 0); 340 } 341 342 $this->unlockindex(); 343 344 return true; 345 } 346 347 /** 348 * Flush all existing items in storage. 349 * 350 * @return boolean 351 * 352 * @since 3.6.3 353 */ 354 public function flush() 355 { 356 if (!$this->lockindex()) 357 { 358 return false; 359 } 360 361 return static::$_db->flush(); 362 } 363 364 /** 365 * Test to see if the storage handler is available. 366 * 367 * @return boolean 368 * 369 * @since 3.0.0 370 */ 371 public static function isSupported() 372 { 373 /* 374 * GAE and HHVM have both had instances where Memcached the class was defined but no extension was loaded. 375 * If the class is there, we can assume support. 376 */ 377 return class_exists('Memcached'); 378 } 379 380 /** 381 * Lock cached item 382 * 383 * @param string $id The cache data ID 384 * @param string $group The cache data group 385 * @param integer $locktime Cached item max lock time 386 * 387 * @return mixed Boolean false if locking failed or an object containing properties lock and locklooped 388 * 389 * @since 3.0.0 390 */ 391 public function lock($id, $group, $locktime) 392 { 393 $returning = new \stdClass; 394 $returning->locklooped = false; 395 396 $looptime = $locktime * 10; 397 398 $cache_id = $this->_getCacheId($id, $group); 399 400 $data_lock = static::$_db->add($cache_id . '_lock', 1, $locktime); 401 402 if ($data_lock === false) 403 { 404 $lock_counter = 0; 405 406 // Loop until you find that the lock has been released. 407 // That implies that data get from other thread has finished. 408 while ($data_lock === false) 409 { 410 if ($lock_counter > $looptime) 411 { 412 break; 413 } 414 415 usleep(100); 416 $data_lock = static::$_db->add($cache_id . '_lock', 1, $locktime); 417 $lock_counter++; 418 } 419 420 $returning->locklooped = true; 421 } 422 423 $returning->locked = $data_lock; 424 425 return $returning; 426 } 427 428 /** 429 * Unlock cached item 430 * 431 * @param string $id The cache data ID 432 * @param string $group The cache data group 433 * 434 * @return boolean 435 * 436 * @since 3.0.0 437 */ 438 public function unlock($id, $group = null) 439 { 440 $cache_id = $this->_getCacheId($id, $group) . '_lock'; 441 return static::$_db->delete($cache_id); 442 } 443 444 /** 445 * Lock cache index 446 * 447 * @return boolean 448 * 449 * @since 3.0.0 450 */ 451 protected function lockindex() 452 { 453 $looptime = 300; 454 $data_lock = static::$_db->add($this->_hash . '-index_lock', 1, 30); 455 456 if ($data_lock === false) 457 { 458 $lock_counter = 0; 459 460 // Loop until you find that the lock has been released. that implies that data get from other thread has finished 461 while ($data_lock === false) 462 { 463 if ($lock_counter > $looptime) 464 { 465 return false; 466 } 467 468 usleep(100); 469 $data_lock = static::$_db->add($this->_hash . '-index_lock', 1, 30); 470 $lock_counter++; 471 } 472 } 473 474 return true; 475 } 476 477 /** 478 * Unlock cache index 479 * 480 * @return boolean 481 * 482 * @since 3.0.0 483 */ 484 protected function unlockindex() 485 { 486 return static::$_db->delete($this->_hash . '-index_lock'); 487 } 488 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |