Support 8.4 CAS/CAD (IF*) operations by mgravell · Pull Request #2978 · StackExchange/StackExchange.Redis (original) (raw)

8.4 adds

IFEQ / IFNE are value equality / non-equality checks; the key is interpreted as a string and checked for full equality against the supplied value. IFDEQ/IFDNE are digest (hash) equality / non-equality checks; the key is interpreted as a string and the digest computed, and the digest is checked for equality against the supplied value. In the case of a test failure, the operation is a no-op and a nil reply is provided, the same as for a XX / NX failure.

The key can also be computed local via xxhash3 (64-bit mode).

This PR:

Note that System.IO.Hashing is consumed to supply XxHash3 - this is a new package dependency, with ns20, net462, net8 and net9 TFMs.

Note: is is planned to combine this work with MSETEX (also 8.4), and use the new expiration abstraction in the new APIs. This means that the current API with TimeSpan? expiry is not "final" - a combined API will allow all of (nothing), EX, PX, EXAT, PXAT, KEEPTTL and PERSIST to be overlapped on a single API, similar to how ValueCondition works here.

Note: CI may fail horribly right now; the 8.4 RC1 ref'd by CI update has glitches that are already fixed. This will be updated (8.4 RC1 is likely to be re-released; it was effectively an internal preview)

Note that all 8.4 features are going to be marked [Experimental] for now, since 8.4 is an RC. This is [SER002] in the API defs below.

The ValueCondition API is worth explicit mention; summary:

[SER002]StackExchange.Redis.ValueCondition (type definition; readonly struct)

[SER002]StackExchange.Redis.ValueCondition.AsDigest() -> StackExchange.Redis.ValueCondition (converts an existing equality condition to a digest condition, by computing the digest; existing digest conditions are unchanged; the equality/non-equality aspect is preserved; "always" etc will throw)

[SER002]StackExchange.Redis.ValueCondition.Value.get -> StackExchange.Redis.RedisValue (gets the underlying value associated with a condition; in the case of a digest, this is based on a long)

[SER002]StackExchange.Redis.ValueCondition.ValueCondition() -> void (implicit constructor, because struct)

[SER002]static StackExchange.Redis.ValueCondition.Always.get -> StackExchange.Redis.ValueCondition (static property, semantically identical to When.Always)

[SER002]static StackExchange.Redis.ValueCondition.CalculateDigest(System.ReadOnlySpan value) -> StackExchange.Redis.ValueCondition (calculate the IFDEQ hash for a given payload; utility method)

[SER002]static StackExchange.Redis.ValueCondition.DigestEqual(in StackExchange.Redis.RedisValue value) -> StackExchange.Redis.ValueCondition (create an IFDEQ condition from a value, by computing the hash)

[SER002]static StackExchange.Redis.ValueCondition.DigestNotEqual(in StackExchange.Redis.RedisValue value) -> StackExchange.Redis.ValueCondition (create an IFDNE condition from a value, by computing the hash)

[SER002]static StackExchange.Redis.ValueCondition.Equal(in StackExchange.Redis.RedisValue value) -> StackExchange.Redis.ValueCondition (create an IFEQ condition from a value, retaining the provided value)

[SER002]static StackExchange.Redis.ValueCondition.Exists.get -> StackExchange.Redis.ValueCondition (static property for an XX condition, semantically identical to When.Exists)

[SER002]static StackExchange.Redis.ValueCondition.implicit operator StackExchange.Redis.ValueCondition(StackExchange.Redis.When when) -> StackExchange.Redis.ValueCondition (allows a When value to be used to specify a ValueCondition)

[SER002]static StackExchange.Redis.ValueCondition.NotEqual(in StackExchange.Redis.RedisValue value) -> StackExchange.Redis.ValueCondition (create an IFNE condition from a value, retaining the provided value)

[SER002]static StackExchange.Redis.ValueCondition.NotExists.get -> StackExchange.Redis.ValueCondition (static property for an NX condition, semantically identical to When.NotExists)

[SER002]static StackExchange.Redis.ValueCondition.operator !(in StackExchange.Redis.ValueCondition value) -> StackExchange.Redis.ValueCondition (negates a condition; NX<-->XX, IFNE<-->IFEQ, IFDNE<-->IFDEQ; others throw)

[SER002]static StackExchange.Redis.ValueCondition.ParseDigest(System.ReadOnlySpan digest) -> StackExchange.Redis.ValueCondition (parses a digest specified as hex bytes into an IFDEQ condition)

[SER002]static StackExchange.Redis.ValueCondition.ParseDigest(System.ReadOnlySpan digest) -> StackExchange.Redis.ValueCondition (parses a digest specified as hex chars into an IFDEQ condition)