rename project to MultiforaDB

Prose and benchmark tables use MultiforaDB; the binary, the CLI usage
line, the log-message prefix and the default database file use
multiforadb.

Two consequences worth noting:

- build.zig.zon's fingerprint is derived from the package name, so it
  had to change with it (Zig refuses to build otherwise). A consumer
  pinning this package by fingerprint needs updating.
- the default --db path is now multiforadb.log, and getCmdLineOpts
  reports it as dbpath. An existing mongo-lite.log has to be passed
  explicitly with --db.

The e2e harness abbreviated the old name as ML_; that is now MFDB_,
including the documented ML_BIN override (MFDB_BIN) and the scratch
file names. MD_ (mongod) is untouched.

compare-run.sh spawned the server by absolute path under a
sandbox/mongo-lite directory that no longer exists; that block already
runs from tests/e2e, so it uses a relative path now.

The archived reports under tests/e2e/results/ keep the old name: they
record what the old binary measured.
This commit is contained in:
2026-08-03 12:35:01 +03:00
parent ac464f2b92
commit d4c9b04f21
20 changed files with 129 additions and 129 deletions

View File

@@ -17,14 +17,14 @@ const std = @import("std");
/// Panic unless `ok`. Active in every optimize mode; see the module comment.
pub fn assert(ok: bool) void {
if (!ok) @panic("mongo-lite: assertion failed");
if (!ok) @panic("multiforadb: assertion failed");
}
/// Panic unless `ok`, naming the invariant that broke. Prefer this where the
/// condition alone does not say what went wrong -- the message lands in the
/// crash output, which may be all an operator has to go on.
pub fn assert_msg(ok: bool, comptime message: []const u8) void {
if (!ok) @panic("mongo-lite: assertion failed: " ++ message);
if (!ok) @panic("multiforadb: assertion failed: " ++ message);
}
test "assert passes on true and is callable in every mode" {

View File

@@ -170,7 +170,7 @@ pub fn dispatch(ctx: *Context, msg: *wire.Message, reply: *wire.Reply) !void {
// rather than turning an applied write into an error the client retries.
if (ctx.engine.take_compact()) {
ctx.engine.compact() catch |err| {
std.debug.print("mongo-lite: compaction failed: {s}\n", .{@errorName(err)});
std.debug.print("multiforadb: compaction failed: {s}\n", .{@errorName(err)});
ctx.engine.request_compact();
};
}
@@ -226,7 +226,7 @@ fn cmd_ping(_: *Context, _: *wire.Message, reply: *wire.Reply) !void {
fn cmd_build_info(_: *Context, _: *wire.Message, reply: *wire.Reply) !void {
try reply.put("version", .{ .string = "4.4.0" });
try reply.put("gitVersion", .{ .string = "mongo-lite" });
try reply.put("gitVersion", .{ .string = "multiforadb" });
try reply.put("versionArray", .{ .array = try int_array(reply, &.{ 4, 4, 0, 0 }) });
try reply.put("openssl", .{ .doc = &.{} });
try reply.put("loaderFlags", .{ .string = "" });
@@ -283,7 +283,7 @@ fn cmd_host_info(ctx: *Context, _: *wire.Message, reply: *wire.Reply) !void {
fn cmd_get_cmd_line_opts(_: *Context, _: *wire.Message, reply: *wire.Reply) !void {
const argv = try reply.arena_alloc().alloc(bson.Pair, 2);
argv[0] = .{ .key = "dbpath", .value = .{ .string = "mongo-lite.log" } };
argv[0] = .{ .key = "dbpath", .value = .{ .string = "multiforadb.log" } };
argv[1] = .{ .key = "port", .value = .{ .int32 = 27017 } };
try reply.put("argv", .{ .array = &.{} });
try reply.put("parsed", .{ .doc = argv });

View File

@@ -986,7 +986,7 @@ pub const Engine = struct {
// epilogue called us.
self.request_compact();
std.debug.print(
"mongo-lite: compaction gave up after {d} attempts (concurrent writes); will retry\n",
"multiforadb: compaction gave up after {d} attempts (concurrent writes); will retry\n",
.{attempt_max},
);
}
@@ -1045,7 +1045,7 @@ pub const Engine = struct {
while (doc_it.next()) |doc_entry| {
ix.append_doc_entries(self.gpa, coll.doc_bytes(doc_entry.value_ptr.*), doc_entry.key_ptr.*) catch |err| switch (err) {
error.ParallelArrays => {
std.debug.print("mongo-lite: WARNING: index '{s}' cannot index an existing document; entry skipped\n", .{ix.name});
std.debug.print("multiforadb: WARNING: index '{s}' cannot index an existing document; entry skipped\n", .{ix.name});
continue;
},
else => return err,
@@ -1053,7 +1053,7 @@ pub const Engine = struct {
}
// Tolerated, not enforced: the database must always open.
if (try ix.finish_bulk(self.gpa, false)) {
std.debug.print("mongo-lite: WARNING: unique index '{s}' has duplicate keys in existing data; duplicates not enforced for existing documents\n", .{ix.name});
std.debug.print("multiforadb: WARNING: unique index '{s}' has duplicate keys in existing data; duplicates not enforced for existing documents\n", .{ix.name});
}
}
@@ -1103,7 +1103,7 @@ fn apply_record(ctx: *anyopaque, record: storage.Record, doc: *bson.Document) an
switch (record.type) {
storage.record_type_index_create => {
self.register_index_from_spec(coll, doc) catch |err| {
std.debug.print("mongo-lite: index create record failed to apply: {s}\n", .{@errorName(err)});
std.debug.print("multiforadb: index create record failed to apply: {s}\n", .{@errorName(err)});
return;
};
return;
@@ -1121,7 +1121,7 @@ fn apply_record(ctx: *anyopaque, record: storage.Record, doc: *bson.Document) an
}
const id_value = doc.get("_id") orelse {
std.debug.print("mongo-lite: log record without _id, skipping\n", .{});
std.debug.print("multiforadb: log record without _id, skipping\n", .{});
return;
};
const id_key = try bson.serialize_value(self.gpa, id_value);

View File

@@ -1,4 +1,4 @@
// mongo-lite core library. Public entry point for tests and the server.
// multiforadb core library. Public entry point for tests and the server.
pub const assert = @import("assert.zig");
pub const bson = @import("bson.zig");

View File

@@ -2,12 +2,12 @@ const std = @import("std");
const mongo = @import("mongo");
const usage =
\\mongo-lite — lightweight MongoDB-compatible document database
\\MultiforaDB — lightweight MongoDB-compatible document database
\\
\\usage: mongo-lite [options]
\\usage: multiforadb [options]
\\ --port <n> listen port (default 27017)
\\ --bind <ip> bind address (default 127.0.0.1)
\\ --db <path> database file (default mongo-lite.log)
\\ --db <path> database file (default multiforadb.log)
\\ --ttl-sweep-secs <n>
\\ seconds between TTL index sweeps (default 60, 0 disables)
\\ --compact-threshold <bytes>
@@ -47,7 +47,7 @@ fn parse_size_suffix(v: []const u8) ?u64 {
pub fn main(init: std.process.Init) !void {
var port: u16 = 27017;
var bind_ip: []const u8 = "127.0.0.1";
var db_path: []const u8 = "mongo-lite.log";
var db_path: []const u8 = "multiforadb.log";
var ttl_sweep_secs: i64 = 60;
var compact_threshold: u64 = 16 * 1024 * 1024;
@@ -58,7 +58,7 @@ pub fn main(init: std.process.Init) !void {
if (std.mem.eql(u8, arg, "--port")) {
const v = it.next() orelse return error.MissingValue;
port = std.fmt.parseInt(u16, v, 10) catch {
std.debug.print("mongo-lite: invalid port '{s}'\n", .{v});
std.debug.print("multiforadb: invalid port '{s}'\n", .{v});
return error.InvalidPort;
};
} else if (std.mem.eql(u8, arg, "--bind")) {
@@ -72,17 +72,17 @@ pub fn main(init: std.process.Init) !void {
// only thing parseInt would otherwise let through.
ttl_sweep_secs = std.fmt.parseInt(i64, v, 10) catch -1;
if (ttl_sweep_secs < 0) {
std.debug.print("mongo-lite: invalid ttl sweep interval '{s}'\n", .{v});
std.debug.print("multiforadb: invalid ttl sweep interval '{s}'\n", .{v});
return error.InvalidTtlSweepSecs;
}
} else if (std.mem.eql(u8, arg, "--compact-threshold")) {
const v = it.next() orelse return error.MissingValue;
const parsed = parse_size_suffix(v) orelse {
std.debug.print("mongo-lite: invalid compact threshold '{s}'\n", .{v});
std.debug.print("multiforadb: invalid compact threshold '{s}'\n", .{v});
return error.InvalidCompactThreshold;
};
if (parsed < 1024 * 1024) {
std.debug.print("mongo-lite: compact threshold must be at least 1m\n", .{});
std.debug.print("multiforadb: compact threshold must be at least 1m\n", .{});
return error.InvalidCompactThreshold;
}
compact_threshold = parsed;
@@ -90,7 +90,7 @@ pub fn main(init: std.process.Init) !void {
try std.Io.File.writeStreamingAll(.stdout(), init.io, usage);
return;
} else {
std.debug.print("mongo-lite: unknown option '{s}'\n{s}", .{ arg, usage });
std.debug.print("multiforadb: unknown option '{s}'\n{s}", .{ arg, usage });
return error.UnknownOption;
}
}
@@ -99,7 +99,7 @@ pub fn main(init: std.process.Init) !void {
var engine = try mongo.db.Engine.open(init.gpa, init.io, db_path);
defer engine.deinit();
engine.compact_threshold = compact_threshold;
std.debug.print("mongo-lite: opened database '{s}' (compact threshold {d})\n", .{ db_path, compact_threshold });
std.debug.print("multiforadb: opened database '{s}' (compact threshold {d})\n", .{ db_path, compact_threshold });
var server = mongo.server.Server{
.gpa = init.gpa,

View File

@@ -35,7 +35,7 @@ pub const Server = struct {
var listener = try addr.listen(io, .{ .reuse_address = true });
defer listener.deinit(io);
std.debug.print("mongo-lite: listening on {s}:{d}\n", .{ self.bind_ip, self.port });
std.debug.print("multiforadb: listening on {s}:{d}\n", .{ self.bind_ip, self.port });
var group: std.Io.Group = .init;
defer group.cancel(io);
@@ -48,7 +48,7 @@ pub const Server = struct {
const stream = listener.accept(io) catch |err| switch (err) {
error.Canceled => return,
else => {
std.debug.print("mongo-lite: accept error: {s}\n", .{@errorName(err)});
std.debug.print("multiforadb: accept error: {s}\n", .{@errorName(err)});
continue;
},
};
@@ -70,12 +70,12 @@ fn ttl_monitor(io: std.Io, server: *Server) error{Canceled}!void {
try std.Io.sleep(io, interval, .awake);
const now_ms = std.Io.Timestamp.now(io, .real).toMilliseconds();
_ = server.engine.ttl_sweep(now_ms) catch |err| {
std.debug.print("mongo-lite: TTL sweep failed: {s}\n", .{@errorName(err)});
std.debug.print("multiforadb: TTL sweep failed: {s}\n", .{@errorName(err)});
continue;
};
if (server.engine.take_compact()) {
server.engine.compact() catch |err| {
std.debug.print("mongo-lite: compaction failed: {s}\n", .{@errorName(err)});
std.debug.print("multiforadb: compaction failed: {s}\n", .{@errorName(err)});
};
}
}
@@ -120,7 +120,7 @@ fn handle_connection_inner(io: std.Io, stream: std.Io.net.Stream, server: *Serve
reader.interface.readSliceAll(&len_bytes) catch return; // clean client disconnect (EOF or RST)
const total: u32 = std.mem.readInt(u32, &len_bytes, .little);
if (total < 16 or total > wire.max_message_size) {
std.debug.print("mongo-lite: bad message length {d} on conn {d}\n", .{ total, connection_id });
std.debug.print("multiforadb: bad message length {d} on conn {d}\n", .{ total, connection_id });
return;
}
@@ -129,14 +129,14 @@ fn handle_connection_inner(io: std.Io, stream: std.Io.net.Stream, server: *Serve
msg_buf.items.len = total;
std.mem.writeInt(u32, msg_buf.items[0..4], total, .little);
reader.interface.readSliceAll(msg_buf.items[4..]) catch |err| {
std.debug.print("mongo-lite: read error on conn {d}: {s} (body, len {d})\n", .{ connection_id, @errorName(err), total });
std.debug.print("multiforadb: read error on conn {d}: {s} (body, len {d})\n", .{ connection_id, @errorName(err), total });
return;
};
var msg = wire.Message.parse(server.gpa, msg_buf.items) catch |err| {
// Unparseable request: close the connection.
const op: i32 = if (msg_buf.items.len >= 16) std.mem.readInt(i32, msg_buf.items[12..16], .little) else 0;
std.debug.print("mongo-lite: bad message on conn {d}: {s} (opCode {d})\n", .{ connection_id, @errorName(err), op });
std.debug.print("multiforadb: bad message on conn {d}: {s} (opCode {d})\n", .{ connection_id, @errorName(err), op });
return;
};
defer msg.deinit();
@@ -146,7 +146,7 @@ fn handle_connection_inner(io: std.Io, stream: std.Io.net.Stream, server: *Serve
commands.dispatch(&ctx, &msg, &reply) catch |err| {
// Discard any partial reply (the client would read the first
// ok field, which may already say 1) and send a clean error.
std.debug.print("mongo-lite: dispatch error on conn {d} cmd {s}: {s}\n", .{ connection_id, msg.command_name(), @errorName(err) });
std.debug.print("multiforadb: dispatch error on conn {d} cmd {s}: {s}\n", .{ connection_id, msg.command_name(), @errorName(err) });
reply.pairs.clearRetainingCapacity();
reply.put_error(
@intFromEnum(commands.ErrorCode.internal_error),
@@ -161,16 +161,16 @@ fn handle_connection_inner(io: std.Io, stream: std.Io.net.Stream, server: *Serve
else
reply.build(server.gpa, reply_request_id, msg.request_id, &out_buf);
built catch |err| {
std.debug.print("mongo-lite: reply build error on conn {d}: {s}\n", .{ connection_id, @errorName(err) });
std.debug.print("multiforadb: reply build error on conn {d}: {s}\n", .{ connection_id, @errorName(err) });
return;
};
reply_request_id +%= 1;
writer.interface.writeAll(out_buf.items) catch |err| {
std.debug.print("mongo-lite: write error on conn {d}: {s}\n", .{ connection_id, @errorName(err) });
std.debug.print("multiforadb: write error on conn {d}: {s}\n", .{ connection_id, @errorName(err) });
return;
};
writer.interface.flush() catch |err| {
std.debug.print("mongo-lite: flush error on conn {d}: {s}\n", .{ connection_id, @errorName(err) });
std.debug.print("multiforadb: flush error on conn {d}: {s}\n", .{ connection_id, @errorName(err) });
return;
};
}

View File

@@ -227,14 +227,14 @@ pub const Log = struct {
while (true) {
var hdr: [block_header_len]u8 = undefined;
const n = self.file.readPositionalAll(self.io, &hdr, pos) catch |err| {
std.debug.print("mongo-lite: log read error at {d}: {s}\n", .{ pos, @errorName(err) });
std.debug.print("multiforadb: log read error at {d}: {s}\n", .{ pos, @errorName(err) });
return error.InvalidLog;
};
if (n == 0) return; // clean end
if (n < block_header_len) return; // torn tail: partial block header
const total: u32 = std.mem.readInt(u32, hdr[0..4], .little);
if (total < block_header_len or total - block_header_len > max_block_payload) {
std.debug.print("mongo-lite: corrupt block length {d} at {d}\n", .{ total, pos });
std.debug.print("multiforadb: corrupt block length {d} at {d}\n", .{ total, pos });
return; // torn tail: impossible length, nothing to validate
}
const payload_len: usize = total - block_header_len;
@@ -262,7 +262,7 @@ pub const Log = struct {
codec_raw => try decomp.appendSlice(self.gpa, payload),
codec_lz4 => try lz4_decompress(self.gpa, payload, &decomp),
else => {
std.debug.print("mongo-lite: unknown block codec {d} at {d}\n", .{ codec, pos });
std.debug.print("multiforadb: unknown block codec {d} at {d}\n", .{ codec, pos });
return error.InvalidLog;
},
}
@@ -284,12 +284,12 @@ pub const Log = struct {
if (bytes.len < 4) return error.InvalidLog;
const total: u32 = std.mem.readInt(u32, bytes[0..4], .little);
if (total < header_len) {
std.debug.print("mongo-lite: corrupt record length {d} at {d}\n", .{ total, pos });
std.debug.print("multiforadb: corrupt record length {d} at {d}\n", .{ total, pos });
return error.InvalidLog;
}
const payload_len: usize = total - 4;
if (payload_len > max_record_payload) {
std.debug.print("mongo-lite: record too large at {d}\n", .{pos});
std.debug.print("multiforadb: record too large at {d}\n", .{pos});
return error.InvalidLog;
}
if (bytes.len < total) return error.InvalidLog; // record crosses the block end
@@ -309,7 +309,7 @@ pub const Log = struct {
const doc = try self.gpa.create(bson.Document);
doc.* = bson.Document.parse(self.gpa, doc_bytes) catch {
self.gpa.destroy(doc);
std.debug.print("mongo-lite: unparseable doc in log at {d}\n", .{pos});
std.debug.print("multiforadb: unparseable doc in log at {d}\n", .{pos});
return error.InvalidLog;
};
try callback(ctx, .{