Repository navigation
Redis 8.12 BLESS (eviction protection) support - #3261
Merged
Merged
Conversation
mgravell
marked this pull request as ready for review
October 5, 2026 13:39
This was referenced Oct 30, 2026
mgravell
added a commit
that referenced
this pull request
Nov 9, 2026
The hash-field-TTL idea (7.4's HEXPIRE) brought to sets (redis/redis#15938, 8.12-rc2), mirroring the HashField* family: - SetAddAndSetExpiry (SADDEX): add members and/or (re)set their expiration in one atomic call; When.NotExists/Exists map to MNX/MXX, which are all-or-nothing across the batch, exactly as HSETEX's FNX/FXX; the bare form discards an existing TTL, KEEPTTL keeps it - SetMemberExpire (SEXPIRE/SPEXPIRE/SEXPIREAT/SPEXPIREAT by precision) -> ExpireResult[], per member - SetMemberGetTimeToLive (SPTTL) and SetMemberGetExpireDateTime (SPEXPIRETIME) -> long[] - SetMemberPersist (SPERSIST) -> PersistResult[] - KeyNotificationType.SExpired ('sexpired', side-effect block), so the 8.12 notification - including on the subkey channels, whose payload names the lapsed member - parses as a known type; GetSubKeys() already handles the payload Gated [Experimental] behind SER011/Experiments.Server_8_12 and RedisFeatures.v8_12_0 (8.11.241), both shared with #3261/#3315; the test docker image moves to client-libs-test:8.12-rc2 as in those PRs. Round-trip tests pin the exact wire bytes; the live tests (HashFieldTests mirror) pass against the 8.12-rc2 topology on both protocols. Plan document in notes/set-member-expiry/.
mgravell
added a commit
that referenced
this pull request
Nov 9, 2026
…ST on IDatabase (#3340) * Initial support for Redis 8.12 set-member expiration The hash-field-TTL idea (7.4's HEXPIRE) brought to sets (redis/redis#15938, 8.12-rc2), mirroring the HashField* family: - SetAddAndSetExpiry (SADDEX): add members and/or (re)set their expiration in one atomic call; When.NotExists/Exists map to MNX/MXX, which are all-or-nothing across the batch, exactly as HSETEX's FNX/FXX; the bare form discards an existing TTL, KEEPTTL keeps it - SetMemberExpire (SEXPIRE/SPEXPIRE/SEXPIREAT/SPEXPIREAT by precision) -> ExpireResult[], per member - SetMemberGetTimeToLive (SPTTL) and SetMemberGetExpireDateTime (SPEXPIRETIME) -> long[] - SetMemberPersist (SPERSIST) -> PersistResult[] - KeyNotificationType.SExpired ('sexpired', side-effect block), so the 8.12 notification - including on the subkey channels, whose payload names the lapsed member - parses as a known type; GetSubKeys() already handles the payload Gated [Experimental] behind SER011/Experiments.Server_8_12 and RedisFeatures.v8_12_0 (8.11.241), both shared with #3261/#3315; the test docker image moves to client-libs-test:8.12-rc2 as in those PRs. Round-trip tests pin the exact wire bytes; the live tests (HashFieldTests mirror) pass against the 8.12-rc2 topology on both protocols. Plan document in notes/set-member-expiry/. * SADDEX rides SetAdd: two Expiration overloads replace the four-per-arity SetAddAndSetExpiry surface Review feedback (see the PR): Expiration already encodes EX/PX/EXAT/PXAT/KEEPTTL - exactly SADDEX's expiration block - so the TimeSpan?/DateTime/keepTtl splits collapse and the surface is SetAdd(key, value, Expiration, When, flags) and SetAdd(key, values, Expiration, When, flags), both bool (+async): 8 members become 4, with no new method name. A required Expiration keeps overload resolution away from the existing SetAdd members. - Expiration.Persist is rejected (SADDEX has no PERSIST; SetMemberPersist is the way to remove member expirations) - previously it would have been sent as a bogus token. - The overloads always send SADDEX: plain SADD is not an equivalent fallback for the no-expiry form, because bare SADDEX discards an existing member's TTL where SADD leaves existing members untouched; the XML docs call this out, and that the multi-value form reports only whether anything changed, not a count. - The SetMemberExpire/GetTimeToLive/GetExpireDateTime/Persist family is unchanged (ExpireWhen's GT/LT cannot ride Expiration, and it mirrors the HashField shape). - plan.md carries a revision note; SER011.md updated; all 50 SetMemberExpiry tests pass live against 8.12-rc2, 525 KeyPrefixed tests pass. * Each set-member-expiry test deletes its key up front: SADDEX's changed-anything reply and the MNX/NX conditions make residue from a previous run (or the other protocol) look like a failure
Adds KeyBless/KeyUnbless/KeyBlessFlags (+async) on IDatabase and IServer.BlessedKeys (+async) over BLESS SCAN, with the BlessFlags enum, gated behind SER011 (Server_8_12). SET/CLEAR are raised to primary-only; GET stays replica-eligible. Adds bless/unbless keyspace notification types.
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.
Adds client support for the Redis 8.12
BLESScommand family (redis/redis#15649), gated behindSER011(Server_8_12).API
Also:
RedisFeatures.Bless, andKeyNotificationType.Bless/Unblessfor thebless/unblesskeyspace events (classg). After merging main post-#3312 these sit at 66/67, after theSetBit..SDiffStorerange that PR added, and both tokens are in the parser test table.Notes
BLESSis replica-eligible, soGETcan be served by a replica;SET/CLEARare raised to primary-only per message.SET/CLEARare write-checked (the flag state converges),GETis read-only,SCANuses the usual cursor rule.BlessFlags.Noneand undefined bits throw client-side. Unknown tokens in aGETreply are ignored.BLESS SCANalways sendsCOUNT, because the server default (1024) isn't our page size.BLESSis excluded from the Twemproxy and Envoy command maps.redis-oss/client-hld/bless/se-redis.md.Testing
require: v8_12_0) pass on RESP2 and RESP3 againstredislabs/client-libs-test:8.12-m02-int.redislabs/client-libs-test:8.12-rc2. TheNO-EVICTtoken,BLESS SCANargument order, the missing-keyno such keyerrors and thebless/unblesskeyspace events were all re-verified by hand on RC2 and match the implementation.Resolved (was: open before marking ready)
RedisFeatures.v8_12_0is now pinned to8.11.241, which is what 8.12 RC2 reports — the8.12.0placeholder would indeed have made the live tests skip on RCs. The docker topology / CI default image is nowredislabs/client-libs-test:8.12-rc2, withcluster-bus-port-protected-mode noadded to the test cluster configs (RC2 introduces that check and otherwise refuses to start a plaintext cluster node).RC2 ZSCAN duplicates (server behavior change, handled)
The only CI failures on the RC2 image are the 8
ScanTests.SortedSetScanLargecases (all page sizes, RESP2+RESP3): a fullZSCANiteration over a stable 2000-element sorted set returns 2001-2003 entries, with a few members duplicated. Reproduced with pureredis-cliagainstredislabs/client-libs-test:8.12-rc2(deterministic per dataset;ZCARDis 2000, distinct members 2000), clean onredis:8.2, andHSCAN/SSCANare unaffected — a ZSCAN behavior change in the 8.12 btree zset encoding, reported upstream as redis/redis#16158.SortedSetScanLargenow asserts the distinct member count, so CI is expected green; revisit if redis/redis#16158 is fixed before GA. Everything else was already green (6700+ tests).