Skip to content

Commit

Permalink
Merge pull request #287 from pantheon-systems/281-get-multiple
Browse files Browse the repository at this point in the history
Implement `wp_cache_get_multiple()` for WP 5.5
  • Loading branch information
danielbachhuber authored Jul 13, 2020
2 parents a2dcf02 + 7dcd65e commit 4a51a19
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 5 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
**Contributors:** getpantheon, danielbachhuber, mboynes, Outlandish Josh
**Tags:** cache, plugin, redis
**Requires at least:** 3.0.1
**Tested up to:** 5.4
**Stable tag:** 1.0.1
**Tested up to:** 5.5
**Stable tag:** 1.1.0
**License:** GPLv2 or later
**License URI:** http://www.gnu.org/licenses/gpl-2.0.html

Expand Down Expand Up @@ -107,6 +107,10 @@ There's a known issue with WordPress `alloptions` cache design. Specifically, a

## Changelog ##

### 1.1.0 (July 13, 2020) ###
* Implements `wp_cache_get_multiple()` for WordPress 5.5 [[#287](https://github.com/pantheon-systems/wp-redis/pull/287)].
* Bails early when connecting to Redis throws an Exception to avoid fatal error [[285](https://github.com/pantheon-systems/wp-redis/pull/285)].

### 1.0.1 (April 14, 2020) ###
* Adds support for specifying Redis database number from environment/server variables [[#273](https://github.com/pantheon-systems/wp-redis/pull/273)].

Expand Down
88 changes: 88 additions & 0 deletions object-cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,24 @@ function wp_cache_get( $key, $group = '', $force = false, &$found = null ) {
return $wp_object_cache->get( $key, $group, $force, $found );
}

/**
* Retrieves multiple values from the cache in one call.
*
* @see WP_Object_Cache::get_multiple()
* @global WP_Object_Cache $wp_object_cache Object cache global instance.
*
* @param array $keys Array of keys under which the cache contents are stored.
* @param string $group Optional. Where the cache contents are grouped. Default empty.
* @param bool $force Optional. Whether to force an update of the local cache
* from the persistent cache. Default false.
* @return array Array of values organized into groups.
*/
function wp_cache_get_multiple( $keys, $group = '', $force = false ) {
global $wp_object_cache;

return $wp_object_cache->get_multiple( $keys, $group, $force );
}

/**
* Increment numeric cache item's value
*
Expand Down Expand Up @@ -644,6 +662,74 @@ public function get( $key, $group = 'default', $force = false, &$found = null )
return $value;
}

/**
* Retrieves multiple values from the cache in one call.
*
* @param array $keys Array of keys under which the cache contents are stored.
* @param string $group Optional. Where the cache contents are grouped. Default empty.
* @param bool $force Optional. Whether to force an update of the local cache
* from the persistent cache. Default false.
* @return array Array of values organized into groups.
*/
public function get_multiple( $keys, $group = 'default', $force = false ) {
if ( empty( $group ) ) {
$group = 'default';
}

$cache = array();
if ( ! $this->_should_persist( $group ) ) {
foreach ( $keys as $key ) {
$cache[ $key ] = $this->_isset_internal( $key, $group ) ? $this->_get_internal( $key, $group ) : false;
false !== $cache[ $key ] ? $this->cache_hits++ : $this->cache_misses++;
}
return $cache;
}

// Attempt to fetch values from the internal cache.
if ( ! $force ) {
foreach ( $keys as $key ) {
if ( $this->_isset_internal( $key, $group ) ) {
$cache[ $key ] = $this->_get_internal( $key, $group );
$this->cache_hits++;
}
}
}
$remaining_keys = array_diff( $keys, array_keys( $cache ) );
// If all keys were satisfied by the internal cache, we're sorted.
if ( empty( $remaining_keys ) ) {
return $cache;
}
if ( $this->_should_use_redis_hashes( $group ) ) {
$redis_safe_group = $this->_key( '', $group );
$results = $this->_call_redis( 'hmGet', $redis_safe_group, $remaining_keys );
} else {
$ids = array();
foreach ( $remaining_keys as $key ) {
$ids[] = $this->_key( $key, $group );
}
$results = $this->_call_redis( 'mget', $ids );
}
// Process the results from the Redis call.
foreach ( $remaining_keys as $i => $key ) {
$value = isset( $results[ $i ] ) ? $results[ $i ] : false;
if ( false !== $value ) {
// All non-numeric values are serialized
$value = is_numeric( $value ) ? intval( $value ) : unserialize( $value );
$this->_set_internal( $key, $group, $value );
$this->cache_hits++;
} else {
$this->cache_misses++;
}
$cache[ $key ] = $value;
}
// Make sure return values are returned in the order of the passed keys.
$return_cache = array();
foreach ( $keys as $key ) {
$return_cache[ $key ] = isset( $cache[ $key ] ) ? $cache[ $key ] : false;
}
return $return_cache;
}

/**
* Increment numeric cache item's value
*
Expand Down Expand Up @@ -1239,7 +1325,9 @@ protected function _call_redis( $method ) {
case 'IsConnected':
case 'exists':
case 'get':
case 'mget':
case 'hGet':
case 'hmGet':
return false;
}

Expand Down
8 changes: 6 additions & 2 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
Contributors: getpantheon, danielbachhuber, mboynes, Outlandish Josh
Tags: cache, plugin, redis
Requires at least: 3.0.1
Tested up to: 5.4
Stable tag: 1.0.1
Tested up to: 5.5
Stable tag: 1.1.0
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html

Expand Down Expand Up @@ -107,6 +107,10 @@ There's a known issue with WordPress `alloptions` cache design. Specifically, a

== Changelog ==

= 1.1.0 (July 13, 2020) =
* Implements `wp_cache_get_multiple()` for WordPress 5.5 [[#287](https://github.com/pantheon-systems/wp-redis/pull/287)].
* Bails early when connecting to Redis throws an Exception to avoid fatal error [[285](https://github.com/pantheon-systems/wp-redis/pull/285)].

= 1.0.1 (April 14, 2020) =
* Adds support for specifying Redis database number from environment/server variables [[#273](https://github.com/pantheon-systems/wp-redis/pull/273)].

Expand Down
50 changes: 50 additions & 0 deletions tests/phpunit/test-cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class CacheTest extends WP_UnitTestCase {

private static $get_key;

private static $mget_key;

private static $set_key;

private static $incr_by_key;
Expand Down Expand Up @@ -43,6 +45,7 @@ public function setUp() {

self::$exists_key = WP_Object_Cache::USE_GROUPS ? 'hExists' : 'exists';
self::$get_key = WP_Object_Cache::USE_GROUPS ? 'hGet' : 'get';
self::$mget_key = WP_Object_Cache::USE_GROUPS ? 'hmGet' : 'mget';
self::$set_key = WP_Object_Cache::USE_GROUPS ? 'hSet' : 'set';
self::$incr_by_key = WP_Object_Cache::USE_GROUPS ? 'hIncrBy' : 'incrBy';
// 'hIncrBy' isn't a typo here — Redis doesn't support decrBy on groups
Expand Down Expand Up @@ -756,6 +759,53 @@ public function test_get_found() {
$this->assertEquals( 1, $this->cache->cache_misses );
}

public function test_get_multiple() {
$this->cache->set( 'foo1', 'bar', 'group1' );
$this->cache->set( 'foo2', 'bar', 'group1' );
$this->cache->set( 'foo1', 'bar', 'group2' );

$found = $this->cache->get_multiple( array( 'foo1', 'foo2', 'foo3' ), 'group1' );

$expected = array(
'foo1' => 'bar',
'foo2' => 'bar',
'foo3' => false,
);

$this->assertSame( $expected, $found );
$this->assertEquals( 2, $this->cache->cache_hits );
$this->assertEquals( 1, $this->cache->cache_misses );
if ( $this->cache->is_redis_connected ) {
$this->assertEquals(
array(
self::$mget_key => 1,
self::$set_key => 3,
),
$this->cache->redis_calls
);
} else {
$this->assertEmpty( $this->cache->redis_calls );
}
}

public function test_get_multiple_non_persistent() {
$this->cache->add_non_persistent_groups( array( 'group1' ) );
$this->cache->set( 'foo1', 'bar', 'group1' );
$this->cache->set( 'foo2', 'bar', 'group1' );

$found = $this->cache->get_multiple( array( 'foo1', 'foo2', 'foo3' ), 'group1' );

$expected = array(
'foo1' => 'bar',
'foo2' => 'bar',
'foo3' => false,
);
$this->assertSame( $expected, $found );
$this->assertEquals( 2, $this->cache->cache_hits );
$this->assertEquals( 1, $this->cache->cache_misses );
$this->assertEmpty( $this->cache->redis_calls );
}

public function test_incr() {
$key = rand_str();

Expand Down
2 changes: 1 addition & 1 deletion wp-redis.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Plugin Name: WP Redis
* Plugin URI: http://github.com/pantheon-systems/wp-redis/
* Description: WordPress Object Cache using Redis. Requires the PhpRedis extension (https://github.com/phpredis/phpredis).
* Version: 1.0.1
* Version: 1.1.0
* Author: Pantheon, Josh Koenig, Matthew Boynes, Daniel Bachhuber, Alley Interactive
* Author URI: https://pantheon.io/
*/
Expand Down

0 comments on commit 4a51a19

Please sign in to comment.