Repository navigation
Query: key the result cache on what the query-clauses filter changed. - #276
Open
robincornett wants to merge 1 commit into
Open
robincornett wants to merge 1 commit into
robincornett wants to merge 1 commit into
Conversation
A {prefix}_{items}_query_clauses callback can narrow the rows on a query var with no registered default, or on state outside the query vars, and neither reached the cache key, so differently filtered queries shared one entry. Build the request before the cache lookup, record which clauses the filter changed, and hash those alongside the query vars. A query no callback changes keeps its previous key, so results-invariant vars still share one entry.
Fixes berlindb#275.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #275 by keying the result cache on whatever the
{prefix}_{items}_query_clausesfilter changed, in addition to the query vars.filter_query_clauses()records which clauses its callbacks changed (a removed clause asnull), andget_cache_key()hashes that alongside the existing query-var slice. A query no callback changes hashes exactly what it did before, soRESULTS_INVARIANT_VARSand theindex_hintscontract inCacheKeyGuardTestare untouched.get_items()builds the request before the cache lookup (newset_item_ids_request()), so the filter has run when the key is computed.get_item_ids()now only executes it.run_aggregate()is split intoget_aggregate_request()(build) andrun_aggregate()(execute and shape), so aggregate queries get the same treatment.CacheKeyGuardTestcases: a var only a clauses callback reads must segment the key, and a hooked callback that changes nothing must not.Testing
composer validate --strict --no-check-publishvendor/bin/phpstan analyse --memory-limit=1Gvendor/bin/phpcsbin/run-tests.sh -p 8.1 -w 7.1 -- --group defaultbin/run-tests.sh -p 8.2 -w 7.1 -- --group defaultThe new
QueryCacheTestandCacheKeyGuardTestcases fail on master (a22276b): each filtered query gets the other query's cached rows, and the filtered aggregate returns the unfiltered count.Notes
Why not a key built from the compiled SQL (the second option in #275).
index_hintschanges the SQL without changing the rows, andCacheKeyGuardTest::test_index_hints_does_not_segment_cache_key()requires the two to share an entry, so an SQL key would break that by design. It would also need$wpdb->remove_placeholder_escape(), whichInterfaces\Connectiondoesn't expose. Keying on the filter's changes covers the same cases, because the clauses the filter receives are built from vars the parsers register, which the existing slice already hashes.Why not hash every query var (the first option). It misses callbacks that read state outside the query vars, such as a list-table filter reading
$_GET, which no var registration can fix.Behavior changes to review.
%misses the cache across requests. Results stay correct; only that narrow case loses cross-request caching.prime_query()doesn't run the filter, so its primed entries only match unfiltered queries. A filtered query misses rather than reading primed IDs its filter never saw.Backports. #275 also affects 3.0.0 and 2.0.3. I've left
release/3.0.xandrelease/2.0.xalone pending your call on whether to backport.