Skip to content

ZRANGESTORE, GEOSEARCHSTORE and EVAL source keys bypass the key pre-processor - #4675

Merged
ggivo merged 3 commits into
redis:masterfrom
insaf021:command-objects-key-preprocessor
Aug 12, 2026
Merged

ggivo merged 3 commits into
redis:masterfrom
insaf021:command-objects-key-preprocessor

Conversation

@insaf021

@insaf021 insaf021 commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

With a PrefixedKeyArgumentPreProcessor("tenantA:") installed:

zunionstore : [ZUNIONSTORE, tenantA:dst, 1, tenantA:src]
zrangestore : [ZRANGESTORE, tenantA:dst, src, 0, -1]
eval (List) : [EVAL, return 1, 1, tenantA:k, v]
eval (varar): [EVAL, return 1, 1, k, v]

CommandArguments.key(Object) is the only place the pre-processor runs and the only place a key is recorded for slot computation, so a key routed through add() reaches the wire untransformed and never enters getKeys(). ZRANGESTORE then writes inside the namespace and reads from outside it, and the cluster provider sees one slot for a two key command so its multi slot guard cannot fire.

Eighteen sites, all the same shape: the source key of zrangestore and geosearchStore/geosearchStoreStoreDist, and the first keyCount varargs of eval/evalsha. The eval varargs overloads already called addHashSlotKeys, which records the slot but leaves the outgoing argument alone; the List<String> keys overloads beside them were always correct and are untouched.

Without a pre-processor, the eval/evalsha varargs overloads behave exactly as before — their slot keys were already registered via addHashSlotKeys, so this PR only changes which argument value goes out when a pre-processor rewrites keys.

For ZRANGESTORE and GEOSEARCHSTORE there is one behaviour change even without a pre-processor: the source key now enters getKeys(), so on cluster a cross-slot call fails client-side with JedisClusterOperationException instead of being dispatched to the destination's node and rejected by the server with a CROSSSLOT error. Standalone behaviour is unchanged.

Tests: cluster tests assert the cross-slot rejection for every zrangestore/geosearchStore overload and pin eval/evalsha varargs slot registration.

Closes #4674


Note

Medium Risk
Fixes cluster slot tracking and key preprocessing for multi-key commands; behavior is unchanged without a key preprocessor, but cluster routing and prefixed keys now correctly include source keys.

Overview
Fixes source keys bypassing key() registration in zrangestore, geosearchStore/geosearchStoreStoreDist, and eval/evalsha varargs overloads.

Those keys were previously passed with add(), so they skipped key preprocessors and were omitted from cluster slot computation. They now go through key(), matching commands like zunionstore. The eval/evalsha varargs paths also stop using addHashSlotKeys alone (which recorded slots but left wire args untransformed).

Cluster tests assert cross-slot rejection for the fixed commands. Without a key preprocessor, wire behavior is unchanged.

Reviewed by Cursor Bugbot for commit 2a37c60. Bugbot is set up for automated code reviews on this repo. Configure here.

@ggivo ggivo added the waiting-for-triage Still needs to be triaged label Aug 6, 2026
@ggivo

ggivo commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the PR, @insaf021.

Team capacity is limited so PR reviews can take some time. There's a corresponding issue (#4674) that still needs triage and acceptance by the team before the PR proposal can be considered.

key() is where the CommandKeyArgumentPreProcessor is applied and where a key is recorded for hash slot computation. These builders sent the key through add()/addObjects() instead, so it reached the wire untransformed and never entered CommandArguments.getKeys().
@insaf021
insaf021 force-pushed the command-objects-key-preprocessor branch from ad410bc to 550dc4b Compare August 8, 2026 07:31
@insaf021

insaf021 commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

Understood, no rush. I've answered the usage question over on #4674. Also rebased onto master to pick up the redis:8.6.2 pin from #4676, so the unrelated SDR failure on the previous run should clear.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 550dc4bd20

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/test/java/redis/clients/jedis/prefix/PrefixedKeyArgumentsTest.java Outdated
…archStore, eval, evalsha)

Cross-slot zrangestore and geosearchStore are now rejected client-side,
since the source key is registered for slot computation; every overload
is covered. The eval/evalsha varargs tests pin slot registration against
the key()/add() loop rewrite.

Replaces PrefixedKeyArgumentsTest: the store commands regress prefixing
and slot registration together through the same key() call, so the
behavioral cluster tests cover both.
ggivo added a commit that referenced this pull request Aug 12, 2026
Running docs/release-notes/<version>.md file, appended in the same PR
as any user-visible behavior change, so notes are written at merge time
instead of reconstructed at release time. Seeded with the #4675 key
pre-processor entry.
ggivo added a commit that referenced this pull request Aug 12, 2026
Running docs/release-notes/<version>.md file, appended in the same PR
as any user-visible behavior change, so notes are written at merge time
instead of reconstructed at release time. Seeded with the #4675 key
pre-processor entry.
@ggivo
ggivo merged commit 77a9d77 into redis:master Aug 12, 2026
14 checks passed
ggivo added a commit that referenced this pull request Aug 25, 2026
* Start release notes for 8.1.0

Running docs/release-notes/<version>.md file, appended in the same PR
as any user-visible behavior change, so notes are written at merge time
instead of reconstructed at release time. Seeded with the #4675 key
pre-processor entry.

* docs: state the compared versions in the 8.1.0 release notes header

Reviewers couldn't tell which versions the notes cover. Add a Full
Changelog compare link (v8.0.0...master until the tag exists) and fold
the link flip into the release-time step.

* docs: replace changelog compare link with an upgrade-from sentence

The compare link needed a manual update at release time; a plain
sentence states the covered upgrade without maintenance.
@ggivo ggivo added this to the 8.1.0 milestone Aug 28, 2026
@ggivo ggivo added bug and removed enhancement labels Aug 28, 2026
@ggivo ggivo changed the title register source keys via key() in zrangestore, geosearchStore, eval ZRANGESTORE, GEOSEARCHSTORE and EVAL source keys bypass the key pre-processor Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ZRANGESTORE, GEOSEARCHSTORE and EVAL source keys bypass the key pre-processor

2 participants