Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delete Cache by Group #2368

Closed

Conversation

pbearne
Copy link

@pbearne pbearne commented Mar 1, 2022

src/wp-includes/class-wp-object-cache.php Outdated Show resolved Hide resolved
src/wp-includes/class-wp-object-cache.php Outdated Show resolved Hide resolved
src/wp-includes/cache.php Outdated Show resolved Hide resolved
src/wp-includes/cache.php Show resolved Hide resolved
@spacedmonkey
Copy link
Member

If this to live in core there needs to be a compat function found in core in cache-compat.php. This function would need to work for ALL object cache implementation, including and not limited to memcached.

I personally think this is going be nearly impossible, as it is hard to know the implementation details of every object cache. But without that compatible layer, this can not live in core 😞

@tillkruss
Copy link
Member

This function would need to work for ALL object cache implementation, including and not limited to memcached.

It's a FAQ and the suggested approch is using prefixes, which I believe wp-memcached is already using heavily.

pbearne and others added 7 commits March 1, 2022 17:48
Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
…_groups' into INITS-115-Support_flushing_cache_groups
@spacedmonkey
Copy link
Member

Please use remove test for wp_cache_get_linked_meta and revert changes to comments and spacing that are not required for this change.

@spacedmonkey
Copy link
Member

If this is going to make it into core, then we are going to need some constant, like WP_ALLOW_CACHE_GROUPS. Drop-in providers, will have to define this. That way, developers / core can work out if we can even use this function.

Thoughts?

src/wp-includes/cache-compat.php Outdated Show resolved Hide resolved
@tillkruss
Copy link
Member

If this is going to make it into core, then we are going to need some constant, like WP_ALLOW_CACHE_GROUPS. Drop-in providers, will have to define this. That way, developers / core can work out if we can even use this function.

Reminds me of get_theme_support() and add_theme_support().

If we default to flushing the entire cache (in the compatibility method), can you give an example how and where WP_ALLOW_CACHE_GROUPS would be used?

@pbearne
Copy link
Author

pbearne commented Mar 2, 2022

I am not sure we do need the global WP_ALLOW_CACHE_GROUPS as I test for a flush_group function
method_exists( $wp_object_cache, 'flush_group' )
and return false if not available so the calling code and handle it

@spacedmonkey spacedmonkey changed the title Inits 115 support flushing cache groups Delete Cache by Group Apr 5, 2022
Copy link
Member

@tillkruss tillkruss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert debug changes.

src/wp-includes/cache.php Outdated Show resolved Hide resolved
Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>

_doing_it_wrong( __FUNCTION__, __( 'Your implementation of object caching does not support flush by group.' ), '6.0.0' );

return wp_cache_flush();
Copy link
Member

@dd32 dd32 Apr 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a dangerous fallback for this method, having plugin code expecting to flush a specific cache group(s) and then flushing the entire cache is not going to end well.

Additionally, IMHO it's not a _doing_it_wrong() E_USER_DEPRECATED, possibly a E_USER_NOTICE level warning instead though?
(I say this, because with many object caches, it's not possible to flush a specific group, as key-value stores often don't have a "flush keys with this prefix" - Memcache object cache dropin gets around this by prefixing the timestamp to keys, so that it can just switch to a new set of prefixes when flushed)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The worry here, is that if you call this function can expect and clear your group and it doesn't we need to warn developer this is happening. Maybe we should return a WP_Error object?

So you could do this in your own code.

$result = wp_cache_flush_group( 'posts' );
if( is_wp_error( $result ) ) {
    wp_cache_flush();
}

But give devs more control here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the WP_Error approach.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think return false would suffice myself if it wasn't going to flush everything.. "Clear this cache group, sorry, that failed.".

But as mentioned in #2368 (comment) variants whose cache server that don't support clearing by prefix, could rotate a prefix to flush the group.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that means that false, could mean a lot of things. Unsupported and the cache group flush failed. That is unclear for developers that using this function, why the failure.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some feedback from @felixarntz:

What I would suggest is considering making support of this more explicitly optional. For example

  • Not put the flush_group() method in the base class, or alternatively put it in the base class as a no-op that just returns false.
  • Introduce wp_cache_flush_group(), but explicitly document it that it may not be supported and therefore returns a boolean to indicate success, which is critical to check here (other than maybe on other cache functions).
  • In the function, depending on my first point, either check if the method exists on the cache implementation and if not return false, or otherwise just call the method and return through its boolean result.

Alternatively, we could make it even more explicit to clarify that developers need to be aware that this may not work, e.g. by having the boolean function just as a check that has to be explicitly called (e.g. wp_cache_can_flush_group()) before calling wp_cache_flush_group(). The latter could cause a _doing_it_wrong() if not supported or throw an exception.

So TLDR whichever way we go, I definitely think it should be explicitly built and marked as optional.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@felixarntz's comments here reflect statement I have made throughout this code review. These needs to be a way for developers to know if running this function is going to work. They have to know if the object cache implement supports it.

I recommend adding a const, like WP_CACHE_SUPPORTS_GROUP_FLUSH, so developers of object cache drop-ins can "opt-in" to support this feature. If this const is not defined, then, developers know not to use this function.

See these simplier examples.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest is using WP_OBJECTCACHE_* since WP_CACHE refers to WP's "page caching" mechanism.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a half thought in a Slack thread that I'll leave in full detail here so it doesn't get lost.

For a lot of groups currently, WP uses the last_changed cache key to determine when the group was last changed. It acts as a faux group flushing mechanism.

wp_cache_set( 'last_changed', microtime(), 'posts' );

For drop-ins that support the flush_group() method, WP could call that and trust the drop in developer to have checked their persistent cache supports it.

For drop-ins that do not include the method, WP could include something similar to polyfill the feature.

// Within caches
if ( ! method_exists( ... )  && 'wp_group_suffiixes' !== $group ) {
   $group = $group . '::' . wp_cahce_group_suffix( $group );
}

// Function
function wp_cahce_group_suffix( $group, $update = false ) {
  $suffix = wp_cache_get( $group, 'wp_group_suffiixes' );
  if ( ! $update ) {
    return $suffix;
  }
  
  $new_suffix = $suffix;
  while ( $new_suffix === $suffix ) {
     $new_suffix = wp_generate_password( 8, true, true );
  }

  return $new_suffix;
}

At this stage, I'd call this a thought bubble and it absolutely needs further thinking through. One of the issues Dion mentioned in Slack is that there is potential to hit key length issues in some persistent caches.

It's also possible this is a terrible idea.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the discussion for this ticket should move back to the original tickets. GH is a code review tool and not best designed for this.

Copy link
Member

@tillkruss tillkruss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new constant needs to be added to the beginning of src/wp-includes/cache.php. I can't do that in the PR unfortunatly.

define( 'WP_OBJECT_CACHE_SUPPORTS_GROUP_FLUSH', false );

src/wp-includes/cache.php Show resolved Hide resolved
src/wp-includes/cache-compat.php Outdated Show resolved Hide resolved
src/wp-includes/cache-compat.php Outdated Show resolved Hide resolved
src/wp-includes/cache.php Outdated Show resolved Hide resolved
src/wp-includes/class-wp-object-cache.php Outdated Show resolved Hide resolved
pbearne and others added 5 commits April 18, 2022 18:53
Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
@spacedmonkey
Copy link
Member

There seems to be unit tests failing now and coding standards need fixing.

src/wp-includes/cache.php Outdated Show resolved Hide resolved
src/wp-includes/cache-compat.php Outdated Show resolved Hide resolved
pbearne and others added 4 commits April 19, 2022 12:04
Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
src/wp-includes/cache-compat.php Outdated Show resolved Hide resolved
Comment on lines +436 to +438
$this->assertTrue( $results );
$this->assertFalse( wp_cache_get( $key, 'group-test' ), 'test_wp_cache_flush_group: group-test should return false' );
$this->assertSame( $val, wp_cache_get( $key, 'group-kept' ), 'test_wp_cache_flush_group: group-kept should still contain my-val' );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$this->assertTrue( $results );
$this->assertFalse( wp_cache_get( $key, 'group-test' ), 'test_wp_cache_flush_group: group-test should return false' );
$this->assertSame( $val, wp_cache_get( $key, 'group-kept' ), 'test_wp_cache_flush_group: group-kept should still contain my-val' );
if (WP_OBJECT_CACHE_SUPPORTS_GROUP_FLUSH) {
$this->assertTrue( $results );
$this->assertFalse( wp_cache_get( $key, 'group-test' ), 'test_wp_cache_flush_group: group-test should return false' );
$this->assertSame( $val, wp_cache_get( $key, 'group-kept' ), 'test_wp_cache_flush_group: group-kept should still contain my-val' );
} else {
$this->assertWPError( $results );
$this->assertSame( 'unsupported', $results->get_error_code() );
}

tests/phpunit/tests/cache.php Outdated Show resolved Hide resolved
pbearne and others added 2 commits April 19, 2022 13:36
Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
@aksld
Copy link

aksld commented Jul 5, 2022

Hello,

What is the next step ?

Do you need help for something ?

@tillkruss
Copy link
Member

@aksld The memcache object cache used by the tests needs support for this feature. Likely by using prefixes that increment.

@pbearne
Copy link
Author

pbearne commented Jul 12, 2022

closed by #2969

@pbearne pbearne closed this Jul 12, 2022
@spacedmonkey
Copy link
Member

Committed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
6 participants