Skip to content

Redis 8.12: bit enumeration, set-member expiration, BLESS (SER011) - #3343

Open
mgravell wants to merge 5 commits into
mainfrom
8.12
Open

mgravell wants to merge 5 commits into
mainfrom
8.12

Conversation

@mgravell

@mgravell mgravell commented Nov 9, 2026

Copy link
Copy Markdown
Collaborator

Integration branch collecting the Redis 8.12 (RC2) feature work, previously reviewed and merged individually:

  • Redis 8.12 BITRANGEINTARRAY (bit enumeration): IDatabase.StringBitPositions #3315 — BITRANGEINTARRAY (bit enumeration): IDatabase.StringBitPositions/StringBitPositionsAsync return the positions of set (or clear) bits in a byte or bit range of a string or native bitmap, with optional paging via LIMIT.
  • Set-member expiration (Redis 8.12): SADDEX / SEXPIRE / SPTTL / SPERSIST on IDatabase #3340 — Set-member expiration: per-member TTLs on sets, mirroring the hash-field expiry surface. SetAdd gains Expiration overloads riding SADDEX (note: the bare form discards an existing member TTL — that is SADDEX's semantic, so plain SADD is not an equivalent fallback), plus SetMemberExpire, SetMemberGetTimeToLive, SetMemberGetExpireDateTime and SetMemberPersist over SEXPIRE/SPEXPIRE/SEXPIREAT/SPEXPIREAT/SPTTL/SPEXPIRETIME/SPERSIST, with the sexpired keyspace notification.
  • Redis 8.12 BLESS (eviction protection) support #3261 — BLESS (eviction protection): per-key eviction-protection flags via IDatabase.KeyBless/KeyUnbless/KeyBlessFlags and the BlessFlags enum, IServer.BlessedKeys for cursor-based enumeration, and the bless/unbless keyspace notifications.

All of the new surface is gated behind the SER011 experimental ID (Experiments.Server_8_12, docs in docs/exp/SER011.md) and version-gated on v8_12_0 (RC2 reports 8.11.241), so nothing lights up against older servers and the API remains subject to change until 8.12 goes GA.

Supporting changes: the test topology moves to the 8.12-rc2 client-libs image (with cluster-bus-port-protected-mode no, which the 8.12 image requires for the plaintext test cluster), and SortedSetScanLarge now counts distinct members because the 8.12 btree zset encoding can return ZSCAN duplicates for an unmodified key (redis/redis#16158).

main has been merged back in so the branch also carries #3341 (CLUSTER SLOT-STATS, SER012) with the shared files reconciled; the merge is conflict-free against current main.

…itions (#3315)

* Plan: StringBitPositions (BITRANGEINTARRAY, Redis 8.12)

* Plan: record the behaviour observed against a local unstable build

* Redis 8.12 BITRANGEINTARRAY: IDatabase.StringBitPositions

Enumerates the set (or, with bit: false, the clear) bit positions in a
byte or bit range of a string or native bitmap, ascending, with an
optional LIMIT; the sibling of StringBitPosition (BITPOS). Reuses
ResultProcessor.Int64Array; the argument tail fits Message.Create, with
the default BYTE omitted as BITCOUNT/BITPOS do. Negative limit throws
client-side.

Gated [Experimental(Experiments.Server_8_12)] (SER011), with
RedisFeatures.v8_12_0 and RedisFeatures.StringBitPositions, matching the
BLESS branch so the two merge textually.

Tests: exact wire bytes for every option combination (BitPositionsRoundTrip),
and live tests in BitTests gated on v8_12_0, observed green against a
local build of unstable (6a5fee67) on RESP2 and RESP3.

Removes the BITRANGEINTARRAY row from the command coverage ledger.

* 8.12 RC2: pin the real pre-release version and run CI against the RC2 image

- RedisFeatures.v8_12_0 is now 8.11.241, which is what 8.12 RC2 reports
  (the earlier 8.12.0 placeholder made the gated tests skip on RC2)
- the test topology image defaults to redislabs/client-libs-test:8.12-rc2
- the cluster configs opt out of the new cluster-bus-port-protected-mode
  check, which otherwise refuses to start a plaintext cluster node on RC2

Validated locally against the RC2 topology: StringBitPositions live tests
and BitPositionsRoundTrip all pass, and the cluster forms cleanly.

* SortedSetScanLarge: count distinct members, tolerating ZSCAN duplicates

The 8.12 btree zset encoding can return duplicate members even for an
unmodified key (redis/redis#16158; the SCAN contract allows it), so the
test now asserts the distinct member count instead of the raw count.
All 8 cases pass against the RC2 topology.
…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 branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant