Make WordPress Core

Changeset 59631

Timestamp:
01/15/2025 10:11:15 PM (14 months ago)
Author:
peterwilsoncc
Message:

Options/Meta APIs: Optimize cache hits for non-existent options.

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.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/option.php

    r59373 r59631  
    163163    if ( ! wp_installing() ) {
    164164        $alloptions = wp_load_alloptions();
    165 
     165        /*
     166         * When getting an option value, we check in the following order for performance:
     167         *
     168         * 1. Check the 'alloptions' cache first to prioritize existing loaded options.
     169         * 2. Check the 'notoptions' cache before a cache lookup or DB hit.
     170         * 3. Check the 'options' cache prior to a DB hit.
     171         * 4. Check the DB for the option and cache it in either the 'options' or 'notoptions' cache.
     172         */
    166173        if ( isset( $alloptions[ $option ] ) ) {
    167174            $value = $alloptions[ $option ];
    168175        } else {
     176
     177
     178
     179
     180
     181
     182
     183
     184
     185
     186
     187
     188
     189
     190
     191
     192
     193
     194
     195
     196
     197
     198
     199
     200
     201
    169202            $value = wp_cache_get( $option, 'options' );
    170203
    171204            if ( false === $value ) {
    172                 // Prevent non-existent options from triggering multiple queries.
    173                 $notoptions = wp_cache_get( 'notoptions', 'options' );
    174 
    175                 // Prevent non-existent `notoptions` key from triggering multiple key lookups.
    176                 if ( ! is_array( $notoptions ) ) {
    177                     $notoptions = array();
    178                     wp_cache_set( 'notoptions', $notoptions, 'options' );
    179                 } elseif ( isset( $notoptions[ $option ] ) ) {
    180                     /**
    181                      * Filters the default value for an option.
    182                      *
    183                      * The dynamic portion of the hook name, `$option`, refers to the option name.
    184                      *
    185                      * @since 3.4.0
    186                      * @since 4.4.0 The `$option` parameter was added.
    187                      * @since 4.7.0 The `$passed_default` parameter was added to distinguish between a `false` value and the default parameter value.
    188                      *
    189                      * @param mixed  $default_value  The default value to return if the option does not exist
    190                      *                               in the database.
    191                      * @param string $option         Option name.
    192                      * @param bool   $passed_default Was `get_option()` passed a default value?
    193                      */
    194                     return apply_filters( "default_option_{$option}", $default_value, $option, $passed_default );
    195                 }
    196205
    197206                $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
  • trunk/tests/phpunit/tests/option/option.php

    r58945 r59631  
    113113
    114114        $before = get_num_queries();
    115         $value  = get_option( 'invalid' );
    116         $after  = get_num_queries();
     115        get_option( 'invalid' );
     116        $after = get_num_queries();
    117117
    118118        $this->assertSame( 0, $after - $before );
     
    128128
    129129        $before = get_num_queries();
    130         $value  = get_option( 'invalid' );
    131         $after  = get_num_queries();
     130        get_option( 'invalid' );
     131        $after = get_num_queries();
    132132
    133133        $notoptions = wp_cache_get( 'notoptions', 'options' );
     
    136136        $this->assertIsArray( $notoptions, 'The notoptions cache should be set.' );
    137137        $this->assertArrayHasKey( 'invalid', $notoptions, 'The "invalid" option should be in the notoptions cache.' );
    138     }
    139 
    140     /**
    141      * @ticket 58277
    142      *
    143      * @covers ::get_option
    144      */
    145     public function test_get_option_notoptions_do_not_load_cache() {
    146         add_option( 'foo', 'bar', '', false );
    147         wp_cache_delete( 'notoptions', 'options' );
    148 
    149         $before = get_num_queries();
    150         $value  = get_option( 'foo' );
    151         $after  = get_num_queries();
    152 
    153         $notoptions = wp_cache_get( 'notoptions', 'options' );
    154 
    155         $this->assertSame( 0, $after - $before, 'The options cache was not hit on the second call to `get_option()`.' );
    156         $this->assertFalse( $notoptions, 'The notoptions cache should not be set.' );
    157138    }
    158139
     
    549530        $this->assertArrayNotHasKey( $option_name, $updated_notoptions, 'The "foobar" option should not be in the notoptions cache after adding it.' );
    550531    }
     532
     533
     534
     535
     536
     537
     538
     539
     540
     541
     542
     543
     544
     545
     546
     547
     548
     549
     550
     551
     552
     553
     554
     555
     556
     557
     558
     559
     560
     561
     562
     563
     564
     565
     566
     567
     568
     569
     570
     571
     572
     573
     574
     575
     576
     577
     578
     579
     580
     581
     582
     583
     584
     585
     586
     587
     588
     589
     590
     591
     592
     593
     594
     595
     596
     597
     598
     599
     600
     601
     602
     603
     604
     605
     606
     607
     608
     609
     610
     611
     612
     613
     614
     615
    551616}
Note: See TracChangeset for help on using the changeset viewer.