Locks Lab: Wrong-Owner DEL
This lab shows a subtle Redis lock bug: a worker whose lock expired can wake up and delete a lock now owned by another worker.
SET NX PX, release with plain DEL.Redis Commands
SET key value NX PX ttl
Acquires the lock only when missing. NX means do not overwrite an existing owner. PX sets TTL in milliseconds.
GET key
Reads the current lock owner token. The token is the proof of ownership.
DEL key
Deletes the lock. Plain DEL is unsafe because it does not verify ownership.
EVAL script keys args
Runs compare-and-delete atomically so no other command interleaves between GET and DEL.
Lua Release Script
if redis.call('GET', KEYS[1]) == ARGV[1] then
return redis.call('DEL', KEYS[1])
else
return 0
end
KEYS[1]The lock key, lock:inventory.
ARGV[1]The caller's ownership token, such as w3-i7.
redis.call('GET', KEYS[1])Reads the current owner inside Redis.
== ARGV[1]Checks whether the caller still owns the lock.
DELDeletes only on token match. Token mismatch returns 0 and preserves the successor's lock.
Run Targets
The runnable lab is labs/redis/locks, backed by labs/redis/cmd/locks.
make break
Naive release. Look for WRONG-OWNER DEL lines.
make test
Lua release. Look for expired holders skipping DEL.
make load
More workers and iterations to stress the release invariant.
Important Limit
Code Pointers
| Code | Why it matters |
|---|---|
cmd/locks/main.go | The expired-owner scenario, unsafe DEL, and Lua compare-and-delete release. |
locks/Makefile | Targets for unsafe release, safe release, and stress runs. |
locks/compose.yaml | Redis container used by the lab. |
locks/README.md | Expected output and the limit of compare-and-delete. |