mirror of
git://develop.git.wordpress.org/
synced 2025-01-16 12:29:54 +01:00
Options/Meta APIs: Optimize cache hits for non-existent options.
Some checks are pending
Coding Standards / PHP coding standards (push) Waiting to run
Coding Standards / JavaScript coding standards (push) Waiting to run
Coding Standards / Slack Notifications (push) Blocked by required conditions
Coding Standards / Failed workflow tasks (push) Blocked by required conditions
End-to-end Tests / Test with SCRIPT_DEBUG disabled (push) Waiting to run
End-to-end Tests / Test with SCRIPT_DEBUG enabled (push) Waiting to run
End-to-end Tests / Slack Notifications (push) Blocked by required conditions
End-to-end Tests / Failed workflow tasks (push) Blocked by required conditions
JavaScript Tests / QUnit Tests (push) Waiting to run
JavaScript Tests / Slack Notifications (push) Blocked by required conditions
JavaScript Tests / Failed workflow tasks (push) Blocked by required conditions
Performance Tests / Single site (push) Waiting to run
Performance Tests / Multisite (push) Waiting to run
Performance Tests / Slack Notifications (push) Blocked by required conditions
Performance Tests / Failed workflow tasks (push) Blocked by required conditions
PHP Compatibility / Check PHP compatibility (push) Waiting to run
PHP Compatibility / Slack Notifications (push) Blocked by required conditions
PHP Compatibility / Failed workflow tasks (push) Blocked by required conditions
PHPUnit Tests / PHP 7.2 (push) Waiting to run
PHPUnit Tests / PHP 7.3 (push) Waiting to run
PHPUnit Tests / PHP 7.4 (push) Waiting to run
PHPUnit Tests / PHP 8.0 (push) Waiting to run
PHPUnit Tests / PHP 8.1 (push) Waiting to run
PHPUnit Tests / PHP 8.2 (push) Waiting to run
PHPUnit Tests / PHP 8.3 (push) Waiting to run
PHPUnit Tests / PHP 8.4 (push) Waiting to run
PHPUnit Tests / html-api-html5lib-tests (push) Waiting to run
PHPUnit Tests / Slack Notifications (push) Blocked by required conditions
PHPUnit Tests / Failed workflow tasks (push) Blocked by required conditions
Test Build Processes / Core running from build (push) Waiting to run
Test Build Processes / Core running from src (push) Waiting to run
Test Build Processes / Gutenberg running from build (push) Waiting to run
Test Build Processes / Gutenberg running from src (push) Waiting to run
Test Build Processes / Slack Notifications (push) Blocked by required conditions
Test Build Processes / Failed workflow tasks (push) Blocked by required conditions
Some checks are pending
Coding Standards / PHP coding standards (push) Waiting to run
Coding Standards / JavaScript coding standards (push) Waiting to run
Coding Standards / Slack Notifications (push) Blocked by required conditions
Coding Standards / Failed workflow tasks (push) Blocked by required conditions
End-to-end Tests / Test with SCRIPT_DEBUG disabled (push) Waiting to run
End-to-end Tests / Test with SCRIPT_DEBUG enabled (push) Waiting to run
End-to-end Tests / Slack Notifications (push) Blocked by required conditions
End-to-end Tests / Failed workflow tasks (push) Blocked by required conditions
JavaScript Tests / QUnit Tests (push) Waiting to run
JavaScript Tests / Slack Notifications (push) Blocked by required conditions
JavaScript Tests / Failed workflow tasks (push) Blocked by required conditions
Performance Tests / Single site (push) Waiting to run
Performance Tests / Multisite (push) Waiting to run
Performance Tests / Slack Notifications (push) Blocked by required conditions
Performance Tests / Failed workflow tasks (push) Blocked by required conditions
PHP Compatibility / Check PHP compatibility (push) Waiting to run
PHP Compatibility / Slack Notifications (push) Blocked by required conditions
PHP Compatibility / Failed workflow tasks (push) Blocked by required conditions
PHPUnit Tests / PHP 7.2 (push) Waiting to run
PHPUnit Tests / PHP 7.3 (push) Waiting to run
PHPUnit Tests / PHP 7.4 (push) Waiting to run
PHPUnit Tests / PHP 8.0 (push) Waiting to run
PHPUnit Tests / PHP 8.1 (push) Waiting to run
PHPUnit Tests / PHP 8.2 (push) Waiting to run
PHPUnit Tests / PHP 8.3 (push) Waiting to run
PHPUnit Tests / PHP 8.4 (push) Waiting to run
PHPUnit Tests / html-api-html5lib-tests (push) Waiting to run
PHPUnit Tests / Slack Notifications (push) Blocked by required conditions
PHPUnit Tests / Failed workflow tasks (push) Blocked by required conditions
Test Build Processes / Core running from build (push) Waiting to run
Test Build Processes / Core running from src (push) Waiting to run
Test Build Processes / Gutenberg running from build (push) Waiting to run
Test Build Processes / Gutenberg running from src (push) Waiting to run
Test Build Processes / Slack Notifications (push) Blocked by required conditions
Test Build Processes / Failed workflow tasks (push) Blocked by required conditions
Optimize the order of checking the various options caches in `get_option()` to prevent hitting external caches each time it is called for a known non-existent option. The caches are checked in the following order when getting an option: 1. Check the `alloptions` cache first to prioritize existing loaded options. 2. Check the `notoptions` cache before a cache lookup or DB hit. 3. Check the `options` cache prior to a DB hit. Follow up to [56595]. Props adamsilverstein, flixos90, ivankristianto, joemcgill, rmccue, siliconforks, spacedmonkey. Fixes #62692. See #58277. git-svn-id: https://develop.svn.wordpress.org/trunk@59631 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
d2630e00cd
commit
5b01d24d8c
@ -162,21 +162,26 @@ function get_option( $option, $default_value = false ) {
|
||||
|
||||
if ( ! wp_installing() ) {
|
||||
$alloptions = wp_load_alloptions();
|
||||
|
||||
/*
|
||||
* When getting an option value, we check in the following order for performance:
|
||||
*
|
||||
* 1. Check the 'alloptions' cache first to prioritize existing loaded options.
|
||||
* 2. Check the 'notoptions' cache before a cache lookup or DB hit.
|
||||
* 3. Check the 'options' cache prior to a DB hit.
|
||||
* 4. Check the DB for the option and cache it in either the 'options' or 'notoptions' cache.
|
||||
*/
|
||||
if ( isset( $alloptions[ $option ] ) ) {
|
||||
$value = $alloptions[ $option ];
|
||||
} else {
|
||||
$value = wp_cache_get( $option, 'options' );
|
||||
|
||||
if ( false === $value ) {
|
||||
// Prevent non-existent options from triggering multiple queries.
|
||||
// Check for non-existent options first to avoid unnecessary object cache lookups and DB hits.
|
||||
$notoptions = wp_cache_get( 'notoptions', 'options' );
|
||||
|
||||
// Prevent non-existent `notoptions` key from triggering multiple key lookups.
|
||||
if ( ! is_array( $notoptions ) ) {
|
||||
$notoptions = array();
|
||||
wp_cache_set( 'notoptions', $notoptions, 'options' );
|
||||
} elseif ( isset( $notoptions[ $option ] ) ) {
|
||||
}
|
||||
|
||||
if ( isset( $notoptions[ $option ] ) ) {
|
||||
/**
|
||||
* Filters the default value for an option.
|
||||
*
|
||||
@ -194,6 +199,10 @@ function get_option( $option, $default_value = false ) {
|
||||
return apply_filters( "default_option_{$option}", $default_value, $option, $passed_default );
|
||||
}
|
||||
|
||||
$value = wp_cache_get( $option, 'options' );
|
||||
|
||||
if ( false === $value ) {
|
||||
|
||||
$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
|
||||
|
||||
// Has to be get_row() instead of get_var() because of funkiness with 0, false, null values.
|
||||
|
@ -112,7 +112,7 @@ class Tests_Option_Option extends WP_UnitTestCase {
|
||||
wp_cache_set( 'notoptions', $notoptions, 'options' );
|
||||
|
||||
$before = get_num_queries();
|
||||
$value = get_option( 'invalid' );
|
||||
get_option( 'invalid' );
|
||||
$after = get_num_queries();
|
||||
|
||||
$this->assertSame( 0, $after - $before );
|
||||
@ -127,7 +127,7 @@ class Tests_Option_Option extends WP_UnitTestCase {
|
||||
get_option( 'invalid' );
|
||||
|
||||
$before = get_num_queries();
|
||||
$value = get_option( 'invalid' );
|
||||
get_option( 'invalid' );
|
||||
$after = get_num_queries();
|
||||
|
||||
$notoptions = wp_cache_get( 'notoptions', 'options' );
|
||||
@ -137,25 +137,6 @@ class Tests_Option_Option extends WP_UnitTestCase {
|
||||
$this->assertArrayHasKey( 'invalid', $notoptions, 'The "invalid" option should be in the notoptions cache.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 58277
|
||||
*
|
||||
* @covers ::get_option
|
||||
*/
|
||||
public function test_get_option_notoptions_do_not_load_cache() {
|
||||
add_option( 'foo', 'bar', '', false );
|
||||
wp_cache_delete( 'notoptions', 'options' );
|
||||
|
||||
$before = get_num_queries();
|
||||
$value = get_option( 'foo' );
|
||||
$after = get_num_queries();
|
||||
|
||||
$notoptions = wp_cache_get( 'notoptions', 'options' );
|
||||
|
||||
$this->assertSame( 0, $after - $before, 'The options cache was not hit on the second call to `get_option()`.' );
|
||||
$this->assertFalse( $notoptions, 'The notoptions cache should not be set.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::get_option
|
||||
* @covers ::add_option
|
||||
@ -548,4 +529,88 @@ class Tests_Option_Option extends WP_UnitTestCase {
|
||||
$updated_notoptions = wp_cache_get( 'notoptions', 'options' );
|
||||
$this->assertArrayNotHasKey( $option_name, $updated_notoptions, 'The "foobar" option should not be in the notoptions cache after adding it.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that get_option() does not hit the external cache multiple times for the same option.
|
||||
*
|
||||
* @ticket 62692
|
||||
*
|
||||
* @covers ::get_option
|
||||
*
|
||||
* @dataProvider data_get_option_does_not_hit_the_external_cache_multiple_times_for_the_same_option
|
||||
*
|
||||
* @param int $expected_connections Expected number of connections to the memcached server.
|
||||
* @param bool $option_exists Whether the option should be set. Default true.
|
||||
* @param string $autoload Whether the option should be auto loaded. Default true.
|
||||
*/
|
||||
public function test_get_option_does_not_hit_the_external_cache_multiple_times_for_the_same_option( $expected_connections, $option_exists = true, $autoload = true ) {
|
||||
if ( ! wp_using_ext_object_cache() ) {
|
||||
$this->markTestSkipped( 'This test requires an external object cache.' );
|
||||
}
|
||||
|
||||
if ( false === $this->helper_object_cache_stats_cmd_get() ) {
|
||||
$this->markTestSkipped( 'This test requires access to the number of get requests to the external object cache.' );
|
||||
}
|
||||
|
||||
if ( $option_exists ) {
|
||||
add_option( 'ticket-62692', 'value', '', $autoload );
|
||||
}
|
||||
|
||||
wp_cache_delete_multiple( array( 'ticket-62692', 'notoptions', 'alloptions' ), 'options' );
|
||||
|
||||
$connections_start = $this->helper_object_cache_stats_cmd_get();
|
||||
|
||||
$call_getter = 10;
|
||||
while ( $call_getter-- ) {
|
||||
get_option( 'ticket-62692' );
|
||||
}
|
||||
|
||||
$connections_end = $this->helper_object_cache_stats_cmd_get();
|
||||
|
||||
$this->assertSame( $expected_connections, $connections_end - $connections_start );
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public function data_get_option_does_not_hit_the_external_cache_multiple_times_for_the_same_option() {
|
||||
return array(
|
||||
'exists, autoload' => array( 1, true, true ),
|
||||
'exists, not autoloaded' => array( 3, true, false ),
|
||||
'does not exist' => array( 3, false ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get the number of get commands from the external object cache.
|
||||
*
|
||||
* @return int|false Number of get command calls, false if unavailable.
|
||||
*/
|
||||
public function helper_object_cache_stats_cmd_get() {
|
||||
if ( ! wp_using_ext_object_cache() || ! function_exists( 'wp_cache_get_stats' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$stats = wp_cache_get_stats();
|
||||
|
||||
// Check the shape of the stats.
|
||||
if ( ! is_array( $stats ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the first server's stats.
|
||||
$stats = array_shift( $stats );
|
||||
|
||||
if ( ! is_array( $stats ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! array_key_exists( 'cmd_get', $stats ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $stats['cmd_get'];
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user