commands: classify commands into none/read/write lock scopes

This commit is contained in:
mongo-light
2026-08-02 10:30:06 +03:00
parent b71b97824e
commit f705bcf458

View File

@@ -31,9 +31,44 @@ pub const ErrorCode = enum(i32) {
invalid_pipeline_operator = 40324, invalid_pipeline_operator = 40324,
}; };
/// Which lock (if any) a command needs on the engine. Contract: only
/// `.write` commands may call engine mutation functions (insert, replace,
/// remove, drop*, get_or_create_collection, compact); `.read` commands may
/// only read (`get_collection`, `database_names`, `collection_names`);
/// `.none` commands must not touch the engine at all.
const CommandKind = enum { none, read, write };
fn command_kind(name: []const u8) CommandKind {
// Read-only: scan the engine without mutating it.
if (std.mem.eql(u8, name, "find") or
std.mem.eql(u8, name, "count") or
std.mem.eql(u8, name, "aggregate") or
std.mem.eql(u8, name, "listDatabases") or
std.mem.eql(u8, name, "listCollections")) return .read;
// Writes: exclusive, totally ordered.
if (std.mem.eql(u8, name, "create") or
std.mem.eql(u8, name, "drop") or
std.mem.eql(u8, name, "dropDatabase") or
std.mem.eql(u8, name, "insert") or
std.mem.eql(u8, name, "update") or
std.mem.eql(u8, name, "delete") or
std.mem.eql(u8, name, "findAndModify")) return .write;
// Everything else (handshake, admin info, no-ops) needs no lock.
return .none;
}
pub fn dispatch(ctx: *Context, msg: *wire.Message, reply: *wire.Reply) !void { pub fn dispatch(ctx: *Context, msg: *wire.Message, reply: *wire.Reply) !void {
try ctx.engine.lock(); switch (command_kind(msg.command_name())) {
defer ctx.engine.unlock(); .none => {},
.read => {
try ctx.engine.lock_read();
defer ctx.engine.unlock_read();
},
.write => {
try ctx.engine.lock();
defer ctx.engine.unlock();
},
}
const name = msg.command_name(); const name = msg.command_name();
if (std.mem.eql(u8, name, "hello")) return cmd_hello(ctx, reply); if (std.mem.eql(u8, name, "hello")) return cmd_hello(ctx, reply);