nedb-engine 2.6.2__tar.gz → 2.6.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/PKG-INFO +1 -1
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/pyproject.toml +1 -1
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/__init__.py +1 -1
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/_native.abi3.so +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/concurrent.py +7 -0
- nedb_engine-2.6.3/python/nedb/nedbd-v2 +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/nedbd-v2-darwin-arm64 +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/nedbd-v2-darwin-x64 +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/nedbd-v2.exe +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/server.py +29 -2
- nedb_engine-2.6.2/python/nedb/nedbd-v2 +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/.gitignore +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/LICENSE +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/README.md +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/client/node/README.md +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/client/python/README.md +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/examples/mini-chain/README.md +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/autoindex.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/backends/__init__.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/backends/redis_backend.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/cascade.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/crypto.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/engine.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/index.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/log.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/merkle.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/mongo.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/proof.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/query.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/redis_compat.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/relations.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/resp2.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/snapshot.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/sql.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/store.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/python/nedb/wrap_redis.py +0 -0
- {nedb_engine-2.6.2 → nedb_engine-2.6.3}/rust/nedb-v2/README.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nedb-engine
|
|
3
|
-
Version: 2.6.
|
|
3
|
+
Version: 2.6.3
|
|
4
4
|
Summary: NEDB — a versioned, self-compressing, time-traveling embedded database (replay-protected, idempotent, relational, searchable) with durable AOF persistence and a server daemon (nedbd).
|
|
5
5
|
Project-URL: Homepage, https://github.com/aiassistsecure/nedb
|
|
6
6
|
Project-URL: Repository, https://github.com/aiassistsecure/nedb
|
|
@@ -10,7 +10,7 @@ build-backend = "hatchling.build"
|
|
|
10
10
|
|
|
11
11
|
[project]
|
|
12
12
|
name = "nedb-engine"
|
|
13
|
-
version = "2.6.
|
|
13
|
+
version = "2.6.3"
|
|
14
14
|
description = "NEDB — a versioned, self-compressing, time-traveling embedded database (replay-protected, idempotent, relational, searchable) with durable AOF persistence and a server daemon (nedbd)."
|
|
15
15
|
readme = "README.md"
|
|
16
16
|
requires-python = ">=3.8"
|
|
Binary file
|
|
@@ -115,6 +115,11 @@ class Sequencer:
|
|
|
115
115
|
def checkpoint(self) -> Any:
|
|
116
116
|
return self._submit("checkpoint")
|
|
117
117
|
|
|
118
|
+
def sweep(self) -> Any:
|
|
119
|
+
"""TTL sweep as ONE committer intent — sweep appends delete ops, so it
|
|
120
|
+
must ride the single writer, never race it from another thread."""
|
|
121
|
+
return self._submit("sweep")
|
|
122
|
+
|
|
118
123
|
# ── read API: concurrent, snapshot-isolated at committed_seq ───────────────
|
|
119
124
|
def query(self, nql: str) -> List[dict]:
|
|
120
125
|
plan = parse_nql(nql)
|
|
@@ -216,6 +221,8 @@ class Sequencer:
|
|
|
216
221
|
return db.checkpoint()
|
|
217
222
|
if k == "tx":
|
|
218
223
|
return db.tx(*intent.args, **intent.kwargs)
|
|
224
|
+
if k == "sweep":
|
|
225
|
+
return db.sweep()
|
|
219
226
|
raise ValueError(f"unknown write kind: {k}")
|
|
220
227
|
|
|
221
228
|
def close(self) -> None:
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -12,6 +12,7 @@ Config (env):
|
|
|
12
12
|
NEDBD_PORT bind port (default 7070)
|
|
13
13
|
NEDBD_DATA data root directory (default ./nedb-data)
|
|
14
14
|
NEDBD_TOKEN bearer token (optional; if set, every /v1 route requires it)
|
|
15
|
+
NEDBD_SWEEP_S TTL sweep interval s (default 30; 0 disables the sweeper)
|
|
15
16
|
|
|
16
17
|
Run:
|
|
17
18
|
nedbd # console script (pip install nedb-engine)
|
|
@@ -24,7 +25,7 @@ HTTP API (all JSON):
|
|
|
24
25
|
GET /v1/databases/<name>
|
|
25
26
|
DELETE /v1/databases/<name>
|
|
26
27
|
POST /v1/databases/<name>/query {nql}
|
|
27
|
-
POST /v1/databases/<name>/put {coll, id, doc, client?, nonce?, idem?}
|
|
28
|
+
POST /v1/databases/<name>/put {coll, id, doc, client?, nonce?, idem?, ttl_s?}
|
|
28
29
|
POST /v1/databases/<name>/index {coll, field, kind}
|
|
29
30
|
POST /v1/databases/<name>/link {frm, rel, to}
|
|
30
31
|
DELETE /v1/databases/<name>/rows/<coll>/<id>
|
|
@@ -35,6 +36,8 @@ HTTP API (all JSON):
|
|
|
35
36
|
GET /v1/databases/<name>/files/<filename>/root?version=N&tier=warm — Merkle root (anchorable)
|
|
36
37
|
POST /v1/databases/<name>/proof {hash} — Merkle inclusion proof (verifiable offline)
|
|
37
38
|
POST /v1/databases/<name>/checkpoint — on-demand checkpoint
|
|
39
|
+
POST /v1/databases/<name>/sweep — delete TTL-expired docs now (also runs
|
|
40
|
+
automatically every NEDBD_SWEEP_S, default 30)
|
|
38
41
|
POST /v1/databases/<name>/batch — ATOMIC multi-op tx: {ops: [{op, coll, id,
|
|
39
42
|
doc?, if_seq?, idem?, client?}], client?}
|
|
40
43
|
all-or-nothing; if_seq CAS preconditions
|
|
@@ -327,7 +330,7 @@ def make_handler(manager: Manager, token: Optional[str]):
|
|
|
327
330
|
if not coll or rid is None or not isinstance(doc, dict):
|
|
328
331
|
raise HttpError(400, "coll, id, and doc are required")
|
|
329
332
|
_scalar = ("client", "nonce", "idem", "evidence", "confidence",
|
|
330
|
-
"valid_from", "valid_to")
|
|
333
|
+
"valid_from", "valid_to", "ttl_s")
|
|
331
334
|
kw = {k: b[k] for k in _scalar if b.get(k) is not None}
|
|
332
335
|
# caused_by may live at the top level of the request body
|
|
333
336
|
# OR inside doc (natural for clients embedding it in the document).
|
|
@@ -369,6 +372,10 @@ def make_handler(manager: Manager, token: Optional[str]):
|
|
|
369
372
|
head = db.checkpoint()
|
|
370
373
|
self._send(200, {"ok": True, "head": head, "seq": db.seq})
|
|
371
374
|
return
|
|
375
|
+
if method == "POST" and action == "sweep":
|
|
376
|
+
swept = db.sweep()
|
|
377
|
+
self._send(200, {"ok": True, "swept": swept, "seq": db.seq})
|
|
378
|
+
return
|
|
372
379
|
if method == "GET" and action == "log":
|
|
373
380
|
limit = int(query.get("limit", ["50"])[0])
|
|
374
381
|
ops = [o.to_dict() for o in db.log.ops[-limit:]][::-1]
|
|
@@ -913,6 +920,26 @@ def main() -> None:
|
|
|
913
920
|
token = args.token
|
|
914
921
|
resp2_port = args.resp2_port
|
|
915
922
|
manager = Manager(data)
|
|
923
|
+
|
|
924
|
+
# TTL sweeper: engine expiry is lazy (as_of=None gets) but daemon reads are
|
|
925
|
+
# snapshot-pinned, so expired docs would linger forever without an active
|
|
926
|
+
# sweep. Runs every NEDBD_SWEEP_S seconds (default 30; 0 disables) through
|
|
927
|
+
# each Sequencer's committer intent — single-writer discipline preserved.
|
|
928
|
+
sweep_s = float(os.environ.get("NEDBD_SWEEP_S", "30"))
|
|
929
|
+
if sweep_s > 0:
|
|
930
|
+
def _sweeper():
|
|
931
|
+
import time as _t
|
|
932
|
+
while True:
|
|
933
|
+
_t.sleep(sweep_s)
|
|
934
|
+
for _name in list(manager._open.keys()):
|
|
935
|
+
try:
|
|
936
|
+
n = manager._open[_name].sweep()
|
|
937
|
+
if n:
|
|
938
|
+
_log(f" [nedbd] ttl sweep [{_name}]: {n} expired", level=1)
|
|
939
|
+
except Exception as _e: # noqa: BLE001
|
|
940
|
+
_log(f" [nedbd] ttl sweep [{_name}] error: {_e}", level=1)
|
|
941
|
+
threading.Thread(target=_sweeper, name="nedbd-ttl-sweeper", daemon=True).start()
|
|
942
|
+
|
|
916
943
|
httpd = ThreadingHTTPServer((host, port), make_handler(manager, token))
|
|
917
944
|
auth = "on" if token else "off"
|
|
918
945
|
BANNER = f"""\
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|