[wp-trac] [WordPress Trac] #25883: get_site_option cache logic for notoptions is incorrect

WordPress Trac noreply at wordpress.org
Fri Nov 8 16:23:05 UTC 2013


#25883: get_site_option cache logic for notoptions is incorrect
--------------------------+-----------------------------
 Reporter:  broveloper    |      Owner:
     Type:  defect (bug)  |     Status:  new
 Priority:  normal        |  Milestone:  Awaiting Review
Component:  Multisite     |    Version:  3.7.1
 Severity:  major         |   Keywords:  needs-patch
--------------------------+-----------------------------
 The core function get_site_option has incorrect logic for
 wp_cache_get(set) for "notoptions".

 **Note: This is a multisite bug**
 Example is if you have 2 networks (A,B) and network(A) has a sitemeta
 record "testmetakey" and network(B) does not.  If network(B) should happen
 to be requested first, then it save the "testmetakey" into the
 "notoptions" array cache.  Then when network(A) makes a request for
 "testmetakey", it will find that "testmetakey" is in the "notoptions"
 cached array, and thus return nothing even though it does have a meta
 value for "testmetakey".  Case and point is "active_sitewide_plugins"

 {{{
 #!php
 function get_site_option( $option, $default = false, $use_cache = true ) {
         global $wpdb;

         // Allow plugins to short-circuit site options.
         $pre = apply_filters( 'pre_site_option_' . $option, false );
         if ( false !== $pre )
                 return $pre;

         // prevent non-existent options from triggering multiple queries
         $notoptions = wp_cache_get( 'notoptions', 'site-options' );
         if ( isset( $notoptions[$option] ) )
                 return apply_filters( 'default_site_option_' . $option,
 $default );

         if ( ! is_multisite() ) {
                 $default = apply_filters( 'default_site_option_' .
 $option, $default );
                 $value = get_option($option, $default);
         } else {
                 $cache_key = "{$wpdb->siteid}:$option";
                 if ( $use_cache )
                         $value = wp_cache_get($cache_key, 'site-options');

                 if ( !isset($value) || (false === $value) ) {
                         $row = $wpdb->get_row( $wpdb->prepare("SELECT
 meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d",
 $option, $wpdb->siteid ) );

                         // Has to be get_row instead of get_var because of
 funkiness with 0, false, null values
                         if ( is_object( $row ) ) {
                                 $value = $row->meta_value;
                                 $value = maybe_unserialize( $value );
                                 wp_cache_set( $cache_key, $value, 'site-
 options' );
                         } else {
                                 $notoptions[$option] = true;
                                 wp_cache_set( 'notoptions', $notoptions,
 'site-options' );
                                 $value = apply_filters(
 'default_site_option_' . $option, $default );
                         }
                 }
         }

         return apply_filters( 'site_option_' . $option, $value );
 }
 }}}

 The cache_key should be using the same logic for options that are not in
 "notoptions":
 {{{
 #!php
 $cache_key = "{$wpdb->siteid}:notoptions";
 }}}


 Patch would be:
 line 760:
 {{{
 #!php
 $notoptions = wp_cache_get( "{$wpdb->siteid}:notoptions", 'site-options'
 );
 }}}

 line 782:
 {{{
 #!php
 wp_cache_set( "{$wpdb->siteid}:notoptions", $notoptions, 'site-options' );
 }}}

 Or set the notoption's cache key in some variable.

--
Ticket URL: <http://core.trac.wordpress.org/ticket/25883>
WordPress Trac <http://core.trac.wordpress.org/>
WordPress blogging software


More information about the wp-trac mailing list