WordPress.org

Make WordPress Core

Changeset 29915


Ignore:
Timestamp:
10/16/2014 04:44:13 AM (6 years ago)
Author:
wonderboymusic
Message:

Cache get_term_by() calls:

  • Add a helper function, wp_get_last_changed(), to retrieve a last-modified timestamp by cache group
  • When caching a term, also make cache entries for slug and name via slug:{$term_id} and name:{$term_id} keys in the $taxonomy:$last_changed bucket that reference the term_id
  • In clean_term_cache() and update_term_cache(), respect $_wp_suspend_cache_invalidation
  • Original term cache entries maintain BC

Adds unit tests.

Props wonderboymusic, tollmanz, boonebgorges.
Fixes #21760.

Location:
trunk
Files:
3 edited

Legend:

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

    r29833 r29915  
    46304630    return (bool) $var;
    46314631}
     4632
     4633/**
     4634 * Helper function to retrieve an incrementer identified by $group
     4635 *
     4636 * @since 4.1.0
     4637 *
     4638 * @param string $group The cache group for the incrementer.
     4639 * @param bool $force Whether or not to generate a new incrementor.
     4640 * @return int The timestamp representing 'last_changed'.
     4641 */
     4642function wp_get_last_changed( $group, $force = false ) {
     4643    $last_changed = wp_cache_get( 'last_changed', $group );
     4644    if ( ! $last_changed || true === $force ) {
     4645        $last_changed = microtime();
     4646        wp_cache_set( 'last_changed', $last_changed, $group );
     4647    }
     4648    return $last_changed;
     4649}
  • trunk/src/wp-includes/taxonomy.php

    r29902 r29915  
    12921292    }
    12931293
     1294    $group = $taxonomy . ':' . wp_get_last_changed( 'terms' );
    12941295    if ( is_object($term) && empty($term->filter) ) {
    1295         wp_cache_add($term->term_id, $term, $taxonomy);
     1296        wp_cache_add( $term->term_id, $term, $taxonomy );
     1297        wp_cache_add( "slug:{$term->slug}", $term->term_id, $group );
     1298        wp_cache_add( "name:" . md5( $term->name ), $term->term_id, $group );
    12961299        $_term = $term;
    12971300    } else {
     
    13041307            if ( ! $_term )
    13051308                return null;
    1306             wp_cache_add($term, $_term, $taxonomy);
     1309            wp_cache_add( $term, $_term, $taxonomy );
     1310            wp_cache_add( "slug:{$_term->slug}", $term, $group );
     1311            wp_cache_add( "name:" . md5( $_term->name ), $term, $group );
    13071312        }
    13081313    }
     
    13761381        return false;
    13771382
     1383    $cache = false;
     1384    $group = $taxonomy . ':' . wp_get_last_changed( 'terms' );
    13781385    if ( 'slug' == $field ) {
    13791386        $field = 't.slug';
     
    13811388        if ( empty($value) )
    13821389            return false;
     1390
     1391        $term_id = wp_cache_get( "slug:{$value}", $group );
     1392        if ( $term_id ) {
     1393            $value = $term_id;
     1394            $cache = true;
     1395        }
    13831396    } else if ( 'name' == $field ) {
    13841397        // Assume already escaped
    13851398        $value = wp_unslash($value);
    13861399        $field = 't.name';
     1400        $term_id = wp_cache_get( "name:" . md5( $value ), $group );
     1401        if ( $term_id ) {
     1402            $value = $term_id;
     1403            $cache = true;
     1404        }
    13871405    } else if ( 'term_taxonomy_id' == $field ) {
    13881406        $value = (int) $value;
    13891407        $field = 'tt.term_taxonomy_id';
    13901408    } else {
     1409        $cache = true;
     1410    }
     1411
     1412    if ( $cache ) {
    13911413        $term = get_term( (int) $value, $taxonomy, $output, $filter);
    1392         if ( is_wp_error( $term ) )
     1414        if ( is_wp_error( $term ) ) {
    13931415            $term = false;
    1394         return $term;
    1395     }
    1396 
    1397     $term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND $field = %s LIMIT 1", $taxonomy, $value) );
     1416        }
     1417    } else {
     1418        $term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND $field = %s LIMIT 1", $taxonomy, $value) );
     1419    }
     1420
    13981421    if ( !$term )
    13991422        return false;
    14001423
    1401     wp_cache_add($term->term_id, $term, $taxonomy);
    1402 
    14031424    /** This filter is documented in wp-includes/taxonomy.php */
    14041425    $term = apply_filters( 'get_term', $term, $taxonomy );
     
    14081429
    14091430    $term = sanitize_term($term, $taxonomy, $filter);
     1431
     1432    wp_cache_add( $term->term_id, $term, $taxonomy );
     1433    wp_cache_add( "slug:{$term->slug}", $term->term_id, $group );
     1434    wp_cache_add( "name:" . md5( $term->name ), $term->term_id, $group );
    14101435
    14111436    if ( $output == OBJECT ) {
     
    18911916
    18921917    $terms = $wpdb->get_results($query);
    1893     if ( 'all' == $_fields ) {
    1894         update_term_cache($terms);
    1895     }
    18961918
    18971919    if ( empty($terms) ) {
     
    35853607 */
    35863608function clean_term_cache($ids, $taxonomy = '', $clean_taxonomy = true) {
    3587     global $wpdb;
     3609    global $_wp_suspend_cache_invalidation, $wpdb;
     3610
     3611    if ( ! empty( $_wp_suspend_cache_invalidation ) ) {
     3612        return;
     3613    }
    35883614
    35893615    if ( !is_array($ids) )
     
    36323658    }
    36333659
    3634     wp_cache_set( 'last_changed', microtime(), 'terms' );
     3660    wp_get_last_changed( 'terms', true );
    36353661}
    36363662
     
    37273753 */
    37283754function update_term_cache($terms, $taxonomy = '') {
     3755    global $_wp_suspend_cache_invalidation;
     3756
     3757    if ( ! empty( $_wp_suspend_cache_invalidation ) ) {
     3758        return;
     3759    }
     3760
    37293761    foreach ( (array) $terms as $term ) {
    37303762        $term_taxonomy = $taxonomy;
     
    37323764            $term_taxonomy = $term->taxonomy;
    37333765
    3734         wp_cache_add($term->term_id, $term, $term_taxonomy);
     3766        wp_cache_add( $term->term_id, $term, $term_taxonomy );
     3767        $group = $term_taxonomy . ':' . wp_get_last_changed( 'terms', true );
     3768        wp_cache_add( "slug:{$term->slug}", $term->term_id, $group );
     3769        wp_cache_add( "name:" . md5( $term->name ), $term->term_id, $group );
    37353770    }
    37363771}
  • trunk/tests/phpunit/tests/term/cache.php

    r27163 r29915  
    9494        _unregister_taxonomy( $tax );
    9595    }
     96
     97    /**
     98     * @ticket 21760
     99     */
     100    function test_get_term_by_slug_cache() {
     101        global $wpdb;
     102        $term_id = $this->factory->term->create( array( 'slug' => 'burrito', 'taxonomy' => 'post_tag' ) );
     103
     104        $queries = $wpdb->num_queries;
     105        get_term_by( 'slug', 'burrito', 'post_tag' );
     106        $initial = $queries + 1;
     107        $this->assertEquals( $initial, $wpdb->num_queries );
     108        $term = get_term_by( 'slug', 'burrito', 'post_tag' );
     109        $this->assertEquals( $initial, $wpdb->num_queries );
     110
     111        $this->assertEquals( $term, wp_cache_get( $term_id, 'post_tag' ) );
     112
     113        $this->assertEquals( get_term( $term_id, 'post_tag' ), $term );
     114        $this->assertEquals( $initial, $wpdb->num_queries );
     115    }
     116
     117    /**
     118     * @ticket 21760
     119     */
     120    function test_get_term_by_slug_cache_update() {
     121        global $wpdb;
     122        $term_id = $this->factory->term->create( array( 'slug' => 'burrito', 'taxonomy' => 'post_tag' ) );
     123
     124        $queries = $wpdb->num_queries;
     125        get_term_by( 'slug', 'burrito', 'post_tag' );
     126        $initial = $queries + 1;
     127        $this->assertEquals( $initial, $wpdb->num_queries );
     128        $term = get_term_by( 'slug', 'burrito', 'post_tag' );
     129        $this->assertEquals( $initial, $wpdb->num_queries );
     130
     131        $this->assertEquals( $term, wp_cache_get( $term_id, 'post_tag' ) );
     132
     133        wp_update_term( $term_id, 'post_tag', array( 'name' => 'Taco' ) );
     134        $this->assertNotEquals( $term, get_term( $term_id, 'post_tag' ) );
     135        $after_queries = $wpdb->num_queries;
     136        get_term_by( 'slug', 'burrito', 'post_tag' );
     137        $this->assertEquals( $after_queries, $wpdb->num_queries );
     138    }
     139
     140    /**
     141     * @ticket 21760
     142     */
     143    function test_get_term_by_name_cache() {
     144        global $wpdb;
     145        $term_id = $this->factory->term->create( array( 'name' => 'burrito', 'taxonomy' => 'post_tag' ) );
     146
     147        $queries = $wpdb->num_queries;
     148        get_term_by( 'name', 'burrito', 'post_tag' );
     149        $initial = $queries + 1;
     150        $this->assertEquals( $initial, $wpdb->num_queries );
     151        $term = get_term_by( 'name', 'burrito', 'post_tag' );
     152        $this->assertEquals( $initial, $wpdb->num_queries );
     153
     154        $this->assertEquals( get_term( $term_id, 'post_tag' ), $term );
     155        $this->assertEquals( $initial, $wpdb->num_queries );
     156    }
     157
     158    /**
     159     * @ticket 21760
     160     */
     161    function test_get_term_by_name_cache_update() {
     162        global $wpdb;
     163        $term_id = $this->factory->term->create( array( 'name' => 'burrito', 'taxonomy' => 'post_tag' ) );
     164
     165        $queries = $wpdb->num_queries;
     166        get_term_by( 'name', 'burrito', 'post_tag' );
     167        $initial = $queries + 1;
     168        $this->assertEquals( $initial, $wpdb->num_queries );
     169        $term = get_term_by( 'name', 'burrito', 'post_tag' );
     170        $this->assertEquals( $initial, $wpdb->num_queries );
     171
     172        wp_update_term( $term_id, 'post_tag', array( 'slug' => 'Taco' ) );
     173        $this->assertNotEquals( $term, get_term( $term_id, 'post_tag' ) );
     174        $after_queries = $wpdb->num_queries;
     175        get_term_by( 'name', 'burrito', 'post_tag' );
     176        $this->assertEquals( $after_queries, $wpdb->num_queries );
     177    }
     178
     179    /**
     180     * @ticket 21760
     181     */
     182    function test_invalidating_term_caches_should_fail_when_invalidation_is_suspended() {
     183        $slug = 'taco';
     184        $name = 'Taco';
     185        $taxonomy = 'post_tag';
     186        $cache_key_slug = 'slug:' . $slug;
     187        $cache_key_name = 'name:' . md5( $name );
     188
     189        $term_id = $this->factory->term->create( array( 'slug' => $slug, 'name' => $name, 'taxonomy' => $taxonomy ) );
     190
     191        $last_changed = wp_get_last_changed( 'terms' );
     192        $group = $taxonomy . ':' . $last_changed;
     193
     194        $term = get_term_by( 'slug', $slug, $taxonomy );
     195
     196        // Verify the term is cached by ID, slug and name
     197        $this->assertEquals( $term, wp_cache_get( $term_id, $taxonomy ) );
     198        $this->assertEquals( $term_id, wp_cache_get( $cache_key_slug, $group ) );
     199        $this->assertEquals( $term_id, wp_cache_get( $cache_key_name, $group ) );
     200
     201        wp_suspend_cache_invalidation();
     202        clean_term_cache( $term_id, $taxonomy );
     203
     204        // Verify that the cached value still matches the correct value
     205        $this->assertEquals( $term, wp_cache_get( $term_id, $taxonomy ) );
     206        $this->assertEquals( $term_id, wp_cache_get( $cache_key_slug, $group ) );
     207        $this->assertEquals( $term_id, wp_cache_get( $cache_key_name, $group ) );
     208
     209        // Verify that last changed has not been updated as part of an invalidation routine
     210        $this->assertEquals( $last_changed, wp_get_last_changed( 'terms' ) );
     211    }
    96212}
Note: See TracChangeset for help on using the changeset viewer.