Expand description
One owner at a time, for the state that more than one thread can reach.
The engine is built so that most state has a single owner and needs no lock at all. The stripes are the exception. A stripe is a piece of the keyspace, and once a server runs commands on more than one thread the same stripe can be wanted by two of them at once. This is the thing that decides which one gets it.
It is a spin lock, and that is a deliberate choice rather than a shortcut. A stripe is held for one command, which is tens or hundreds of nanoseconds, so a waiter that parks in the kernel would spend more time going to sleep and waking up than it would have spent waiting. The wait here is a short spin and then a yield, which is the shape that fits a hold time this short. It is the wrong shape for anything held across a syscall, so nothing held across a syscall should use it.
use yo_common::lock::Lock;
let counter = Lock::new(0u64);
*counter.lock() += 1;
assert_eq!(*counter.lock(), 1);§Taking two of them
Two locks taken at once are a deadlock waiting for the order to disagree, and the answer is the one the command layer already uses: when a command names keys in several stripes, the stripes are taken in stripe order, so two commands that want the same pair want it the same way round. Nothing here enforces that, because a lock cannot see the other locks.
What it can see is the other half of the same mistake, which is one thread taking the same lock twice. That is a hang in a release build and there is nothing to see when it happens, so a debug build remembers who holds a lock and panics rather than spinning forever. Tests and the fuzzers run in debug builds, so the mistake is a failure with a message instead of a test that never finishes.