New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
vsr: fix races in client_replies #1515
Conversation
5bdd222
to
5f1a140
Compare
Alternative fix is available at #1513, though I like this version more. |
5f1a140
to
0ba9044
Compare
src/vsr/client_replies.zig
Outdated
@@ -243,6 +243,15 @@ pub fn ClientRepliesType(comptime Storage: type) type { | |||
client_replies.write_reply_next(); | |||
} | |||
|
|||
if (callback == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could rewrite this into const callback = read.callback orelse { ...
to avoid callback.?
later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be a bit more complicated as the read's released here already, but, on balance, yeah, this seems better.
while (reads.next()) |read| { | ||
if (read.slot.index == write.slot.index) return; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe in write_reply_callback
we could iterate the reads and assert that none of them are to the slot that we just wrote?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There actually can be races after the state sync.
TIL: in our testing storage, we forbid write-write races, but allow write-read races. Which ... seems fine? At least in this case.
f464c4e
to
9db2919
Compare
- it might be the case that `writing` bitset is not set, but there's a write for the slot in the queue: replies can wait on read to complete. - when a faulty read completes, it might clobber faulty bit, unset by a a write which was scheduled after the read. The specific series of events here: 1. Replica receives a RequestReply and starts a reply read 2. The read completes with a failure, replica sets the faulty bit 3. Replica receives RequestReply starts a reply read 4. Replica receives Reply and starts a reply write - the write unsets faulty bit - the write doesn't start, because there's a read executing 4. The read completes, setting the faulty bit _again_ 5. Replica receives RequestReply - It _doesn't_ start reply read, because there's an in-progress write that can resolve a read. - But the faulty bit is set, tripping up an assertion. The root issue here is the race between a read and a write for the same reply. Remove the race by explicitly handling the interleaving: * When submitting a read, resolve it immediately if there's a pending write (this was already handled by `read_reply_sync`) * When submitting a write, resolve any pending reads for the same reply. * Remove the code to block the write while the read is in-progress, as this is no longer possible. Note that it is still possible that a read and a write for the same slot race, if they target different replies. In this case, there won't be clobbering, as, when the read completes, we double-check freshness by consulting `client_sessions`. SEED: 2517747396662708227 Closes: #1511
9db2919
to
4db067f
Compare
writing
bitset is not set, but there's a write for the slot in the queue: replies can wait on read to complete.The specific series of events here:
The root issue here is the race between a read and a write for the same reply. Remove the race by explicitly handling the interleaving:
read_reply_sync
)Note that it is still possible that a read and a write for the same slot race, if they target different replies. In this case, there won't be clobbering, as, when the read completes, we double-check freshness by consulting
client_sessions
.SEED: 2517747396662708227
Closes: #1511