Old code was occasionally hitting a s.state == Slot::Writing assertion when
closing the writing state. Since I could not find a specific bug that would
lead to this, I decided to simplify state management by moving Slot locking
further away from the Slot state.
Two kinds of Slot locks are now supported: exclusive and shared. These are
implemented using simple atomic counters. To obtain the shared lock, the slot
must also be in a readable, not-marked-for-freeing state (this is where the
lock and the state still overlap). The code should eventually be polished
to use explicit creation-is-acquisition lock objects.
Old code could not cope with Slot deletion event arriving when the Slot was
being written to. We now mark the slot as in need of freeing, regardless of
the slot state. This may need more work to properly cleanup marked slots.
The old code used open/closeForWriting sequences for rebuilding the map from
disk. There were possibly some race conditions in that code. It is now
replaced with an dedicated, simpler, and optimized putAt() method.