├── .gitignore ├── README.md ├── object-cache.php └── readme.txt /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | A WordPress object cache backend that implements all available methods using the Redis PECL library. 4 | 5 | ## Authors 6 | 7 | * Eric Mann 8 | * Erick Hitter 9 | 10 | ## Installation 11 | 1. Install and configure Redis. There is a good tutorial [here](http://www.saltwebsites.com/2012/install-redis-245-service-centos-6). 12 | 2. Install the [Redis PECL module](http://pecl.php.net/package/redis). 13 | 3. Add `object-cache.php` to the wp-content directory. It is a drop-in file, not a plugin, so it belongs in the wp-content directory, not the plugins directory. 14 | 4. By default, the script will connect to Redis at 127.0.0.1:6379. See the *Connecting to Redis* section for further options. 15 | 16 | ### Connecting to Redis ### 17 | 18 | By default, the plugin uses `127.0.0.1` and `6379` as the default host and port when creating a new client instance; the default database of `0` is also used. Three constants are provided to override these default values. 19 | 20 | Specify `WP_REDIS_BACKEND_HOST`, `WP_REDIS_BACKEND_PORT`, and `WP_REDIS_BACKEND_DB` to set the necessary, non-default connection values for your Redis instance. 21 | 22 | ### Prefixing Cache Keys ### 23 | 24 | The constant `WP_CACHE_KEY_SALT` is provided to add a prefix to all cache keys used by the plugin. If running two single instances of WordPress from the same Redis instance, this constant could be used to avoid overlap in cache keys. Note that special handling is not needed for WordPress Multisite. 25 | -------------------------------------------------------------------------------- /object-cache.php: -------------------------------------------------------------------------------- 1 | add( $key, $value, $group, $expiration ); 26 | } 27 | 28 | /** 29 | * Closes the cache. 30 | * 31 | * This function has ceased to do anything since WordPress 2.5. The 32 | * functionality was removed along with the rest of the persistent cache. This 33 | * does not mean that plugins can't implement this function when they need to 34 | * make sure that the cache is cleaned up after WordPress no longer needs it. 35 | * 36 | * @return bool Always returns True 37 | */ 38 | function wp_cache_close() { 39 | return true; 40 | } 41 | 42 | /** 43 | * Decrement a numeric item's value. 44 | * 45 | * @param string $key The key under which to store the value. 46 | * @param int $offset The amount by which to decrement the item's value. 47 | * @param string $group The group value appended to the $key. 48 | * 49 | * @global WP_Object_Cache $wp_object_cache 50 | * 51 | * @return int|bool Returns item's new value on success or FALSE on failure. 52 | */ 53 | function wp_cache_decr( $key, $offset = 1, $group = '' ) { 54 | global $wp_object_cache; 55 | return $wp_object_cache->decrement( $key, $offset, $group ); 56 | } 57 | 58 | /** 59 | * Remove the item from the cache. 60 | * 61 | * @param string $key The key under which to store the value. 62 | * @param string $group The group value appended to the $key. 63 | * @param int $time The amount of time the server will wait to delete the item in seconds. 64 | * 65 | * @global WP_Object_Cache $wp_object_cache 66 | * 67 | * @return bool Returns TRUE on success or FALSE on failure. 68 | */ 69 | function wp_cache_delete( $key, $group = '', $time = 0 ) { 70 | global $wp_object_cache; 71 | return $wp_object_cache->delete( $key, $group, $time ); 72 | } 73 | 74 | /** 75 | * Invalidate all items in the cache. 76 | * 77 | * @param int $delay Number of seconds to wait before invalidating the items. 78 | * 79 | * @global WP_Object_Cache $wp_object_cache 80 | * 81 | * @return bool Returns TRUE on success or FALSE on failure. 82 | */ 83 | function wp_cache_flush( $delay = 0 ) { 84 | global $wp_object_cache; 85 | return $wp_object_cache->flush( $delay ); 86 | } 87 | 88 | /** 89 | * Retrieve object from cache. 90 | * 91 | * Gets an object from cache based on $key and $group. 92 | * 93 | * @param string $key The key under which to store the value. 94 | * @param string $group The group value appended to the $key. 95 | * 96 | * @global WP_Object_Cache $wp_object_cache 97 | * 98 | * @return bool|mixed Cached object value. 99 | */ 100 | function wp_cache_get( $key, $group = '' ) { 101 | global $wp_object_cache; 102 | return $wp_object_cache->get( $key, $group ); 103 | } 104 | 105 | /** 106 | * Retrieve multiple values from cache. 107 | * 108 | * Gets multiple values from cache, including across multiple groups 109 | * 110 | * Usage: array( 'group0' => array( 'key0', 'key1', 'key2', ), 'group1' => array( 'key0' ) ) 111 | * 112 | * Mirrors the Memcached Object Cache plugin's argument and return-value formats 113 | * 114 | * @param array $groups Array of groups and keys to retrieve 115 | * 116 | * @global WP_Object_Cache $wp_object_cache 117 | * 118 | * @return bool|mixed Array of cached values, keys in the format $group:$key. Non-existent keys false 119 | */ 120 | function wp_cache_get_multi( $groups ) { 121 | global $wp_object_cache; 122 | return $wp_object_cache->get_multi( $groups ); 123 | } 124 | 125 | /** 126 | * Increment a numeric item's value. 127 | * 128 | * @param string $key The key under which to store the value. 129 | * @param int $offset The amount by which to increment the item's value. 130 | * @param string $group The group value appended to the $key. 131 | * 132 | * @global WP_Object_Cache $wp_object_cache 133 | * 134 | * @return int|bool Returns item's new value on success or FALSE on failure. 135 | */ 136 | function wp_cache_incr( $key, $offset = 1, $group = '' ) { 137 | global $wp_object_cache; 138 | return $wp_object_cache->increment( $key, $offset, $group ); 139 | } 140 | 141 | /** 142 | * Sets up Object Cache Global and assigns it. 143 | * 144 | * @global WP_Object_Cache $wp_object_cache WordPress Object Cache 145 | * 146 | * @return void 147 | */ 148 | function wp_cache_init() { 149 | global $wp_object_cache; 150 | $wp_object_cache = new WP_Object_Cache(); 151 | } 152 | 153 | /** 154 | * Replaces a value in cache. 155 | * 156 | * This method is similar to "add"; however, is does not successfully set a value if 157 | * the object's key is not already set in cache. 158 | * 159 | * @param string $key The key under which to store the value. 160 | * @param mixed $value The value to store. 161 | * @param string $group The group value appended to the $key. 162 | * @param int $expiration The expiration time, defaults to 0. 163 | * 164 | * @global WP_Object_Cache $wp_object_cache 165 | * 166 | * @return bool Returns TRUE on success or FALSE on failure. 167 | */ 168 | function wp_cache_replace( $key, $value, $group = '', $expiration = 0 ) { 169 | global $wp_object_cache; 170 | return $wp_object_cache->replace( $key, $value, $group, $expiration ); 171 | } 172 | 173 | /** 174 | * Sets a value in cache. 175 | * 176 | * The value is set whether or not this key already exists in Redis. 177 | * 178 | * @param string $key The key under which to store the value. 179 | * @param mixed $value The value to store. 180 | * @param string $group The group value appended to the $key. 181 | * @param int $expiration The expiration time, defaults to 0. 182 | * 183 | * @global WP_Object_Cache $wp_object_cache 184 | * 185 | * @return bool Returns TRUE on success or FALSE on failure. 186 | */ 187 | function wp_cache_set( $key, $value, $group = '', $expiration = 0 ) { 188 | global $wp_object_cache; 189 | return $wp_object_cache->set( $key, $value, $group, $expiration ); 190 | } 191 | 192 | /** 193 | * Switch the interal blog id. 194 | * 195 | * This changes the blog id used to create keys in blog specific groups. 196 | * 197 | * @param int $_blog_id Blog ID 198 | * 199 | * @global WP_Object_Cache $wp_object_cache 200 | * 201 | * @return bool 202 | */ 203 | function wp_cache_switch_to_blog( $_blog_id ) { 204 | global $wp_object_cache; 205 | return $wp_object_cache->switch_to_blog( $_blog_id ); 206 | } 207 | 208 | /** 209 | * Adds a group or set of groups to the list of Redis groups. 210 | * 211 | * @param string|array $groups A group or an array of groups to add. 212 | * 213 | * @global WP_Object_Cache $wp_object_cache 214 | * 215 | * @return void 216 | */ 217 | function wp_cache_add_global_groups( $groups ) { 218 | global $wp_object_cache; 219 | $wp_object_cache->add_global_groups( $groups ); 220 | } 221 | 222 | /** 223 | * Adds a group or set of groups to the list of non-Redis groups. 224 | * 225 | * @param string|array $groups A group or an array of groups to add. 226 | * 227 | * @global WP_Object_Cache $wp_object_cache 228 | * 229 | * @return void 230 | */ 231 | function wp_cache_add_non_persistent_groups( $groups ) { 232 | global $wp_object_cache; 233 | $wp_object_cache->add_non_persistent_groups( $groups ); 234 | } 235 | 236 | class WP_Object_Cache { 237 | 238 | /** 239 | * Holds the Redis client. 240 | * 241 | * @var Predis\Client 242 | */ 243 | private $redis; 244 | 245 | /** 246 | * Track if Redis is available 247 | * 248 | * @var bool 249 | */ 250 | private $redis_connected = false; 251 | 252 | /** 253 | * Holds the non-Redis objects. 254 | * 255 | * @var array 256 | */ 257 | private $cache = array(); 258 | 259 | /** 260 | * List of global groups. 261 | * 262 | * @var array 263 | */ 264 | public $global_groups = array( 'users', 'userlogins', 'usermeta', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss' ); 265 | 266 | /** 267 | * List of groups not saved to Redis. 268 | * 269 | * @var array 270 | */ 271 | public $no_redis_groups = array( 'comment', 'counts' ); 272 | 273 | /** 274 | * Prefix used for global groups. 275 | * 276 | * @var string 277 | */ 278 | public $global_prefix = ''; 279 | 280 | /** 281 | * Prefix used for non-global groups. 282 | * 283 | * @var string 284 | */ 285 | public $blog_prefix = ''; 286 | 287 | /** 288 | * Track how many requests were found in cache 289 | * 290 | * @var int 291 | */ 292 | public $cache_hits = 0; 293 | 294 | /** 295 | * Track how may requests were not cached 296 | * 297 | * @var int 298 | */ 299 | public $cache_misses = 0; 300 | 301 | /** 302 | * Instantiate the Redis class. 303 | * 304 | * Instantiates the Redis class. 305 | * 306 | * @param null $persistent_id To create an instance that persists between requests, use persistent_id to specify a unique ID for the instance. 307 | */ 308 | public function __construct() { 309 | global $blog_id, $table_prefix; 310 | 311 | // General Redis settings 312 | $redis = array( 313 | 'host' => '127.0.0.1', 314 | 'port' => 6379, 315 | ); 316 | 317 | if ( defined( 'WP_REDIS_BACKEND_HOST' ) && WP_REDIS_BACKEND_HOST ) { 318 | $redis['host'] = WP_REDIS_BACKEND_HOST; 319 | } 320 | if ( defined( 'WP_REDIS_BACKEND_PORT' ) && WP_REDIS_BACKEND_PORT ) { 321 | $redis['port'] = WP_REDIS_BACKEND_PORT; 322 | } 323 | if ( defined( 'WP_REDIS_BACKEND_AUTH' ) && WP_REDIS_BACKEND_AUTH ) { 324 | $redis['auth'] = WP_REDIS_BACKEND_AUTH; 325 | } 326 | if ( defined( 'WP_REDIS_BACKEND_DB' ) && WP_REDIS_BACKEND_DB ) { 327 | $redis['database'] = WP_REDIS_BACKEND_DB; 328 | } 329 | if ( ( defined( 'WP_REDIS_SERIALIZER' ) ) ) { 330 | $redis['serializer'] = WP_REDIS_SERIALIZER; 331 | } else { 332 | $redis['serializer'] = Redis::SERIALIZER_PHP; 333 | } 334 | 335 | // Use Redis PECL library. 336 | try { 337 | $this->redis = new Redis(); 338 | $this->redis->connect( $redis['host'], $redis['port'] ); 339 | $this->redis->setOption( Redis::OPT_SERIALIZER, $redis['serializer'] ); 340 | 341 | if ( isset( $redis['auth'] ) ) { 342 | $this->redis->auth( $redis['auth'] ); 343 | } 344 | 345 | if ( isset( $redis['database'] ) ) { 346 | $this->redis->select( $redis['database'] ); 347 | } 348 | 349 | $this->redis_connected = true; 350 | } catch ( RedisException $e ) { 351 | // When Redis is unavailable, fall back to the internal back by forcing all groups to be "no redis" groups 352 | $this->no_redis_groups = array_unique( array_merge( $this->no_redis_groups, $this->global_groups ) ); 353 | $this->redis_connected = false; 354 | } 355 | 356 | /** 357 | * This approach is borrowed from Sivel and Boren. Use the salt for easy cache invalidation and for 358 | * multi single WP installs on the same server. 359 | */ 360 | if ( ! defined( 'WP_CACHE_KEY_SALT' ) ) { 361 | define( 'WP_CACHE_KEY_SALT', '' ); 362 | } 363 | 364 | // Assign global and blog prefixes for use with keys 365 | if ( function_exists( 'is_multisite' ) ) { 366 | $this->global_prefix = ( is_multisite() || defined( 'CUSTOM_USER_TABLE' ) && defined( 'CUSTOM_USER_META_TABLE' ) ) ? '' : $table_prefix; 367 | $this->blog_prefix = ( is_multisite() ? $blog_id : $table_prefix ) . ':'; 368 | } 369 | } 370 | 371 | /** 372 | * Is Redis available? 373 | * 374 | * @return bool 375 | */ 376 | protected function can_redis() { 377 | return $this->redis_connected; 378 | } 379 | 380 | /** 381 | * Adds a value to cache. 382 | * 383 | * If the specified key already exists, the value is not stored and the function 384 | * returns false. 385 | * 386 | * @param string $key The key under which to store the value. 387 | * @param mixed $value The value to store. 388 | * @param string $group The group value appended to the $key. 389 | * @param int $expiration The expiration time, defaults to 0. 390 | * @return bool Returns TRUE on success or FALSE on failure. 391 | */ 392 | public function add( $key, $value, $group = 'default', $expiration = 0 ) { 393 | return $this->add_or_replace( true, $key, $value, $group, $expiration ); 394 | } 395 | 396 | /** 397 | * Replace a value in the cache. 398 | * 399 | * If the specified key doesn't exist, the value is not stored and the function 400 | * returns false. 401 | * 402 | * @param string $key The key under which to store the value. 403 | * @param mixed $value The value to store. 404 | * @param string $group The group value appended to the $key. 405 | * @param int $expiration The expiration time, defaults to 0. 406 | * @return bool Returns TRUE on success or FALSE on failure. 407 | */ 408 | public function replace( $key, $value, $group = 'default', $expiration = 0 ) { 409 | return $this->add_or_replace( false, $key, $value, $group, $expiration ); 410 | } 411 | 412 | /** 413 | * Add or replace a value in the cache. 414 | * 415 | * Add does not set the value if the key exists; replace does not replace if the value doesn't exist. 416 | * 417 | * @param bool $add True if should only add if value doesn't exist, false to only add when value already exists 418 | * @param string $key The key under which to store the value. 419 | * @param mixed $value The value to store. 420 | * @param string $group The group value appended to the $key. 421 | * @param int $expiration The expiration time, defaults to 0. 422 | * @return bool Returns TRUE on success or FALSE on failure. 423 | */ 424 | protected function add_or_replace( $add, $key, $value, $group = 'default', $expiration = 0 ) { 425 | $derived_key = $this->build_key( $key, $group ); 426 | 427 | // If group is a non-Redis group, save to internal cache, not Redis 428 | if ( in_array( $group, $this->no_redis_groups ) || ! $this->can_redis() ) { 429 | 430 | // Check if conditions are right to continue 431 | if ( 432 | ( $add && isset( $this->cache[ $derived_key ] ) ) || 433 | ( ! $add && ! isset( $this->cache[ $derived_key ] ) ) 434 | ) { 435 | return false; 436 | } 437 | 438 | $this->add_to_internal_cache( $derived_key, $value ); 439 | 440 | return true; 441 | } 442 | 443 | // Check if conditions are right to continue 444 | if ( 445 | ( $add && $this->redis->exists( $derived_key ) ) || 446 | ( ! $add && ! $this->redis->exists( $derived_key ) ) 447 | ) { 448 | return false; 449 | } 450 | 451 | // Save to Redis 452 | $expiration = abs( intval( $expiration ) ); 453 | if ( $expiration ) { 454 | $result = $this->parse_predis_response( $this->redis->setex( $derived_key, $expiration, $value ) ); 455 | } else { 456 | $result = $this->parse_predis_response( $this->redis->set( $derived_key, $value ) ); 457 | } 458 | 459 | return $result; 460 | } 461 | 462 | /** 463 | * Remove the item from the cache. 464 | * 465 | * @param string $key The key under which to store the value. 466 | * @param string $group The group value appended to the $key. 467 | * @return bool Returns TRUE on success or FALSE on failure. 468 | */ 469 | public function delete( $key, $group = 'default' ) { 470 | $derived_key = $this->build_key( $key, $group ); 471 | 472 | // Remove from no_redis_groups array 473 | if ( in_array( $group, $this->no_redis_groups ) || ! $this->can_redis() ) { 474 | if ( isset( $this->cache[ $derived_key ] ) ) { 475 | unset( $this->cache[ $derived_key ] ); 476 | 477 | return true; 478 | } else { 479 | return false; 480 | } 481 | } 482 | 483 | $result = $this->parse_predis_response( $this->redis->del( $derived_key ) ); 484 | 485 | unset( $this->cache[ $derived_key ] ); 486 | 487 | return $result; 488 | } 489 | 490 | /** 491 | * Invalidate all items in the cache. 492 | * 493 | * @param int $delay Number of seconds to wait before invalidating the items. 494 | * @return bool Returns TRUE on success or FALSE on failure. 495 | */ 496 | public function flush( $delay = 0 ) { 497 | $delay = abs( intval( $delay ) ); 498 | if ( $delay ) { 499 | sleep( $delay ); 500 | } 501 | 502 | $this->cache = array(); 503 | 504 | if ( $this->can_redis() ) { 505 | $result = $this->parse_predis_response( $this->redis->flushdb() ); 506 | } 507 | 508 | return $result; 509 | } 510 | 511 | /** 512 | * Retrieve object from cache. 513 | * 514 | * Gets an object from cache based on $key and $group. 515 | * 516 | * @param string $key The key under which to store the value. 517 | * @param string $group The group value appended to the $key. 518 | * @return bool|mixed Cached object value. 519 | */ 520 | public function get( $key, $group = 'default' ) { 521 | $derived_key = $this->build_key( $key, $group ); 522 | 523 | if ( in_array( $group, $this->no_redis_groups ) || ! $this->can_redis() ) { 524 | if ( isset( $this->cache[ $derived_key ] ) ) { 525 | $this->cache_hits++; 526 | return is_object( $this->cache[ $derived_key ] ) ? clone $this->cache[ $derived_key ] : $this->cache[ $derived_key ]; 527 | } else { 528 | $this->cache_misses++; 529 | return false; 530 | } 531 | } 532 | 533 | if ( $this->redis->exists( $derived_key ) ) { 534 | $this->cache_hits++; 535 | $value = $this->redis->get( $derived_key ); 536 | } else { 537 | $this->cache_misses; 538 | return false; 539 | } 540 | 541 | $this->add_to_internal_cache( $derived_key, $value ); 542 | 543 | return is_object( $value ) ? clone $value : $value; 544 | } 545 | 546 | /** 547 | * Retrieve multiple values from cache. 548 | * 549 | * Gets multiple values from cache, including across multiple groups 550 | * 551 | * Usage: array( 'group0' => array( 'key0', 'key1', 'key2', ), 'group1' => array( 'key0' ) ) 552 | * 553 | * Mirrors the Memcached Object Cache plugin's argument and return-value formats 554 | * 555 | * @param array $groups Array of groups and keys to retrieve 556 | * @uses this::filter_redis_get_multi() 557 | * @return bool|mixed Array of cached values, keys in the format $group:$key. Non-existent keys null. 558 | */ 559 | public function get_multi( $groups ) { 560 | if ( empty( $groups ) || ! is_array( $groups ) ) { 561 | return false; 562 | } 563 | 564 | // Retrieve requested caches and reformat results to mimic Memcached Object Cache's output 565 | $cache = array(); 566 | 567 | foreach ( $groups as $group => $keys ) { 568 | if ( in_array( $group, $this->no_redis_groups ) || ! $this->can_redis() ) { 569 | foreach ( $keys as $key ) { 570 | $cache[ $this->build_key( $key, $group ) ] = $this->get( $key, $group ); 571 | } 572 | } else { 573 | // Reformat arguments as expected by Redis 574 | $derived_keys = array(); 575 | foreach ( $keys as $key ) { 576 | $derived_keys[] = $this->build_key( $key, $group ); 577 | } 578 | 579 | // Retrieve from cache in a single request 580 | $group_cache = $this->redis->mget( $derived_keys ); 581 | 582 | // Build an array of values looked up, keyed by the derived cache key 583 | $group_cache = array_combine( $derived_keys, $group_cache ); 584 | 585 | // Redis returns null for values not found in cache, but expected return value is false in this instance 586 | $group_cache = array_map( array( $this, 'filter_redis_get_multi' ), $group_cache ); 587 | 588 | $cache = array_merge( $cache, $group_cache ); 589 | } 590 | } 591 | 592 | // Add to the internal cache the found values from Redis 593 | foreach ( $cache as $key => $value ) { 594 | if ( $value ) { 595 | $this->cache_hits++; 596 | $this->add_to_internal_cache( $key, $value ); 597 | } else { 598 | $this->cache_misses++; 599 | } 600 | } 601 | 602 | return $cache; 603 | } 604 | 605 | /** 606 | * Sets a value in cache. 607 | * 608 | * The value is set whether or not this key already exists in Redis. 609 | * 610 | * @param string $key The key under which to store the value. 611 | * @param mixed $value The value to store. 612 | * @param string $group The group value appended to the $key. 613 | * @param int $expiration The expiration time, defaults to 0. 614 | * @return bool Returns TRUE on success or FALSE on failure. 615 | */ 616 | public function set( $key, $value, $group = 'default', $expiration = 0 ) { 617 | $derived_key = $this->build_key( $key, $group ); 618 | 619 | // If group is a non-Redis group, save to internal cache, not Redis 620 | if ( in_array( $group, $this->no_redis_groups ) || ! $this->can_redis() ) { 621 | $this->add_to_internal_cache( $derived_key, $value ); 622 | 623 | return true; 624 | } 625 | 626 | // Save to Redis 627 | $expiration = abs( intval( $expiration ) ); 628 | if ( $expiration ) { 629 | $result = $this->parse_predis_response( $this->redis->setex( $derived_key, $expiration, $value ) ); 630 | } else { 631 | $result = $this->parse_predis_response( $this->redis->set( $derived_key, $value ) ); 632 | } 633 | 634 | return $result; 635 | } 636 | 637 | /** 638 | * Increment a Redis counter by the amount specified 639 | * 640 | * @param string $key 641 | * @param int $offset 642 | * @param string $group 643 | * @return bool 644 | */ 645 | public function increment( $key, $offset = 1, $group = 'default' ) { 646 | $derived_key = $this->build_key( $key, $group ); 647 | $offset = (int) $offset; 648 | 649 | // If group is a non-Redis group, save to internal cache, not Redis 650 | if ( in_array( $group, $this->no_redis_groups ) || ! $this->can_redis() ) { 651 | $value = $this->get_from_internal_cache( $derived_key, $group ); 652 | $value += $offset; 653 | $this->add_to_internal_cache( $derived_key, $value ); 654 | 655 | return true; 656 | } 657 | 658 | // Save to Redis 659 | $result = $this->parse_predis_response( $this->redis->incrBy( $derived_key, $offset ) ); 660 | 661 | $this->add_to_internal_cache( $derived_key, (int) $this->redis->get( $derived_key ) ); 662 | 663 | return $result; 664 | } 665 | 666 | /** 667 | * Decrement a Redis counter by the amount specified 668 | * 669 | * @param string $key 670 | * @param int $offset 671 | * @param string $group 672 | * @return bool 673 | */ 674 | public function decrement( $key, $offset = 1, $group = 'default' ) { 675 | $derived_key = $this->build_key( $key, $group ); 676 | $offset = (int) $offset; 677 | 678 | // If group is a non-Redis group, save to internal cache, not Redis 679 | if ( in_array( $group, $this->no_redis_groups ) || ! $this->can_redis() ) { 680 | $value = $this->get_from_internal_cache( $derived_key, $group ); 681 | $value -= $offset; 682 | $this->add_to_internal_cache( $derived_key, $value ); 683 | 684 | return true; 685 | } 686 | 687 | // Save to Redis 688 | $result = $this->parse_predis_response( $this->redis->decrBy( $derived_key, $offset ) ); 689 | 690 | $this->add_to_internal_cache( $derived_key, (int) $this->redis->get( $derived_key ) ); 691 | 692 | return $result; 693 | } 694 | 695 | /** 696 | * Render data about current cache requests 697 | * 698 | * @return string 699 | */ 700 | public function stats() { 701 | ?>
702 | _i18n( '_e', 'Cache Hits:' ); ?> _i18n( 'number_format_i18n', $this->cache_hits, false ); ?>
703 | _i18n( '_e', 'Cache Misses:' ); ?> _i18n( 'number_format_i18n', $this->cache_misses, false ); ?>
704 | _i18n( '_e', 'Using Redis?' ); ?>
705 | can_redis() ? $this->_i18n( '__', 'yes' ) : $this->_i18n( '__', 'no' );
706 | ?>
707 |
709 |
_i18n( '_e', 'Caches Retrieved:' ); ?>
710 |