Make WordPress Core


Ignore:
Timestamp:
10/18/2022 06:14:01 PM (3 years ago)
Author:
davidbaumwald
Message:

Networks and Sites: Revert the use of the metadata API for *_network_options functions.

[54080] refactored the logic in get_network_option(), update_network_option() and delete_network_option() to use the metadata API. However, this change resulted in issues with large multisite installs that utilize memcached having network options > 1MB in size.

This change reverts [54080] and all related follow-up changes.

Reverts [54080], [54081], and [54082]. Partially reverts [54267] and [54402].

Props pavelschoffer, rebasaurus, johnbillion, spacedmonkey, desrosj, rinatkhaziev.
Fixes #56845.
See #37181.

File:
1 edited

Legend:

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

    r54345 r54637  
    349349 *
    350350 * @since 3.0.0
    351  * @since 6.1.0 Now uses update_meta_cache().
     351 *
     352 * @global wpdb $wpdb WordPress database abstraction object.
    352353 *
    353354 * @param int $network_id Optional site ID for which to query the options. Defaults to the current site.
    354355 */
    355356function wp_load_core_site_options( $network_id = null ) {
    356     if ( ! is_multisite() || wp_installing() ) {
     357    global $wpdb;
     358
     359    if ( ! is_multisite() || wp_using_ext_object_cache() || wp_installing() ) {
    357360        return;
    358361    }
     
    362365    }
    363366
    364     update_meta_cache( 'site', $network_id );
     367    $core_options = array( 'site_name', 'siteurl', 'active_sitewide_plugins', '_site_transient_timeout_theme_roots', '_site_transient_theme_roots', 'site_admins', 'can_compress_scripts', 'global_terms_enabled', 'ms_files_rewriting' );
     368
     369    $core_options_in = "'" . implode( "', '", $core_options ) . "'";
     370    $options         = $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value FROM $wpdb->sitemeta WHERE meta_key IN ($core_options_in) AND site_id = %d", $network_id ) );
     371
     372    $data = array();
     373    foreach ( $options as $option ) {
     374        $key                = $option->meta_key;
     375        $cache_key          = "{$network_id}:$key";
     376        $option->meta_value = maybe_unserialize( $option->meta_value );
     377
     378        $data[ $cache_key ] = $option->meta_value;
     379    }
     380    wp_cache_set_multiple( $data, 'site-options' );
    365381}
    366382
     
    13711387 *
    13721388 * @since 4.4.0
    1373  * @since 6.1.0 Now uses get_metadata().
    13741389 *
    13751390 * @see get_option()
    1376  * @see get_metadata()
     1391 *
     1392 * @global wpdb $wpdb WordPress database abstraction object.
    13771393 *
    13781394 * @param int    $network_id ID of the network. Can be null to default to the current network ID.
     
    13821398 */
    13831399function get_network_option( $network_id, $option, $default = false ) {
     1400    global $wpdb;
     1401
    13841402    if ( $network_id && ! is_numeric( $network_id ) ) {
    13851403        return false;
     
    14221440    }
    14231441
    1424     if ( ! is_multisite() ) {
     1442    // Prevent non-existent options from triggering multiple queries.
     1443    $notoptions_key = "$network_id:notoptions";
     1444    $notoptions     = wp_cache_get( $notoptions_key, 'site-options' );
     1445
     1446    if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
     1447
    14251448        /**
    14261449         * Filters the value of a specific default network option.
     
    14371460         * @param int    $network_id ID of the network.
    14381461         */
    1439         $default = apply_filters( "default_site_option_{$option}", $default, $option, $network_id );
     1462        return apply_filters( "default_site_option_{$option}", $default, $option, $network_id );
     1463    }
     1464
     1465    if ( ! is_multisite() ) {
     1466        /** This filter is documented in wp-includes/option.php */
     1467        $default = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id );
    14401468        $value   = get_option( $option, $default );
    14411469    } else {
    1442         $meta = get_metadata_raw( 'site', $network_id, $option );
    1443         if ( is_array( $meta ) && ! empty( $meta ) ) {
    1444             $value = array_shift( $meta );
    1445         } else {
    1446             /** This filter is documented in wp-includes/option.php */
    1447             $value = apply_filters( "default_site_option_{$option}", $default, $option, $network_id );
    1448 
    1449             /** This action is documented in wp-includes/meta.php */
    1450             $value = apply_filters( 'default_site_metadata', $value, $network_id, $option, true, 'site' );
    1451         }
     1470        $cache_key = "$network_id:$option";
     1471        $value     = wp_cache_get( $cache_key, 'site-options' );
     1472
     1473        if ( ! isset( $value ) || false === $value ) {
     1474            $row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
     1475
     1476            // Has to be get_row() instead of get_var() because of funkiness with 0, false, null values.
     1477            if ( is_object( $row ) ) {
     1478                $value = $row->meta_value;
     1479                $value = maybe_unserialize( $value );
     1480                wp_cache_set( $cache_key, $value, 'site-options' );
     1481            } else {
     1482                if ( ! is_array( $notoptions ) ) {
     1483                    $notoptions = array();
     1484                }
     1485
     1486                $notoptions[ $option ] = true;
     1487                wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
     1488
     1489                /** This filter is documented in wp-includes/option.php */
     1490                $value = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id );
     1491            }
     1492        }
     1493    }
     1494
     1495    if ( ! is_array( $notoptions ) ) {
     1496        $notoptions = array();
     1497        wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
    14521498    }
    14531499
     
    14751521 *
    14761522 * @since 4.4.0
    1477  * @since 6.1.0 Now uses add_metadata().
    14781523 *
    14791524 * @see add_option()
    1480  * @see add_metadata()
     1525 *
     1526 * @global wpdb $wpdb WordPress database abstraction object.
    14811527 *
    14821528 * @param int    $network_id ID of the network. Can be null to default to the current network ID.
     
    14861532 */
    14871533function add_network_option( $network_id, $option, $value ) {
     1534    global $wpdb;
     1535
    14881536    if ( $network_id && ! is_numeric( $network_id ) ) {
    14891537        return false;
     
    15151563    $value = apply_filters( "pre_add_site_option_{$option}", $value, $option, $network_id );
    15161564
     1565    $notoptions_key = "$network_id:notoptions";
     1566
    15171567    if ( ! is_multisite() ) {
    15181568        $result = add_option( $option, $value, '', 'no' );
    15191569    } else {
    1520         $value  = sanitize_option( $option, $value );
    1521         $result = add_metadata( 'site', $network_id, wp_slash( $option ), wp_slash( $value ), true );
     1570        $cache_key = "$network_id:$option";
     1571
     1572        // Make sure the option doesn't already exist.
     1573        // We can check the 'notoptions' cache before we ask for a DB query.
     1574        $notoptions = wp_cache_get( $notoptions_key, 'site-options' );
     1575
     1576        if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
     1577            if ( false !== get_network_option( $network_id, $option, false ) ) {
     1578                return false;
     1579            }
     1580        }
     1581
     1582        $value = sanitize_option( $option, $value );
     1583
     1584        $serialized_value = maybe_serialize( $value );
     1585        $result           = $wpdb->insert(
     1586            $wpdb->sitemeta,
     1587            array(
     1588                'site_id'    => $network_id,
     1589                'meta_key'   => $option,
     1590                'meta_value' => $serialized_value,
     1591            )
     1592        );
     1593
     1594        if ( ! $result ) {
     1595            return false;
     1596        }
     1597
     1598        wp_cache_set( $cache_key, $value, 'site-options' );
     1599
     1600        // This option exists now.
     1601        $notoptions = wp_cache_get( $notoptions_key, 'site-options' ); // Yes, again... we need it to be fresh.
     1602
     1603        if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
     1604            unset( $notoptions[ $option ] );
     1605            wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
     1606        }
    15221607    }
    15231608
     
    15611646 *
    15621647 * @since 4.4.0
    1563  * @since 6.1.0 Now uses delete_metadata().
    15641648 *
    15651649 * @see delete_option()
    1566  * @see delete_metadata()
    15671650 *
    15681651 * @global wpdb $wpdb WordPress database abstraction object.
     
    15731656 */
    15741657function delete_network_option( $network_id, $option ) {
     1658    global $wpdb;
     1659
    15751660    if ( $network_id && ! is_numeric( $network_id ) ) {
    15761661        return false;
     
    16011686        $result = delete_option( $option );
    16021687    } else {
    1603         $result = delete_metadata( 'site', $network_id, wp_slash( $option ), '' );
     1688        $row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM {$wpdb->sitemeta} WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
     1689        if ( is_null( $row ) || ! $row->meta_id ) {
     1690            return false;
     1691        }
     1692        $cache_key = "$network_id:$option";
     1693        wp_cache_delete( $cache_key, 'site-options' );
     1694
     1695        $result = $wpdb->delete(
     1696            $wpdb->sitemeta,
     1697            array(
     1698                'meta_key' => $option,
     1699                'site_id'  => $network_id,
     1700            )
     1701        );
    16041702    }
    16051703
     
    16411739 *
    16421740 * @since 4.4.0
    1643  * @since 6.1.0 Now uses update_metadata().
    16441741 *
    16451742 * @see update_option()
    1646  * @see update_metadata()
     1743 *
     1744 * @global wpdb $wpdb WordPress database abstraction object.
    16471745 *
    16481746 * @param int    $network_id ID of the network. Can be null to default to the current network ID.
     
    16521750 */
    16531751function update_network_option( $network_id, $option, $value ) {
     1752    global $wpdb;
     1753
    16541754    if ( $network_id && ! is_numeric( $network_id ) ) {
    16551755        return false;
     
    17011801    }
    17021802
     1803    $notoptions_key = "$network_id:notoptions";
     1804    $notoptions     = wp_cache_get( $notoptions_key, 'site-options' );
     1805
     1806    if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
     1807        unset( $notoptions[ $option ] );
     1808        wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
     1809    }
     1810
    17031811    if ( ! is_multisite() ) {
    17041812        $result = update_option( $option, $value, 'no' );
    17051813    } else {
    1706         $value  = sanitize_option( $option, $value );
    1707         $result = update_metadata( 'site', $network_id, wp_slash( $option ), wp_slash( $value ) );
     1814        $value = sanitize_option( $option, $value );
     1815
     1816        $serialized_value = maybe_serialize( $value );
     1817        $result           = $wpdb->update(
     1818            $wpdb->sitemeta,
     1819            array( 'meta_value' => $serialized_value ),
     1820            array(
     1821                'site_id'  => $network_id,
     1822                'meta_key' => $option,
     1823            )
     1824        );
     1825
     1826        if ( $result ) {
     1827            $cache_key = "$network_id:$option";
     1828            wp_cache_set( $cache_key, $value, 'site-options' );
     1829        }
    17081830    }
    17091831
Note: See TracChangeset for help on using the changeset viewer.