You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
One command can see a key both live and expired, so a replica can diverge on *STORE-style commands #632
Found in the review of #631 (which fixed #628). A key can pass its deadline in the microseconds between two lookups inside one command. Each lookup reads the clock again, so one command can see the same key as live at one point and as gone at another. A replica never expires keys by its own clock; it holds the key until the master's UNLINK arrives.
SUNIONSTORE d a b on the master reads a as absent and stores b. The command is propagated as is.
The replica still holds a, so it stores a ∪ b.
The later UNLINK a doesn't fix d.
The same can happen with any command whose effect lands on another key: BITOP, PFMERGE, ZUNIONSTORE/ZINTERSTORE, SORT ... STORE, GEOSEARCHSTORE, SMOVE, LMOVE, COPY.
Fix: take one clock reading per command, as Redis does with commandTimeSnapshot(), and use it for every expiry check in that command: is_past, the shard lookups, and the expire-first hook. The key's state is then the same throughout a command, so the hook's decision and the command's lookups agree.
sure, it's yours, thanks @SoumaCloud. it's on 1.3.0 so no rush. the idea is to read the clock once when a command starts (like Redis's commandTimeSnapshot) and pass that time to every expiry check the command does: is_past, the shard lookups, and the expire-first hook in handler::expire_named_keys_first. a good test is a key with a tiny pexpire run through SUNIONSTORE/BITOP/COPY in a loop on a master with a replica, then check the replica's dest key always matches the master's. this is your first PR here so the CI runs need an approval click from us, we'll do that quickly. shout if anything in the handler is unclear.
Activity
SoumaCloud commentedon Nov 11, 2026
Let me try this one @murtazayusuf
murtazayusuf commentedon Nov 11, 2026
sure, it's yours, thanks @SoumaCloud. it's on 1.3.0 so no rush. the idea is to read the clock once when a command starts (like Redis's commandTimeSnapshot) and pass that time to every expiry check the command does: is_past, the shard lookups, and the expire-first hook in handler::expire_named_keys_first. a good test is a key with a tiny pexpire run through SUNIONSTORE/BITOP/COPY in a loop on a master with a replica, then check the replica's dest key always matches the master's. this is your first PR here so the CI runs need an approval click from us, we'll do that quickly. shout if anything in the handler is unclear.