perf(2meet-data-optimizer-hivepress-addon): expire object-cache transients
- with an external object cache, a HivePress timeout entry expires when it records; the value (written before its timeout) after at most a week — a miss only makes HivePress rebuild it. Entries of deleted posts no longer accumulate without end - Verify: HivepressTransientFilterTest TTL test, integration 53, unit 145; dev36 Redis TTL on tmdo_hp_transient keys - PR: PR-099
This commit is contained in:
@@ -80,6 +80,9 @@ final class TMDO_Hivepress_Transient_Filter {
|
||||
/** Object cache group used instead of wp_options when a persistent cache is present. */
|
||||
public const CACHE_GROUP = 'tmdo_hp_transient';
|
||||
|
||||
/** Longest an object-cache entry lives: a week (HivePress's default is a day). */
|
||||
public const MAX_CACHE_TTL = 604800;
|
||||
|
||||
/**
|
||||
* Register the four metadata filters on `init`. Idempotent — safe to call
|
||||
* multiple times.
|
||||
@@ -267,8 +270,10 @@ final class TMDO_Hivepress_Transient_Filter {
|
||||
* In wp_options both halves of the transient pair are written with
|
||||
* `autoload=no` (they are read on-demand only — never via
|
||||
* wp_load_alloptions() — so eagerly loading them on every page would defeat
|
||||
* the point of the move). HivePress checks the timeout itself, so the
|
||||
* cache entries get no TTL of their own.
|
||||
* the point of the move). In the object cache a timeout entry expires when
|
||||
* it says; the value, written before its timeout, after MAX_CACHE_TTL — a
|
||||
* miss only makes HivePress rebuild it — so entries of deleted posts do
|
||||
* not pile up (2.3 PR-099).
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @param string $meta_key Original `_transient_*` meta_key.
|
||||
@@ -281,7 +286,8 @@ final class TMDO_Hivepress_Transient_Filter {
|
||||
$option_name = ( $is_timeout ? '_transient_timeout_' : '_transient_' ) . $translated;
|
||||
|
||||
if ( wp_using_ext_object_cache() ) {
|
||||
wp_cache_set( $option_name, $meta_value, self::CACHE_GROUP );
|
||||
$ttl = $is_timeout ? min( self::MAX_CACHE_TTL, max( 1, (int) $meta_value - time() ) ) : self::MAX_CACHE_TTL;
|
||||
wp_cache_set( $option_name, $meta_value, self::CACHE_GROUP, $ttl );
|
||||
return;
|
||||
}
|
||||
update_option( $option_name, $meta_value, false );
|
||||
|
||||
@@ -213,6 +213,26 @@ class HivepressTransientFilterTest extends TestCase {
|
||||
$this->assertSame( array( '99999999' ), WPDO_Hivepress_Transient_Filter::on_read( null, 100, '_transient_timeout_hp_models/cat/v1', true ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Entries expire in the object cache too (2.3 PR-099): the timeout at the
|
||||
* time it records, the value (written first, before its timeout is known)
|
||||
* after at most a week. Orphans of deleted posts no longer pile up.
|
||||
*/
|
||||
public function test_with_an_object_cache_entries_get_a_ttl(): void {
|
||||
$GLOBALS['_wp_using_ext_object_cache'] = true;
|
||||
$key = '_transient_hp_models/cat/v1';
|
||||
$translated = WPDO_Hivepress_Transient_Filter::translate_key( 100, $key );
|
||||
|
||||
WPDO_Hivepress_Transient_Filter::on_update( null, 100, $key, 'val', '' );
|
||||
WPDO_Hivepress_Transient_Filter::on_update( null, 100, '_transient_timeout_hp_models/cat/v1', (string) ( time() + 3600 ), '' );
|
||||
WPDO_Hivepress_Transient_Filter::on_update( null, 101, '_transient_timeout_hp_models/cat/v1', (string) ( time() - 5 ), '' );
|
||||
|
||||
$ttl = $GLOBALS['_wp_cache_ttl'][ WPDO_Hivepress_Transient_Filter::CACHE_GROUP ];
|
||||
$this->assertSame( WPDO_Hivepress_Transient_Filter::MAX_CACHE_TTL, $ttl[ '_transient_' . $translated ] );
|
||||
$this->assertEqualsWithDelta( 3600, $ttl[ '_transient_timeout_' . $translated ], 2 );
|
||||
$this->assertSame( 1, $ttl[ '_transient_timeout_' . WPDO_Hivepress_Transient_Filter::translate_key( 101, $key ) ], 'already expired' );
|
||||
}
|
||||
|
||||
public function test_with_an_object_cache_a_value_left_in_wp_options_is_not_read(): void {
|
||||
// A miss must not fall back to get_option(): the option is absent after
|
||||
// cleanup and WordPress would add its name to `notoptions` for good.
|
||||
|
||||
@@ -21,6 +21,14 @@ if ( ! file_exists( $tmdo_core_bootstrap ) ) {
|
||||
. dirname( __DIR__, 3 ) . '/2meet-data-optimizer'
|
||||
);
|
||||
}
|
||||
// Defined before the core bootstrap (which only adds it when missing) so tests can read the TTL.
|
||||
if ( ! function_exists( 'wp_cache_set' ) ) {
|
||||
function wp_cache_set( $key, $value, $group = '', $ttl = 0 ): bool {
|
||||
$GLOBALS['_wp_cache'][ $group ][ $key ] = $value;
|
||||
$GLOBALS['_wp_cache_ttl'][ $group ][ $key ] = (int) $ttl;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
require_once $tmdo_core_bootstrap;
|
||||
|
||||
// External object cache switch for the transient filter tests (Redis on real sites).
|
||||
|
||||
Reference in New Issue
Block a user