fix: Prevent EXISTS from incrementing keyspace hit/miss stats#3986
fix: Prevent EXISTS from incrementing keyspace hit/miss stats#3986yulazariy wants to merge 1 commit into
Conversation
Add LOOKUP_NOSTATS flag to lookupKeyReadWithFlags in existsCommand so that EXISTS does not affect keyspace_hits or keyspace_misses counters. These stats are meant for cache hit/miss tracking and EXISTS is a key existence check, not a cache access. Signed-off-by: Yehonatan Yulazari <yulazari@amazon.com>
📝 WalkthroughWalkthrough
EXISTS keyspace stats suppression
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~3 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/unit/keyspace.tcl`:
- Line 76: The test at line 76 assumes that nonexistingkey is absent when
calling r exists nonexistingkey, but does not explicitly ensure this beforehand.
This can cause test failures if prior test state leaks and the key actually
exists, preventing the miss path from being exercised. Before the EXISTS call on
nonexistingkey, explicitly delete the key using r del nonexistingkey or assert
its absence to guarantee deterministic behavior and ensure the miss path is
always tested regardless of prior test state.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 8212c92c-acf2-40a1-9bae-102e6dddc662
📒 Files selected for processing (2)
src/db.ctests/unit/keyspace.tcl
| set hits_before [getInfoProperty $info keyspace_hits] | ||
| set misses_before [getInfoProperty $info keyspace_misses] | ||
| r exists existskey | ||
| r exists nonexistingkey |
There was a problem hiding this comment.
Make the miss-path assertion deterministic.
At Line 76, nonexistingkey is assumed absent; if prior test state leaks, this can become a hit and stop exercising the miss path. Explicitly delete/assert absence before the EXISTS call.
Suggested patch
test {EXISTS does not update keyspace hits or misses} {
r set existskey value
+ r del nonexistingkey
set info [r info stats]
set hits_before [getInfoProperty $info keyspace_hits]
set misses_before [getInfoProperty $info keyspace_misses]
r exists existskey
r exists nonexistingkey📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| r exists nonexistingkey | |
| test {EXISTS does not update keyspace hits or misses} { | |
| r set existskey value | |
| r del nonexistingkey | |
| set info [r info stats] | |
| set hits_before [getInfoProperty $info keyspace_hits] | |
| set misses_before [getInfoProperty $info keyspace_misses] | |
| r exists existskey | |
| r exists nonexistingkey |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/unit/keyspace.tcl` at line 76, The test at line 76 assumes that
nonexistingkey is absent when calling r exists nonexistingkey, but does not
explicitly ensure this beforehand. This can cause test failures if prior test
state leaks and the key actually exists, preventing the miss path from being
exercised. Before the EXISTS call on nonexistingkey, explicitly delete the key
using r del nonexistingkey or assert its absence to guarantee deterministic
behavior and ensure the miss path is always tested regardless of prior test
state.
|
Thank you @yulazariy IMO this makes sense. I do think this is makes sense, but it is also a behavioral change (even if never documented) |
|
cool thanks @ranshid Also looks like there is a (not related) flakey test https://github.com/valkey-io/valkey/actions/runs/27496365556/job/81271055172?pr=3986 |
|
@valkey-review-bot Is this a backward compatible change according to semantic versioning? |
|
On the backward-compatibility question (@zuiderkwast): this is a behavioral change to a public, observable interface, not an API-breaking one.
So: API-compatible, but a metric-semantics change. Under semver this fits a minor release (or a patch with an explicit release note), not a silent patch — consistent with @ranshid flagging it as a major-decision. One thing worth settling before merge: the change leaves One inline note on a side effect of the chosen flag. |
|
|
||
| for (j = 1; j < c->argc; j++) { | ||
| if (lookupKeyReadWithFlags(c->db, c->argv[j], LOOKUP_NOTOUCH)) count++; | ||
| if (lookupKeyReadWithFlags(c->db, c->argv[j], LOOKUP_NOTOUCH | LOOKUP_NOSTATS)) count++; |
There was a problem hiding this comment.
LOOKUP_NOSTATS suppresses the keyspace_misses counter, but the keymiss keyspace notification is gated separately on LOOKUP_NONOTIFY (src/db.c:120-121), which is not passed here. So after this change EXISTS on a missing key still fires a NOTIFY_KEY_MISS (keymiss) event while no longer incrementing keyspace_misses — the two were previously in lockstep for this command.
If the intent is "EXISTS is not a cache access," the notification arguably should be suppressed too, for consistency with the stats:
| if (lookupKeyReadWithFlags(c->db, c->argv[j], LOOKUP_NOTOUCH | LOOKUP_NOSTATS)) count++; | |
| if (lookupKeyReadWithFlags(c->db, c->argv[j], LOOKUP_NOTOUCH | LOOKUP_NOSTATS | LOOKUP_NONOTIFY)) count++; |
If firing keymiss for EXISTS is intentional (some clients rely on it for key-tracking/invalidation), then leaving it as-is is fine — but worth confirming, since the divergence is easy to miss.
|
@valkey-review-bot Whether the behavior change breaks the documented behavior depends on whether this behavior is publicly documented for this command and these stats, right? The public documentation is in the valkey-doc repo. |
|
On the documentation question (@zuiderkwast): I can't inspect the
So whether this "breaks documented behavior" reduces entirely to what valkey-doc says about these two INFO fields and whether per-command contribution is described there. If valkey-doc only describes the counters generically (cache hit/miss tracking) without enumerating which commands feed them, this is a semantics shift but not a contradiction of a written contract; if it explicitly lists One code-level note that bears on framing this purely as a "stats" change: with |
Add LOOKUP_NOSTATS flag to lookupKeyReadWithFlags in existsCommand so that EXISTS does not affect keyspace_hits or keyspace_misses counters. These stats are meant for cache hit/miss tracking and EXISTS is a key existence check, not a cache access.