Skip to:
Content

BuddyPress.org

Ticket #7237: 7237.2.diff

File 7237.2.diff, 9.9 KB (added by boonebgorges, 3 years ago)
  • src/bp-activity/bp-activity-cache.php

    diff --git src/bp-activity/bp-activity-cache.php src/bp-activity/bp-activity-cache.php
    index a3a7241..a647e1a 100644
    function bp_activity_clear_cache_for_deleted_activity( $deleted_ids ) { 
    6363        }
    6464}
    6565add_action( 'bp_activity_deleted_activities', 'bp_activity_clear_cache_for_deleted_activity' );
     66
     67/**
     68 * Reset 'last_changed' cache incrementor.
     69 *
     70 * @since 2.7.0
     71 */
     72function bp_activity_reset_cache_incrementor() {
     73        wp_cache_delete( 'last_changed', 'bp_activity' );
     74}
     75add_action( 'bp_activity_delete', 'bp_activity_reset_cache_incrementor' );
     76add_action( 'bp_activity_add', 'bp_activity_reset_cache_incrementor' );
  • src/bp-activity/classes/class-bp-activity-activity.php

    diff --git src/bp-activity/classes/class-bp-activity-activity.php src/bp-activity/classes/class-bp-activity-activity.php
    index c24a533..bfcf975 100644
    class BP_Activity_Activity { 
    645645                         */
    646646                        $activity_ids_sql = apply_filters( 'bp_activity_paged_activities_sql', $activity_ids_sql, $r );
    647647
    648                         $activity_ids = $wpdb->get_col( $activity_ids_sql );
     648                        $cached = bp_core_get_incremented_cache( $activity_ids_sql, 'bp_activity' );
     649                        if ( false === $cached ) {
     650                                $activity_ids = $wpdb->get_col( $activity_ids_sql );
     651                                bp_core_set_incremented_cache( $activity_ids_sql, 'bp_activity', $activity_ids );
     652                        } else {
     653                                $activity_ids = $cached;
     654                        }
    649655
    650656                        $retval['has_more_items'] = ! empty( $per_page ) && count( $activity_ids ) > $per_page;
    651657
    class BP_Activity_Activity { 
    702708                         * @param string $sort      Sort direction for query.
    703709                         */
    704710                        $total_activities_sql = apply_filters( 'bp_activity_total_activities_sql', "SELECT count(DISTINCT a.id) FROM {$bp->activity->table_name} a {$join_sql} {$where_sql}", $where_sql, $sort );
    705                         $total_activities     = $wpdb->get_var( $total_activities_sql );
     711                        $cached = bp_core_get_incremented_cache( $total_activities_sql, 'bp_activity' );
     712                        if ( false === $cached ) {
     713                                $total_activities = $wpdb->get_var( $total_activities_sql );
     714                                bp_core_set_incremented_cache( $total_activities_sql, 'bp_activity', $total_activities );
     715                        } else {
     716                                $total_activities = $cached;
     717                        }
    706718
    707719                        if ( !empty( $r['max'] ) ) {
    708720                                if ( (int) $total_activities > (int) $r['max'] ) {
  • src/bp-core/bp-core-cache.php

    diff --git src/bp-core/bp-core-cache.php src/bp-core/bp-core-cache.php
    index f4bbab0..0573e8a 100644
    function bp_update_meta_cache( $args = array() ) { 
    262262
    263263        return $cache;
    264264}
     265
     266/**
     267 * Gets a cached list of IDs matching a query key.
     268 *
     269 * A utility function for use by query methods like BP_Activity_Activity::get().
     270 *
     271 * @since 2.7.0
     272 *
     273 * @param string $key   Unique key for the query. Usually a SQL string.
     274 * @param string $group Cache group. Eg 'bp_activity'.
     275 * @return array|bool False if no cached values are found, otherwise an array of IDs.
     276 */
     277function bp_core_get_incremented_cache( $key, $group ) {
     278        $cache_key = bp_core_get_incremented_cache_key( $key, $group );
     279        return wp_cache_get( $cache_key, $group );
     280}
     281
     282/**
     283 * Caches a list of IDs matched by an object query.
     284 *
     285 * A utility function for use by query methods like BP_Activity_Activity::get().
     286 *
     287 * @since 2.7.0
     288 *
     289 * @param string $key   Unique key for the query. Usually a SQL string.
     290 * @param string $group Cache group. Eg 'bp_activity'.
     291 * @param array  $ids   Array of IDs.
     292 * @return bool
     293 */
     294function bp_core_set_incremented_cache( $key, $group, $ids ) {
     295        $cache_key = bp_core_get_incremented_cache_key( $key, $group );
     296        return wp_cache_set( $cache_key, $ids, $group );
     297}
     298
     299/**
     300 * Gets the key to be used when caching an ID query using WP's wp_cache_*() functions.
     301 *
     302 * The $key is hashed with a component-specific incrementor, which is used to
     303 * invalidate multiple caches at once.
     304 *
     305 * @since 2.7.0
     306 *
     307 * @param string $key   Unique key for the query. Usually a SQL string.
     308 * @param string $group Cache group. Eg 'bp_activity'.
     309 * @return string
     310 */
     311function bp_core_get_incremented_cache_key( $key, $group ) {
     312        $incrementor = bp_core_get_incrementor( $group );
     313        $cache_key = md5( $key . $incrementor );
     314        return $cache_key;
     315}
     316
     317/**
     318 * Gets a group-specific cache incrementor.
     319 *
     320 * The incrementor is paired with query identifiers (like SQL strings) to
     321 * create cache keys that can be invalidated en masse.
     322 *
     323 * If an incrementor does not yet exist for the given `$group`, one will
     324 * be created.
     325 *
     326 * @since 2.7.0
     327 *
     328 * @param string $group Cache group. Eg 'bp_activity'.
     329 * @return string
     330 */
     331function bp_core_get_incrementor( $group ) {
     332        $incrementor = wp_cache_get( 'last_changed', $group );
     333        if ( ! $incrementor ) {
     334                $incrementor = microtime();
     335                wp_cache_set( 'last_changed', $incrementor, $group );
     336        }
     337
     338        return $incrementor;
     339}
  • tests/phpunit/testcases/activity/cache.php

    diff --git tests/phpunit/testcases/activity/cache.php tests/phpunit/testcases/activity/cache.php
    index 0e4c6dc..0c64771 100644
    class BP_Tests_Activity_Cache extends BP_UnitTestCase { 
    8383
    8484                $this->assertSame( 'bar foo', $a_fp['activities'][0]->content );
    8585        }
     86
     87        /**
     88         * @ticket BP7237
     89         * @ticket BP6643
     90         */
     91        public function test_query_should_be_cached() {
     92                global $wpdb;
     93
     94                $u = $this->factory->user->create();
     95                $a = $this->factory->activity->create( array(
     96                        'component'     => buddypress()->activity->id,
     97                        'type'          => 'activity_update',
     98                        'user_id'       => $u,
     99                        'content'       => 'foo bar',
     100                ) );
     101
     102                $activity_args = array(
     103                        'per_page' => 10,
     104                        'fields' => 'ids',
     105                        'count_total' => true,
     106                );
     107
     108                $a1 = bp_activity_get( $activity_args );
     109
     110                $num_queries = $wpdb->num_queries;
     111
     112                $a2 = bp_activity_get( $activity_args );
     113
     114                $this->assertEqualSets( $a1, $a2 );
     115                $this->assertSame( $num_queries, $wpdb->num_queries );
     116        }
     117
     118        /**
     119         * @ticket BP7237
     120         * @ticket BP6643
     121         */
     122        public function test_query_cache_should_be_skipped_for_different_query_params() {
     123                global $wpdb;
     124
     125                $u = $this->factory->user->create();
     126                $a = $this->factory->activity->create( array(
     127                        'component'     => buddypress()->activity->id,
     128                        'type'          => 'activity_update',
     129                        'user_id'       => $u,
     130                        'content'       => 'foo bar',
     131                ) );
     132
     133                $activity_args = array(
     134                        'per_page' => 10,
     135                        'fields' => 'ids',
     136                        'count_total' => true,
     137                        'filter' => array(
     138                                'component' => buddypress()->activity->id,
     139                        ),
     140                );
     141
     142                $a1 = bp_activity_get( $activity_args );
     143
     144                $num_queries = $wpdb->num_queries;
     145
     146                // This is enough to make the ID and COUNT clause miss the cache.
     147                $activity_args['filter']['action'] = 'activity_update';
     148                $a2 = bp_activity_get( $activity_args );
     149
     150                $this->assertEqualSets( $a1, $a2 );
     151
     152                // Two extra queries: one for the IDs, one for the count.
     153                $n = $num_queries + 2;
     154                $this->assertSame( $num_queries + 2, $wpdb->num_queries );
     155        }
     156
     157        /**
     158         * @ticket BP7237
     159         * @ticket BP6643
     160         */
     161        public function test_query_cache_should_be_invalidated_by_activity_add() {
     162                global $wpdb;
     163
     164                $u = $this->factory->user->create();
     165                $a1 = $this->factory->activity->create( array(
     166                        'component'     => buddypress()->activity->id,
     167                        'type'          => 'activity_update',
     168                        'user_id'       => $u,
     169                        'content'       => 'foo bar',
     170                ) );
     171
     172                $activity_args = array(
     173                        'per_page' => 10,
     174                        'fields' => 'ids',
     175                        'count_total' => true,
     176                );
     177
     178                $q1 = bp_activity_get( $activity_args );
     179
     180                // Bust the cache.
     181                $a2 = $this->factory->activity->create( array(
     182                        'component'     => buddypress()->activity->id,
     183                        'type'          => 'activity_update',
     184                        'user_id'       => $u,
     185                        'content'       => 'foo bar',
     186                ) );
     187
     188                $num_queries = $wpdb->num_queries;
     189
     190                $q2 = bp_activity_get( $activity_args );
     191
     192                $expected = array( $a1, $a2 );
     193
     194                $this->assertEqualSets( $expected, $q2['activities'] );
     195                $this->assertEquals( 2, $q2['total'] );
     196                $this->assertSame( $num_queries + 2, $wpdb->num_queries );
     197        }
     198
     199        /**
     200         * @ticket BP7237
     201         * @ticket BP6643
     202         */
     203        public function test_query_cache_should_be_invalidated_by_activity_edit() {
     204                global $wpdb;
     205
     206                $u = $this->factory->user->create();
     207                $a = $this->factory->activity->create( array(
     208                        'component'     => buddypress()->activity->id,
     209                        'type'          => 'activity_update',
     210                        'user_id'       => $u,
     211                        'content'       => 'foo bar',
     212                ) );
     213
     214                $activity_args = array(
     215                        'per_page' => 10,
     216                        'fields' => 'ids',
     217                        'count_total' => true,
     218                );
     219
     220                $q1 = bp_activity_get( $activity_args );
     221
     222                // Bust the cache.
     223                $this->factory->activity->create( array(
     224                        'id'            => $a,
     225                        'component'     => buddypress()->activity->id,
     226                        'type'          => 'activity_update',
     227                        'user_id'       => $u,
     228                        'content'       => 'foo bar baz',
     229                ) );
     230
     231                $num_queries = $wpdb->num_queries;
     232
     233                $q2 = bp_activity_get( $activity_args );
     234
     235                $this->assertEqualSets( $q1, $q2 );
     236                $this->assertSame( $num_queries + 2, $wpdb->num_queries );
     237        }
     238
     239        /**
     240         * @ticket BP7237
     241         * @ticket BP6643
     242         */
     243        public function test_query_cache_should_be_invalidated_by_activity_delete() {
     244                global $wpdb;
     245
     246                $u = $this->factory->user->create();
     247                $a = $this->factory->activity->create( array(
     248                        'component'     => buddypress()->activity->id,
     249                        'type'          => 'activity_update',
     250                        'user_id'       => $u,
     251                        'content'       => 'foo bar',
     252                ) );
     253
     254                $activity_args = array(
     255                        'per_page' => 10,
     256                        'fields' => 'ids',
     257                        'count_total' => true,
     258                );
     259
     260                $q1 = bp_activity_get( $activity_args );
     261
     262                // Bust the cache.
     263                bp_activity_delete( array(
     264                        'id' => $a,
     265                ) );
     266
     267                $num_queries = $wpdb->num_queries;
     268
     269                $q2 = bp_activity_get( $activity_args );
     270
     271                $this->assertEqualSets( array(), $q2['activities'] );
     272                $this->assertEquals( 0, $q2['total'] );
     273                $this->assertSame( $num_queries + 2, $wpdb->num_queries );
     274        }
    86275}