Files
MultiforaDB/README.md
2026-08-02 10:42:39 +03:00

84 lines
3.6 KiB
Markdown

# mongo-light
A lightweight, embedded MongoDB-compatible document database written in
Zig 0.16. Like SQLite, it stores everything in a single file; unlike SQLite,
it speaks the MongoDB wire protocol, so real clients — `mongosh`, the Node.js
driver, PyMongo — connect over TCP and just work.
## Quick start
```sh
zig build # build the server
zig build test # run the unit test suite
zig-out/bin/mongo-light --port 27017 --db data.log
# in another terminal:
mongosh --port 27017
> db.users.insertOne({name: "alice", age: 30})
> db.users.find({age: {$gt: 25}}).toArray()
> db.users.updateOne({name: "alice"}, {$set: {vip: true}})
> db.users.deleteOne({name: "bob"})
```
## Features
- **Wire protocol**: OP_MSG (2013) plus legacy OP_QUERY/OP_REPLY (2004/2001)
for the driver handshake; hello/isMaster with `maxWireVersion: 8`, so
modern drivers (Node, Python, mongosh) connect without workarounds.
- **BSON**: full parse/serialize round-trip for all common types
(including binary, regex, timestamps, ObjectId), canonical MongoDB
comparison order for sorting and range queries.
- **CRUD**: `insert`, `find` (filter, sort, skip/limit, projection),
`update` (multi/upsert), `delete`, `findAndModify`, `count`,
`aggregate` (`$match`, `$sort`, `$skip`, `$limit`, `$project`, `$count`,
`$group` with `$sum`), plus `create`/`drop`/`listCollections`/
`listDatabases`/`dropDatabase`.
- **Query operators**: `$eq` `$ne` `$gt` `$gte` `$lt` `$lte` `$in` `$nin`
`$exists` `$regex` (hand-rolled engine: anchors, `.`, `* + ?`, character
classes, groups, alternation, `i`/`s` options) `$not` `$and` `$or` `$nor`
`$size` `$all` `$elemMatch`, with dot paths and array multikey semantics.
- **Update operators**: `$set` `$unset` `$inc` `$push` (`$each`) `$pull`
`$rename`, with dot-path creation (including array indices).
- **Storage**: append-only record log (CRC32-checked, `fsync` per write,
torn-tail tolerant) with in-memory indexes rebuilt on open and automatic
compaction (rewrite + atomic rename when the log grows past 16 MB).
Killed mid-write (`kill -9`), the database recovers all committed writes;
the log and compaction both work with relative or absolute `--db` paths.
Records up to the announced 16 MB `maxBsonObjectSize` replay correctly.
- **Concurrency**: a writer-preferring read/write lock splits command
execution — reads (`find`, `count`, `aggregate`, `list*`) run concurrently
across connections, writes (CRUD, DDL) are exclusive and totally ordered,
and handshake/no-op commands run lock-free. The log append + `fsync` still
happen under the write lock, so the crash guarantees are unchanged. Fine
for light workloads.
## Layout
```
src/
bson.zig BSON parse/serialize, ObjectId, canonical comparison order
wire.zig OP_MSG/OP_QUERY framing, message + reply builders
commands.zig command dispatch (hello, CRUD, aggregate, admin)
server.zig TCP accept loop, per-connection handlers
db.zig in-memory engine: db → collection → _id → document maps
storage.zig append-only log: records, replay, CRC validation
query.zig filter matcher, regex engine, sort, projection
update.zig update operators with dot-path navigation
main.zig CLI: --port, --bind, --db
```
## Not (yet) implemented
- Authentication (SCRAM) — run without credentials
- Real cursors (all results are returned in one batch, cursor id 0)
- Indexes (O(n) scans)
- Transactions, change streams, replicasets
- Compression (OP_COMPRESSED)
## Code style
Zig 0.16 idioms (`std.Io` threaded through everything, unmanaged
containers); user-declared functions use `snake_case` per this repo's house
style.