wire/server: honour moreToCome on OP_MSG requests
`Message.flags` was parsed and stored but never read. An OP_MSG request with
moreToCome set is fire-and-forget: the client will not read a reply. Sending one
anyway leaves it unread in the socket, so the next command on that connection
reads the previous command's reply and waits forever for its own.
This is not a corner case. Every unacknowledged write uses it, and the Node
driver sends `endSessions` with `writeConcern: {w: 0}` whenever a client closes
-- so an ordinary application that never asks for w:0 still hits it. Before:
insertOne({w: 0}) -> ok, acknowledged=false
countDocuments() (same conn) -> BSON element "cursor" is missing
The command still runs; only the reply is suppressed.
The e2e case pins maxPoolSize to 1, because with a larger pool the driver may
hand the next operation a different connection and hide the bug. It asserts the
connection still works afterwards, which is the part that matters -- not that
the unacknowledged write itself returned.
This commit is contained in:
12
src/wire.zig
12
src/wire.zig
@@ -28,6 +28,18 @@ pub const Message = struct {
|
||||
body: bson.Document,
|
||||
seqs: []const Seq,
|
||||
|
||||
/// OP_MSG flagBits: bit 0 checksumPresent, bit 1 moreToCome, bit 16
|
||||
/// exhaustAllowed.
|
||||
pub const flag_more_to_come: u32 = 1 << 1;
|
||||
|
||||
/// Whether the client declared it will not read a reply to this request
|
||||
/// (unacknowledged writes, `endSessions`). Answering one anyway leaves an
|
||||
/// unread reply in the socket and desyncs every later command on the
|
||||
/// connection -- see the handler in server.zig.
|
||||
pub fn more_to_come(self: *const Message) bool {
|
||||
return self.flags & flag_more_to_come != 0;
|
||||
}
|
||||
|
||||
pub fn parse(gpa: std.mem.Allocator, bytes: []const u8) !Message {
|
||||
if (bytes.len < 16) return error.InvalidMessage;
|
||||
const total: u32 = std.mem.readInt(u32, bytes[0..4], .little);
|
||||
|
||||
Reference in New Issue
Block a user