NEDB v2.1.0 — Sprint Release
"Batch writes tripled. TRACE and AS OF fixed. Live query subscriptions. 28/28 tests green."
Install
pip install --upgrade nedb-engine # 2.1.0
npm install nedb-engine # 2.1.0
pip install --upgrade nedb-engine-client # 1.1.0
npm install nedb-engine-client # 1.1.0Start the v2 DAG engine:
NEDBD_DAG=1 NEDB_TMK=<32-byte-hex> nedbd --data ./data
curl http://127.0.0.1:7070/health
# {"ok":true,"version":"2.1.0","engine":"dag","service":"nedbd","encrypted":true}What's new
🔥 Batch writes +185% — 1,106/s → 3,153/s
POST /v1/databases/:name/batch now processes all put ops in parallel via Rayon. Object writes and id-index updates run concurrently across all cores. Sequential ordering preserved via pre-allocated seq numbers.
Batch writes (500/req): 1,106/s @ 1.25ms → 3,153/s @ 0.42ms
📈 Point reads +33% — 392/s → 523/s
Fixed a silent bug: node.hash was serialized as empty (skipped by skip_serializing_if) so every read-back returned a node with hash = "". This broke TRACE, AS OF, and caused unnecessary read failures. Now restored from the lookup path on every objects.read().
🔧 TRACE and AS OF were broken — now fixed
TRACE caused_by and AS OF seq both rely on following hash chains through the graph and object store. With node.hash = "" they silently returned empty results. Both are now fully functional:
# Causal trace — follow the chain backward
curl -X POST .../query -d '{"nql":"FROM ops WHERE _id = \"c\" TRACE caused_by LIMIT 10"}'
# Time-travel — state at a specific sequence number
curl -X POST .../query -d '{"nql":"FROM docs AS OF 42"}'📡 Live query subscriptions — POST /subscribe
Subscribe to any NQL query and receive real-time diffs as SSE:
curl -N -X POST http://127.0.0.1:7070/v1/databases/vision/subscribe \
-H 'content-type: application/json' \
-d '{"nql":"FROM blocks ORDER BY height DESC LIMIT 5"}'
# Initial result sent immediately
# data: {"sub_id":1,"rows":[...],"event":"initial"}
# After every PUT/batch that changes the result:
# data: {"sub_id":1,"rows":[...],"count":5}Unsubscribe: DELETE /v1/databases/:name/subscribe/:sub_id
⏰ Hourly checkpoint + graceful shutdown
- Hourly: MANIFEST flushed at top of every clock hour (system-clock aligned)
- SIGTERM (
systemctl stop, Docker): caught, flushes all MANIFESTs, clean exit - SIGINT (Ctrl+C): same
- Background ticker: MANIFEST dirty-flag flushed every 1s — removed per-write I/O from the hot path
🔬 DAG test suite — 28/28
python3 tests/test_dag.py — auto-spawns nedbd if nothing on port 7070, cleans up after. Covers:
- CRUD, tombstone deletes, query (NQL WHERE/ORDER BY/GROUP BY/SEARCH)
- Batch (parallel puts, mixed put/del, monotonic seq)
- Integrity (BLAKE2b head, verify, tamper evidence)
- Timeline (VALID AS OF, AS OF seq time-travel)
- Causal (TRACE caused_by)
- SSE (/events endpoint)
🖥️ Studio DAG engine badge
NEDB Studio now shows a DAG ◆ badge (green) in the nav bar when connected to the v2 Rust engine, AOF (amber) when on v1. Read-only — Studio observes the engine, never controls it. Tooltip: "start nedbd with --dag to use v2 DAG engine".
📊 engine: "dag" in /health
The health endpoint now reports the engine type:
{
"ok": true,
"service": "nedbd",
"version": "2.1.0",
"engine": "dag",
"databases": ["vision"],
"encrypted": true
}Benchmark (Intel iMac, 10k writes / 100k reads)
| Operation | v2.0.36 | v2.1.0 | Change |
|---|---|---|---|
| Sequential writes | 352/s @ 6.4ms | 399/s @ 5.6ms | +13% |
| Batch writes (500/req) | 1,106/s @ 1.25ms | 3,153/s @ 0.42ms | +185% 🔥 |
| Point-lookup reads | 392/s @ 5.9ms | 523/s @ 4.7ms | +33% |
| ORDER BY queries | 457/s @ 3.8ms | 572/s @ 2.4ms | +25% |
| Verify 30k objects | — | 1.15s (~26k/s) | ✅ |
| Concurrent writes (16) | 248/s @ 230ms | 245/s @ 215ms | ≈ flat |
Concurrent single-PUT bottleneck remains — targeted in v2.2.
Full changelog
perf(db): parallel batch writes viaput_batch()— Rayon object + index writesperf(db): decoupleflush_manifestfrom write path — background ticker every 1sfeat(server): hourly clock-aligned checkpoint + SIGTERM/SIGINT graceful shutdownfeat(server): live query subscriptions —POST /v1/databases/:name/subscribefeat(server):engine: "dag"field in/healthresponsefix(store): restorenode.hashafter deserialization — fixes TRACE and AS OFfix(store): guard empty hash inObjectStore::read()— no more panic on empty stringtest: DAG correctness suite — 28 tests, auto-spawn,tests/test_dag.pyfeat(studio): engine status badge (DAG ◆ / AOF) in Studio Nav bar
Links
- Source: github.com/aiassistsecure/nedb
- PyPI: pypi.org/project/nedb-engine
- npm: npmjs.com/package/nedb-engine
- Client PyPI: pypi.org/project/nedb-engine-client
- Studio: studio.interchained.org
© INTERCHAINED, LLC × Vex (Claude Sonnet 4.6)