From 5975c2d2faf9230ec505f6214c9481fb659d55ed Mon Sep 17 00:00:00 2001 From: David Herrera Date: Thu, 7 Nov 2024 23:28:24 -0500 Subject: [PATCH] Cache items fetched during the request in memory --- CHANGELOG.md | 8 ++++++- src/class-big-pit.php | 27 ++++++++++++++++++++++ tests/Unit/CrudUnitTest.php | 45 +++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aadef05..ffa3d87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,15 @@ This library adheres to [Semantic Versioning](https://semver.org/) and [Keep a CHANGELOG](https://keepachangelog.com/en/1.0.0/). +## 0.4.0 + +### Added + +- In-memory cache of items fetched during the request. + ## 0.3.0 -## Changed +### Changed - When storing items with the PSR-16 adapter, the group name is now automatically prefixed to avoid unintended data loss when flushing the cache. diff --git a/src/class-big-pit.php b/src/class-big-pit.php index 506bb37..355eea1 100644 --- a/src/class-big-pit.php +++ b/src/class-big-pit.php @@ -30,6 +30,15 @@ final class Big_Pit implements Feature { */ private bool $ready = false; + /** + * Cached values. + * + * @phpstan-var array> + * + * @var array[] + */ + private array $cache = []; + /** * Instance. * @@ -79,6 +88,16 @@ public function get( string $key, string $group ): mixed { return null; } + if ( isset( $this->cache[ $group ] ) && array_key_exists( $key, $this->cache[ $group ] ) ) { + $value = $this->cache[ $group ][ $key ]; + + if ( is_object( $value ) ) { + $value = clone $value; + } + + return $value; + } + $value = $wpdb->get_var( $wpdb->prepare( "SELECT item_value FROM {$wpdb->big_pit} WHERE item_group = %s AND item_key = %s LIMIT 1", @@ -91,6 +110,8 @@ public function get( string $key, string $group ): mixed { $value = maybe_unserialize( $value ); } + $this->cache[ $group ][ $key ] = $value; + return $value; } @@ -141,6 +162,8 @@ public function set( string $key, mixed $value, string $group ): void { [ '%s', '%s', '%s' ], ); } + + unset( $this->cache[ $group ][ $key ] ); } /** @@ -164,6 +187,8 @@ public function delete( string $key, string $group ): void { ], [ '%s', '%s' ], ); + + unset( $this->cache[ $group ][ $key ] ); } /** @@ -185,6 +210,8 @@ public function flush_group( string $group ): void { ], [ '%s' ], ); + + unset( $this->cache[ $group ] ); } /** diff --git a/tests/Unit/CrudUnitTest.php b/tests/Unit/CrudUnitTest.php index 6f94450..53ae46a 100644 --- a/tests/Unit/CrudUnitTest.php +++ b/tests/Unit/CrudUnitTest.php @@ -68,4 +68,49 @@ public function test_crud() { // key3 should still be there. $this->assertSame( $val3, $big_pit->get( $key3, $grp2 ) ); } + + /** + * Test for expected number of queries with the in-memory cache. + */ + public function test_in_memory_cache() { + global $wpdb; + + $big_pit = Big_Pit::instance(); + + // Two fetches of the same key should only result in one query. + $num_queries_before = $wpdb->num_queries; + $big_pit->get( 'key1', 'group1' ); + $big_pit->get( 'key1', 'group1' ); + $this->assertSame( 1, $wpdb->num_queries - $num_queries_before ); + + $big_pit->set( 'key1', 'value1', 'group1' ); + + // Value has changed, so there should be another query. + $num_queries_before = $wpdb->num_queries; + $big_pit->get( 'key1', 'group1' ); + $this->assertSame( 1, $wpdb->num_queries - $num_queries_before ); + + // Fetching it again should not result in another query. + $big_pit->get( 'key1', 'group1' ); + $this->assertSame( 1, $wpdb->num_queries - $num_queries_before ); + + $big_pit->delete( 'key1', 'group1' ); + + // Value has changed, so there should be another query. + $num_queries_before = $wpdb->num_queries; + $big_pit->get( 'key1', 'group1' ); + $this->assertSame( 1, $wpdb->num_queries - $num_queries_before ); + + $big_pit->set( 'key1', 'value1', 'group1' ); + $big_pit->set( 'key2', 'value2', 'group1' ); + $big_pit->get( 'key1', 'group1' ); + $big_pit->get( 'key2', 'group1' ); + $big_pit->flush_group( 'group1' ); + + // All values have changed, so there should be queries for each value in the group that was set. + $num_queries_before = $wpdb->num_queries; + $big_pit->get( 'key1', 'group1' ); + $big_pit->get( 'key2', 'group1' ); + $this->assertSame( 2, $wpdb->num_queries - $num_queries_before ); + } }