Skip to:

Opened 9 years ago

Closed 6 years ago

Last modified 3 years ago

#6643 closed enhancement (maybelater)

Incrementor-based caching for ID queries

Reported by: boonebgorges's profile boonebgorges Owned by:
Milestone: Priority: normal
Severity: normal Version:
Component: Performance Keywords: trac-tidy-2018


In an increasing number of places in BP, we use the following pattern:

  1. Query for an array of IDs whose objects match the passed params
  2. Prime the cache for the full items (if necessary)
  3. Server the objects from the cache.

We do this for activity and members, and we should do it for groups etc too.

The second half of this process is fairly cache-optimized. Activity items, for example, are cached individually. But the first part, where activity queries take place, is not cached at all.

The challenge with caching ID queries is that the queries themselves can vary greatly based on the params passed to the function. This makes it nearly impossible to do highly focused cache invalidation. (For example, if a new activity item is posted in a group, you need to invalidate the cache for: (a) all pages of the group's activity, (b) all pages of the group's activity, as filterable by the "Show" dropdown, (c) the All Activity query, (d) the All Activity query, as filtered by the "Show" dropdown, (e) the My Groups and other activity queries for each member of the group, etc etc etc.)

This is a case where we can take a page from WP's playbook. In the taxonomy component (and to some extent in comments and posts), a cache incrementor 'last_changed' is used. By creating a cache key that's a hash of last_changed + the query vars, you have a simple method for cache invalidation: whenever new activity (or whatever) is created, bump last_changed. Now all cache using a key generated from last_changed is invalidated. See get_terms().

Zach Tollman wrote a nice piece about the strategy a few years ago: The biggest challenge is making sure that we work reasonably well with cache backends that have suboptimal eviction policies. One idea is this: there are two incrementor-related items in the cache. One is the last_changed key itself. The other is an array of all cache keys that use that particular last_changed key. When we increment, we use that array to delete the stale cache items. So invalidation would look like this:

function bp_increment_last_changed( $cache_group ) {
    $last_changed = wp_cache_get( 'last_changed', $cache_group );
    $keys = wp_cache_get( 'last_changed_cache_keys', $cache_group );
    foreach ( $keys as $key ) {
        wp_cache_delete( $key, $cache_group );

    wp_cache_delete( 'last_changed_cache_keys', $cache_group );
    wp_cache_set( 'last_changed', microtime(), $cache_group );

and when we cache a query, we do it like this:

$last_changed = wp_cache_get( 'last_changed', 'bp_activity' );
$cache_key = $last_changed . md5( $some_cleanedup_version_of_the_query_params );

// do the query

wp_cache_set( $cache_key, $query_results, 'bp_activity' );
$cache_keys = wp_cache_get( 'last_changed_cache_keys', 'bp_activity' );
$cache_keys[] = $cache_key;
wp_cache_set( 'last_changed_cache_keys', $cache_keys, 'bp_activity' );

Or something like that.


Change History (8)

#1 @DJPaul
9 years ago

  • Component changed from API to API - Cache
  • Milestone changed from Awaiting Review to Future Release

Looks good.

#2 @boonebgorges
8 years ago

  • Milestone changed from Future Release to 2.6

I'd like to look at implementing this for at least one component during 2.6.

This ticket was mentioned in Slack in #buddypress by boone. View the logs.

8 years ago

#4 @DJPaul
8 years ago

  • Milestone changed from 2.6 to Future Release

#5 @DJPaul
8 years ago

  • Component changed from API - Cache to Performance

#6 @boonebgorges
8 years ago

This task has been completed in the following components in BP 2.7:

Primary queries that still need attention:

  • the ID query in BP_User_Query
  • XProfile - it's already partly done (I think xprofile_groups) but could use more review
  • Messages

#7 @DJPaul
6 years ago

  • Keywords trac-tidy-2018 added

We're closing this ticket because it has not received any contribution or comments for at least two years. We have decided that it is better to close tickets that are good ideas, which have not gotten (or are unlikely to get) contributions, rather than keep things open indefinitely. This will help us share a more realistic roadmap for BuddyPress with you.

Everyone very much appreciates the time and effort that you spent sharing your idea with us. On behalf of the entire BuddyPress team, thank you.

If you feel strongly that this enhancement should still be added to BuddyPress, and you are able to contribute effort towards it, we encourage you to re-open the ticket, or start a discussion about it in our Slack channel. Please consider that time has proven that good ideas without contributions do not get built.

For more information, see
or find us on Slack, in the #buddypress channel:

#8 @DJPaul
6 years ago

  • Milestone Awaiting Contributions deleted
  • Resolution set to maybelater
  • Status changed from new to closed
Note: See TracTickets for help on using tickets.