Skip to content

Add SETNE#4258

Closed
erikdubbelboer wants to merge 1 commit intoredis:unstablefrom
erikdubbelboer:setne
Closed

Add SETNE#4258
erikdubbelboer wants to merge 1 commit intoredis:unstablefrom
erikdubbelboer:setne

Conversation

@erikdubbelboer
Copy link
Contributor

Add command to only set a value when it's different than the current value. This is useful when listening for changes and you don't want to be notified when a value doesn't change.

This native command is about 3 times faster than using a lua script and is only a few new lines.

See: https://www.reddit.com/r/redis/comments/6vry8x/proposed_new_command_setne_set_if_not_equal/

Add command to only set a value when it's different than the current
value. This is useful when listening for changes and you don't want to
be notified when a value doesn't change.
@masterclock
Copy link

what's the progress of this PR?

@slayerulan
Copy link

Any update regarding this PR?

@GeoffreyPlitt
Copy link

+1 Really want this.

@kristoff-it
Copy link
Contributor

Hi, I quickly wrote an implementation of this command as a module.
You can find the source code here:
https://github.com/kristoff-it/redis-setne

If you don't know / care about Zig, just download a pre-compiled dynamic library from the Releases section.

@kinkey
Copy link

kinkey commented Apr 13, 2020

What is the status of this PR? Thanks in advance.

@erikdubbelboer
Copy link
Contributor Author

I could rebase it on master if there was a chance of it being merged. Buf after more thant 2 years I doubt it will be.

@yoav-steinberg yoav-steinberg added state:needs-investigation the problem or solution is not clear, some investigation is needed and removed state:needs-investigation the problem or solution is not clear, some investigation is needed labels Dec 16, 2021
@yoav-steinberg
Copy link
Contributor

yoav-steinberg commented Dec 16, 2021

The pros here are mostly performance related since there's an easy solution using scripting.
The cons are that this might be too specific for string set command and scripting can be used.
@itamarhaber @oranagra WDYT?
In any case I suggest we handle this or close it since it's not a big issue and the PR is ready.

@itamarhaber
Copy link
Member

I think if this is added, instead of a new string command, SETs syntax can be added with an NE flag.

I don't think we should add a new flag though. If a SET doesn't modify the data, did it really happen? Assuming nothing's changed (i.e. also TTL is the same), should an event be generated or even a replication entry for that matter?

@madolson
Copy link
Contributor

Another interesting case that comes to mind is client side caching, it would be an optimization to not invalidate a key if the value didn't change.

Idk though, LUA seems like the right approach here to me, this seems close to CAS which we've also been hesitant to implement. I suppose I would vote to close this, but don't feel strongly.

@yoav-steinberg
Copy link
Contributor

yoav-steinberg commented Dec 19, 2021

I don't think we should add a new flag though. If a SET doesn't modify the data, did it really happen? Assuming nothing's changed (i.e. also TTL is the same), should an event be generated or even a replication entry for that matter?

The problem with treating this as just a SET optimization is:

  • This might be considered a breaking change since in the past we did send notifications on this "nop".
  • There's a serious performance issue here: doing the extra memcmp before each memcpy will definitely make SET slower.

@madolson I'm marking to be closed, as I think this can be treated as a special case of SETCAS (#8361) and we should continue discussion there. I'll reference this ticket there.

@yoav-steinberg yoav-steinberg added the state:to-be-closed requesting the core team to close the issue label Dec 19, 2021
@motz0815
Copy link

The problem with treating this as just a SET optimization is:

* This might be considered a breaking change since in the past we did send notifications on this "nop".

* There's a serious performance issue here: doing the extra `memcmp` before each `memcpy` will definitely make `SET` slower.

@madolson I'm marking to be closed, as I think this can be treated as a special case of SETCAS (#8361) and we should continue discussion there. I'll reference this ticket there.

Wouldn't that be even slower than just adding a new command that does that all by itself?

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

minchopaskal added a commit that referenced this pull request Oct 21, 2025
…nd-delete (#14435)

# Description

Add optimistic locking for string objects via compare-and-set and
compare-and-delete mechanism.

## What's changed

Introduction of new DIGEST command for string objects calculated via
XXH3 hash.

Extend SET command with new parameters supporting optimistic locking.
The new value is set only if checks against a given (old) value or a
given string digest pass.

Introduction of new DELEX command to support conditionally deleting a
key. Conditions are also checks against string value or string digest.

## Motivation

For developers who need to to implement a compare-and-set and
compare-and-delete single-key optimistic concurrency control this PR
provides single-command based implementation.

Compare-and-set and compare-and-delete are mostly used for [Optimistic
concurrency
control](https://en.wikipedia.org/wiki/Optimistic_concurrency_control):
a client (1) fetches the value, keeps the old value (or its digest, for
a large string) in memory, (2) manipulates a local copy of the value,
(3) applies the local changes to the server, but only if the server’s
value hasn’t been changed (still equal to the old value).

Note that compare-and-set [can also be
implemented](https://redis.io/docs/latest/develop/using-commands/transactions/#optimistic-locking-using-check-and-set)
with WATCH … MULTI … EXEC and Lua scripts. The new SET optional
arguments and the DELEX command do not enable new functionality,
however, they are much simpler and faster to use for the very common use
case of single-key optimistic concurrency control.

## Related issues and PRs

#12485
#8361
#4258

## Description of the new commands

### DIGEST

```
DIGEST key
```

Get the hash digest of the value stored in key, as an hex string.

Reply:
- Null if key does not exist
- error if key exists but holds a value which is not a string
- (bulk string) the XXH3 digest of the value stored in key, as an hex
string

### SET

```
SET key value [NX | XX | IFEQ match-value | IFNE match-value | IFDEQ match-digest | IFDNE match-digest] [GET] [EX seconds | PX milliseconds | EXAT unix-time-seconds | PXAT unix-time-milliseconds | KEEPTTL]
```

`IFEQ match-value` - Set the key’s value and expiration only if its
current value is equal to match-value. If key doesn’t exist - it won’t
be created.
`IFNE match-value` - Set the key’s value and expiration only if its
current value is not equal to match-value. If key doesn’t exist - it
will be created.
`IFDEQ match-digest` - Set the key’s value and expiration only if the
digest of its current value is equal to match-digest. If key doesn’t
exist - it won’t be created.
`IFDNE match-digest` - Set the key’s value and expiration only if the
digest of its current value is not equal to match-digest. If key doesn’t
exist - it will be created.

Reply update:
- If GET was not specified:
   - Nil reply if either
- the key doesn’t exist and XX/IFEQ/IFDEQ was specified. The key was not
created.
- the key exists, and NX was specified or a specified
IFEQ/IFNE/IFDEQ/IFDNE condition is false. The key was not set.
   - Simple string reply: OK: The key was set.
- If GET was specified, any of the following:
- Nil reply: The key didn't exist before this command (whether the key
was created or not).
- Bulk string reply: The previous value of the key (whether the key was
set or not).

### DELEX

```
DELEX key [IFEQ match-value | IFNE match-value | IFDEQ match-digest | IFDNE match-digest]
```

Conditionally removes the specified key. A key is ignored if it does not
exist.

`IFEQ match-value` - Delete the key only if its value is equal to
match-value
`IFNE match-value` - Delete the key only if its value is not equal to
match-value
`IFDEQ match-digest` - Delete the key only if the digest of its value is
equal to match-digest
`IFDNE match-digest` - Delete the key only if the digest of its value is
not equal to match-digest

Reply: 
- error if key exists but holds a value that is not a string and
IFEQ/IFNE/IFDEQ/IFDNE is specified.
- (integer) 0 if not deleted (the key does not exist or a specified
IFEQ/IFNE/IFDEQ/IFDNE condition is false), or 1 if deleted.

### Notes

Added copy of xxhash repo to deps -
[version](Cyan4973/xxHash@c961fbe)

---------

Co-authored-by: debing.sun <debing.sun@redis.com>
Co-authored-by: Yuan Wang <wangyuancode@163.com>
@sundb
Copy link
Collaborator

sundb commented Oct 28, 2025

Close via #14435

@sundb sundb closed this Oct 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state:to-be-closed requesting the core team to close the issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.