Step 1 of 3 · Reading · ~2 min
Conditional Writes
String Commands
SET NX & XX — Conditional Writes
Plain SET always succeeds. Real applications frequently need something stronger: "only write this if nobody else already has," or "only update this if it already exists." Redis exposes both as flags on SET itself, rather than as separate commands — an important design choice worth understanding before you implement it.
The two flags
SET key value NX— Not eXists: write only if the key is currently absent. Returns+OK\r\non success,$-1\r\n(null) if the key already existed and nothing was written.SET key value XX— eXists: write only if the key is currently present. Returns+OK\r\non success,$-1\r\nif the key didn't exist.
Note both "conditional failure" cases return null, not an error — failing the condition is a normal, expected outcome (like GET on a missing key), not something's gone wrong.
Why NX matters: distributed locking
SET lock_key token NX is the textbook building block for a distributed lock: only one client's SET can succeed when the key is absent, so "I got +OK" means "I hold the lock." This is precisely why the check-and-write must happen as a single atomic command rather than a client doing EXISTS then SET — two separate round trips have a race window where two clients could both see the key absent and both proceed to write. Because your Redis clone processes one command to completion before reading the next, implementing NX as a single handler function gives you this atomicity for free.
Implementation
Parse the flags out of the trailing arguments before deciding what to do:
Edge cases
- NX and XX together are mutually exclusive in real Redis —
SET key val NX XXreturns a syntax error. Decide whether your implementation enforces this or just lets XX's check run after NX's (which would always fail since a key can't simultaneously not-exist and exist) — either way, don't silently succeed. - Flags are case-insensitive just like command names:
nx,Nx,NXshould all work — normalize with.upper()as shown above. - Order of arguments: real Redis also allows
EX/PXalongsideNX/XXin the sameSETcall (you'll add that in the next lesson) — structure your flag parsing as a generic loop overrestnow so it's easy to extend rather than hard-coding "flags are always at position 2 and 3." - Don't confuse "returns null because the condition failed" with "returns null because of an error" — these must produce the exact same byte pattern (
$-1\r\n) as aGETmiss, since that's what the null bulk string means in RESP.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…