@push.rocks/smartdb 5.4.0 → 5.5.0
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.
- package/dist_rust/rustdb_linux_amd64 +0 -0
- package/dist_rust/rustdb_linux_amd64.tsrust-build.json +5 -5
- package/dist_rust/rustdb_linux_arm64 +0 -0
- package/dist_rust/rustdb_linux_arm64.tsrust-build.json +5 -5
- package/dist_rust/rustdb_macos_amd64 +0 -0
- package/dist_rust/rustdb_macos_amd64.tsrust-build.json +5 -5
- package/dist_rust/rustdb_macos_arm64 +0 -0
- package/dist_rust/rustdb_macos_arm64.tsrust-build.json +5 -5
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/ts_smartdb/rust-db-bridge.d.ts +6 -0
- package/dist_ts/ts_smartdb/rust-db-bridge.js +10 -1
- package/dist_ts/ts_smartdb/server/SmartdbServer.d.ts +2 -0
- package/dist_ts/ts_smartdb/server/SmartdbServer.js +5 -1
- package/dist_ts_debugserver/bundled.js +5 -1
- package/package.json +4 -4
- package/readme.hints.md +9 -0
- package/readme.md +52 -17
- package/readme.plan.md +28 -12
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/ts_smartdb/rust-db-bridge.ts +12 -0
- package/ts/ts_smartdb/server/SmartdbServer.ts +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartdb",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.5.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A MongoDB-compatible embedded database server with wire protocol support, backed by a high-performance Rust engine.",
|
|
6
6
|
"exports": {
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
"@api.global/typedserver": "^8.4.6",
|
|
16
16
|
"@design.estate/dees-element": "^2.2.4",
|
|
17
17
|
"@git.zone/tsbuild": "^4.4.2",
|
|
18
|
-
"@git.zone/tsbundle": "^2.
|
|
19
|
-
"@git.zone/tsrust": "^1.10.
|
|
18
|
+
"@git.zone/tsbundle": "^2.13.0",
|
|
19
|
+
"@git.zone/tsrust": "^1.10.4",
|
|
20
20
|
"@git.zone/tstest": "^4.0.0",
|
|
21
|
-
"@types/node": "26.
|
|
21
|
+
"@types/node": "26.4.1",
|
|
22
22
|
"mongodb": "^7.5.0"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
package/readme.hints.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# smartdb hints
|
|
2
2
|
|
|
3
|
+
## Single-Node Concern Profile, Namespace Clock, and Deadlines (5.5.0)
|
|
4
|
+
|
|
5
|
+
- `rustdb-commands/src/concerns.rs` is the sole owner of `readConcern`, `writeConcern`, and `maxTimeMS` validation. It runs in the router before authentication, sessions, permits, or gates. The profile is stated for one voting node: fsynced acknowledgement satisfies `w: 1`, `w: "majority"`, and `j: true`; `w: N > 1` is `UnsatisfiableWriteConcern` (100), tag sets are `UnknownReplWriteConcern` (79), cluster-time read concerns and misplaced fields are `InvalidOptions` (72), malformed deadlines are `BadValue` (2). `j: true` on `MemoryStorageAdapter` is `BadValue` through `StorageAdapter::journaled_writes()`. The driver sends a transaction's read concern on whichever statement starts the transaction, so a transaction-starting insert may carry one. Never accept a concern by widening an allowlist; every accepted value must map to a guarantee the engine actually provides.
|
|
6
|
+
- `rustdb-commands/src/clock.rs` (`CommandContext::namespace_clock`) is the publication clock. Every in-process publication that changes visible namespace contents records `publish_namespace` while it still holds the namespace write lock (point writes, transaction commit completion, `create`, `drop`, `renameCollection`, `$out`, `$merge`, oplog revert) or `publish_database` (`dropDatabase`, in-process durable replacement through `invalidate_database_runtime`, and cross-process publication observed through `invalidate_database_runtime_for_epoch`). `$out` publishes right after it drops the old contents and again after the refill, so a failed refill still invalidates pinned snapshots. Index DDL does not change documents and does not publish. Adding a new mutation path without a publication is a snapshot-consistency bug.
|
|
7
|
+
- Transactions pin `TransactionState::snapshot_sequence` when they materialize their first namespace. `transactions::load_transaction_docs_locked` requires the caller to hold the namespace write lock (insert/update/delete already do); `load_transaction_docs` acquires it for readers (`find`, `count`, `distinct`). A namespace whose `last_publication` exceeds the pinned sequence fails with `SnapshotUnavailable` (246); the router labels it `TransientTransactionError` so `withTransaction` restarts. This turns lazy per-namespace materialization into one database-wide snapshot without a second data copy; Storage VNext MVCC read timestamps replace the materialized copy itself.
|
|
8
|
+
- Sessions retain `last_outcome` (`TransactionOutcome::Committed`/`Aborted` per transaction number) through `SessionEngine::finish_transaction_if_bound`. `commitTransaction`/`abortTransaction` without an active binding replay that outcome: repeated commit is `ok`, abort-after-commit is `TransactionCommitted` (256), commit-after-abort is `NoSuchTransaction` (251), and an older `txnNumber` on start is `TransactionTooOld` (225). Outcomes are process-local; after a crash the outcome of an in-flight commit is discoverable only from the data, which is why callers must journal their own attempts inside the transaction.
|
|
9
|
+
- `rustdb-commands/src/deadline.rs` holds the `maxTimeMS` deadline in a tokio task-local set by `CommandRouter::route_with_response_policy`. Checks are cooperative: admission, `deadline::wait_bounded` inside `acquire_write_lock`/`acquire_maintenance_write_gate`, `wait_until_deadline` around the maintenance read lease, `check()` after materialization in readers, `check_every` in insert/delete loops, and one final `check()` before `apply_write_batch_with_completion` in commit. Handler futures are not cancellation-safe, so never wrap a handler in `tokio::time::timeout`; add a check at the next safe point instead. `SMARTDB_TEST_OPERATION_DELAY=<command>:<ms>` (test-support builds only) injects a pre-dispatch delay for deterministic expiry tests.
|
|
10
|
+
- Error labels are derived from the response code in `attach_error_labels` so pre-dispatch rejections and handler errors label identically: transaction statements with 112/246/251 carry `TransientTransactionError`; `commitTransaction` with 50 or 64 carries `UnknownTransactionCommitResult`.
|
|
11
|
+
|
|
3
12
|
## Storage VNext A0 Committed Log
|
|
4
13
|
|
|
5
14
|
- `rustdb-kernel` is a fixture-only, non-serving A0 durability slice. It is not linked into the released `rustdb` binary and provides no BSON, CRUD, MVCC, concern, deadline, migration, replication, or availability behavior.
|
package/readme.md
CHANGED
|
@@ -354,7 +354,7 @@ Legacy v0 JSON collections are converted into hidden sibling staging directories
|
|
|
354
354
|
|
|
355
355
|
Persisted users also carry a random principal identity and a monotonic generation. SmartDB reloads and resolves that identity for every authenticated command, so password or role changes take effect immediately and stale sockets are rejected. Deleting and recreating the same username creates a different principal; an old connection cannot inherit the replacement user's authority. Cross-process user updates are serialized through the persisted users-file lock.
|
|
356
356
|
|
|
357
|
-
Single-node transactions are supported through official MongoDB driver sessions. `find`, `count`, `distinct`, `insert`, `update`, `findAndModify`, and `delete` use the transaction snapshot and buffered write set; `commitTransaction` applies that write set with conflict checks, and `abortTransaction` discards it. After applicable authentication, authorization, and allocation-policy checks, collection, database, and index DDL, user-management mutations, and aggregate pipelines ending in `$out` or `$merge` reject transaction envelopes with `OperationNotSupportedInTransaction` (code 263) before session or transaction creation, maintenance gates, or mutation. Live logical sessions remain resumable across socket disconnects. Bounded background cleanup aborts expired transactions, removes expired sessions, and releases publication leases; explicit `endSessions` and `killSessions` do the same for their active transactions.
|
|
357
|
+
Single-node transactions are supported through official MongoDB driver sessions. `find`, `count`, `distinct`, `insert`, `update`, `findAndModify`, and `delete` use the transaction snapshot and buffered write set; `commitTransaction` applies that write set with conflict checks, and `abortTransaction` discards it. The snapshot is database-wide: the first namespace a transaction materializes pins a publication sequence on the namespace clock, and any later namespace that was published after that sequence fails closed with `SnapshotUnavailable` (code 246) and the `TransientTransactionError` label so the driver restarts the transaction on fresh state; write-write conflicts surface at commit as `WriteConflict` (code 112) with the same label. Each session remembers the outcome of its last transaction number: a repeated `commitTransaction` replays `ok`, `abortTransaction` after a commit reports `TransactionCommitted` (code 256), `commitTransaction` after an abort reports `NoSuchTransaction` (code 251), and starting a transaction with an older number reports `TransactionTooOld` (code 225). After applicable authentication, authorization, and allocation-policy checks, collection, database, and index DDL, user-management mutations, and aggregate pipelines ending in `$out` or `$merge` reject transaction envelopes with `OperationNotSupportedInTransaction` (code 263) before session or transaction creation, maintenance gates, or mutation. Live logical sessions remain resumable across socket disconnects. Bounded background cleanup aborts expired transactions, removes expired sessions, and releases publication leases; explicit `endSessions` and `killSessions` do the same for their active transactions.
|
|
358
358
|
|
|
359
359
|
### Durable Database Publication Holds
|
|
360
360
|
|
|
@@ -497,6 +497,7 @@ await client.db('admin').command({ usersInfo: 'reader' });
|
|
|
497
497
|
| `port` | `number` | Actual bound port while running; otherwise the configured port (TCP mode) |
|
|
498
498
|
| `host` | `string` | Configured host (TCP mode) |
|
|
499
499
|
| `socketPath` | `string \| undefined` | Socket path (socket mode) |
|
|
500
|
+
| `processId` | `number \| undefined` | Operating-system pid of the spawned Rust engine while it runs as a child process (for crash and kill tests) |
|
|
500
501
|
| `getMetrics()` | `Promise<ISmartDbMetrics>` | Server metrics (db/collection counts, sessions, transactions, auth, uptime) |
|
|
501
502
|
| `getOpLog(params?)` | `Promise<IOpLogResult>` | Query oplog entries with optional filters |
|
|
502
503
|
| `getOpLogStats()` | `Promise<IOpLogStats>` | Aggregate oplog statistics |
|
|
@@ -999,22 +1000,56 @@ than a claim about exact allocator heap usage.
|
|
|
999
1000
|
|
|
1000
1001
|
### Read and Write Concerns and Wire Deadlines
|
|
1001
1002
|
|
|
1002
|
-
SmartDB
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1003
|
+
SmartDB serves every database from exactly one voting node and states its
|
|
1004
|
+
concern profile in those terms instead of ignoring or blanket-rejecting the
|
|
1005
|
+
fields:
|
|
1006
|
+
|
|
1007
|
+
- **Write concern.** Every acknowledged write is fsynced to the write-ahead log
|
|
1008
|
+
and the data file before the response is sent, so `w: 1`, `w: "majority"`
|
|
1009
|
+
(the majority of one voter is that voter), and `j: true` are all satisfied by
|
|
1010
|
+
the same durable commit. `w: 0` is acknowledged the same way whenever a
|
|
1011
|
+
response is expected; the exact `writeConcern: { w: 0 }` `endSessions` and
|
|
1012
|
+
`killSessions` envelopes still run without a transport response. `wtimeout`
|
|
1013
|
+
bounds a replication wait that does not exist on one node and has no
|
|
1014
|
+
additional effect. `w: N` for `N > 1` fails with `UnsatisfiableWriteConcern`
|
|
1015
|
+
(code 100), tag-set modes fail with `UnknownReplWriteConcern` (code 79), and
|
|
1016
|
+
`j: true` fails with `BadValue` (code 2) on the in-memory storage backend,
|
|
1017
|
+
which does not journal. Write concern is accepted only on commands that
|
|
1018
|
+
write (including DDL, user management, `commitTransaction`, and
|
|
1019
|
+
`abortTransaction`) and is rejected with `InvalidOptions` (code 72) inside a
|
|
1020
|
+
multi-statement transaction, where it belongs on the commit.
|
|
1021
|
+
- **Read concern.** `local`, `available`, `majority`, and `linearizable` all
|
|
1022
|
+
observe the durably committed state, because nothing is acknowledged before
|
|
1023
|
+
it is durable and reads never observe uncommitted transaction buffers.
|
|
1024
|
+
`snapshot` is accepted only on the first statement of a multi-document
|
|
1025
|
+
transaction and is served by the database-wide transaction snapshot
|
|
1026
|
+
described below. Read concern is accepted on `find`, `count`, `distinct`,
|
|
1027
|
+
and `aggregate` only, and `afterClusterTime`, `atClusterTime`, and
|
|
1028
|
+
`afterOpTime` are rejected with `InvalidOptions` because a single node issues
|
|
1029
|
+
no cluster time.
|
|
1030
|
+
- **Deadlines.** `maxTimeMS` attaches a cooperative deadline to the command.
|
|
1031
|
+
It is checked at admission, during namespace-lock and maintenance-gate
|
|
1032
|
+
waits, before `find`, `count`, and `distinct` materialize documents, between
|
|
1033
|
+
documents in `insert` and `delete` batches, and immediately before a
|
|
1034
|
+
transaction commit is handed to storage; expiry fails with `MaxTimeMSExpired`
|
|
1035
|
+
(code 50). Database-permit waits keep their fixed internal timeout, and a
|
|
1036
|
+
single storage step or an in-progress `update` batch runs to completion
|
|
1037
|
+
before the next check, so a write that expires after its first documents
|
|
1038
|
+
were published reports the expiry while those documents remain durable,
|
|
1039
|
+
exactly like an interrupted MongoDB batch. The official driver transmits a
|
|
1040
|
+
transaction's `maxCommitTimeMS` as `maxTimeMS` on `commitTransaction`; a
|
|
1041
|
+
commit that expires before its batch is handed to storage publishes nothing,
|
|
1042
|
+
records the transaction as aborted, and carries the
|
|
1043
|
+
`UnknownTransactionCommitResult` label; the driver's commit retry then sees
|
|
1044
|
+
`NoSuchTransaction` with `TransientTransactionError` and restarts the whole
|
|
1045
|
+
transaction. `getMore` rejects `maxTimeMS` with `BadValue` because SmartDB
|
|
1046
|
+
has no awaitData cursors, and a literal `maxCommitTimeMS` field is rejected
|
|
1047
|
+
with `InvalidOptions`.
|
|
1048
|
+
|
|
1049
|
+
Callers may therefore rely on a successful SmartDB response as a durable,
|
|
1050
|
+
single-node acknowledgement. They must not read it as a replica-backed
|
|
1051
|
+
acknowledgement: majority semantics across several voters arrive with
|
|
1052
|
+
replication.
|
|
1018
1053
|
|
|
1019
1054
|
### Unsupported Administrative Commands
|
|
1020
1055
|
|
package/readme.plan.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Status: canonical direction, approved 2026-08-17. Reread before starting engine or
|
|
4
4
|
managed-service work.
|
|
5
5
|
|
|
6
|
-
Baseline: `@push.rocks/smartdb` 5.
|
|
6
|
+
Baseline: `@push.rocks/smartdb` 5.5.0. SmartDB is a Rust database engine with a
|
|
7
7
|
TypeScript lifecycle facade, a MongoDB wire-protocol command surface, file and
|
|
8
8
|
memory storage, authentication, transactions, resource fencing, and official
|
|
9
9
|
MongoDB Node.js driver integration.
|
|
@@ -18,12 +18,22 @@ Current execution status:
|
|
|
18
18
|
- strict latest-per-key runtime WAL recovery and post-publication point-write
|
|
19
19
|
fencing were released in 5.3.2; crash-safe ordinary DDL, debug-server security,
|
|
20
20
|
and general crash/soak qualification remain separate required 5.x slices
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
change-proportional appends, strict pair recovery, and ambiguity fencing
|
|
21
|
+
- 5.4.0 released the non-serving, fixture-only A0 committed-log kernel with one
|
|
22
|
+
static timeline, contiguous LSNs, exact retry receipts, bounded
|
|
23
|
+
change-proportional appends, strict pair recovery, and ambiguity fencing; the
|
|
24
|
+
follow-up A1/MVCC/rollover/checkpoint work is parked unreleased on the
|
|
25
|
+
`storage-vnext-a1-wip` branch
|
|
24
26
|
- A0 has no BSON document substrate, MVCC, checkpoint, segment rollover, OpenRaft
|
|
25
|
-
integration, wire serving,
|
|
26
|
-
|
|
27
|
+
integration, wire serving, migration, or availability claim; Phase 3B and the
|
|
28
|
+
earlier Phase 0/1 gates have not passed
|
|
29
|
+
- 5.5.0 serves the truthful single-node concern profile on the legacy engine:
|
|
30
|
+
fsync-backed `w: 1`/`majority`/`j` acknowledgement, committed-state reads for
|
|
31
|
+
`local`/`available`/`majority`/`linearizable`, database-wide transaction
|
|
32
|
+
snapshots pinned by the namespace publication clock with fail-closed
|
|
33
|
+
`SnapshotUnavailable` retries, cooperative `maxTimeMS` deadlines, and
|
|
34
|
+
per-session idempotent commit/abort outcomes; unsatisfiable `w: N > 1`, tag
|
|
35
|
+
sets, cluster-time read concerns, and journaled writes on the memory backend
|
|
36
|
+
remain rejected
|
|
27
37
|
|
|
28
38
|
## Product objective
|
|
29
39
|
|
|
@@ -136,7 +146,10 @@ and reproducible baseline measurements.
|
|
|
136
146
|
## Phase 1: truthful single-node behavior
|
|
137
147
|
|
|
138
148
|
- stop over-advertising MongoDB version, wire behavior, and batch limits
|
|
139
|
-
-
|
|
149
|
+
- serve the single-node concern profile truthfully and reject every concern,
|
|
150
|
+
option, command, or administrative stub whose guarantee one node cannot
|
|
151
|
+
provide (completed 2026-09-02: concerns, deadlines, database-wide transaction
|
|
152
|
+
snapshots, idempotent transaction outcomes)
|
|
140
153
|
- completed slice (2026-08-25): validate OP_MSG required flags, CRC-32C
|
|
141
154
|
checksums, bounded framing, and exact no-response admission and execution
|
|
142
155
|
- preserve complete BSON type and value identity for document and index keys
|
|
@@ -219,10 +232,12 @@ Gates:
|
|
|
219
232
|
- add configurable service classes and fair scheduling
|
|
220
233
|
- add only features selected by the certified compatibility profile
|
|
221
234
|
|
|
222
|
-
Semantic work may proceed after Phase 2.
|
|
223
|
-
and durable index publication
|
|
224
|
-
|
|
225
|
-
|
|
235
|
+
Semantic work may proceed after Phase 2. Crash-durable retryable outcomes,
|
|
236
|
+
transaction publication, and durable index publication move onto Storage VNext.
|
|
237
|
+
The single-node concern profile is served today: every acknowledged write is
|
|
238
|
+
durable before the response, reads observe committed state, and transactions
|
|
239
|
+
observe one database-wide snapshot. Multi-voter majority acknowledgement and
|
|
240
|
+
cluster-time read concerns remain rejected until replication implements them.
|
|
226
241
|
|
|
227
242
|
Gate: bounded-memory scans at maximum declared scale, published p99 latency and
|
|
228
243
|
capacity curves, proven tenant isolation, and zero certified-profile mismatches.
|
|
@@ -256,7 +271,8 @@ logged state.
|
|
|
256
271
|
- replicate the Storage VNext log across three replicas in separate failure domains
|
|
257
272
|
- add terms, quorum commit, snapshot installation, log catch-up, and membership
|
|
258
273
|
changes
|
|
259
|
-
-
|
|
274
|
+
- extend the single-node concern profile to multi-voter majority acknowledgement
|
|
275
|
+
and cluster-time read concerns
|
|
260
276
|
- publish accurate `hello` topology and election metadata
|
|
261
277
|
- add causal times, retryable outcomes, idempotent transaction commits, and
|
|
262
278
|
failover-safe session behavior
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -389,6 +389,18 @@ export function getRustDbAllocatorEnv(
|
|
|
389
389
|
*/
|
|
390
390
|
export class RustDbBridge extends EventEmitter {
|
|
391
391
|
private bridge: plugins.smartrust.RustBridge<TSmartDbCommands>;
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Operating-system process id of the spawned Rust engine while it runs as a
|
|
395
|
+
* child process of this Node.js process. Undefined before spawn, after
|
|
396
|
+
* termination, or when the bridge is connected to an external process.
|
|
397
|
+
*/
|
|
398
|
+
public get processId(): number | undefined {
|
|
399
|
+
const transport = (this.bridge as unknown as {
|
|
400
|
+
transport?: { childProcess?: { pid?: number } | null };
|
|
401
|
+
}).transport;
|
|
402
|
+
return transport?.childProcess?.pid;
|
|
403
|
+
}
|
|
392
404
|
private terminationConfirmed = true;
|
|
393
405
|
private terminationPromise: Promise<void> | undefined;
|
|
394
406
|
private terminationFailure: unknown;
|
|
@@ -387,6 +387,11 @@ export class SmartdbServer {
|
|
|
387
387
|
/**
|
|
388
388
|
* Check if the server is running
|
|
389
389
|
*/
|
|
390
|
+
/** Process id of the spawned Rust engine, when it runs as a child process. */
|
|
391
|
+
get processId(): number | undefined {
|
|
392
|
+
return this.bridge.processId;
|
|
393
|
+
}
|
|
394
|
+
|
|
390
395
|
get running(): boolean {
|
|
391
396
|
return this.isRunning;
|
|
392
397
|
}
|