The two servers¶
SecantusDB ships two separate servers that speak the same MongoDB wire protocol. You run one or the other — there is no in-process engine switching, and a client never sees a mix of the two.
The Python server — the original pure-Python
SecantusDBServer(this PyPI package). It is the conformance leader and the default choice.The Rust server — a self-contained Rust server (its own wire / dispatch / cursors / accept loop over the pure-Rust engines and a WiredTiger-backed store) that runs its accept loop off the GIL. Its Python ergonomic is a thin embedded lifecycle handle (
start/stop/address); Python is only the launcher, never in the request path.
Both store data on the same vendored WiredTiger engine mongod ships, so
the on-disk durability story is identical. The difference is the layers above
storage — command dispatch, query planning, the operator engines — which are
Python in one server and Rust in the other.
Note
The old in-process accelerator (SECANTUS_ENGINE=rust /
SecantusDBServer(engine=...)) has been retired in favour of this
two-server split. The Python server is always pure-Python; the Rust engines
live only in the Rust server.
Which one should I use?¶
Python server |
Rust server |
|
|---|---|---|
Package |
|
built behind a flag / |
Maturity |
conformance reference — 99.5% of pymongo’s own suite |
99.5% of the same suite |
Best for |
the default: tests, dev, embedded apps, single-node prototypes |
throughput-sensitive workloads where the Rust hot path matters |
Request path |
pure Python |
pure Rust (off the GIL) |
Use the Python server unless you have a specific reason not to. It is the conformance reference, supports the full in-scope feature set described in Compatibility, and is the only server with the SQL / PostgreSQL frontend. The Rust server now matches it on pymongo’s suite and is faster per operation (see Benchmark); its few remaining feature gaps are listed below and in the Feature comparison.
Versioning¶
The two servers are separate deliverables on independent version lines;
they diverged at 0.5.2 and advance independently:
Python server —
0.5.3bN(PEP 440). This is the PyPI package version inpyproject.toml/secantus.__version__.Rust server —
0.5.3-beta.N(SemVer pre-release), carried in lockstep across thecrates/*workspace and surfaced over the wire asbuildInfo.secantusVersion, by thesecantusd-rs --versionflag, and by the embedded handle’sRustServer.version.
A change that touches only one server bumps only that server’s version.
Running each server¶
Python server¶
from pymongo import MongoClient
from secantus import SecantusDBServer
with SecantusDBServer(port=27017) as server:
client = MongoClient(server.uri)
client["mydb"]["users"].insert_one({"_id": 1, "name": "Joe"})
Or as a daemon — pip install puts a secantusd-py script on PATH:
secantusd-py --host 127.0.0.1 --port 27017
See Quickstart and Installation.
Rust server¶
The Rust server is not in the default wheel. Build it with the storage-engine flag on:
SKBUILD_CMAKE_DEFINE=SECANTUS_BUILD_STORAGE_ENGINE=ON uv sync --extra dev
A flag-on build exposes the embedded handle and a secantusd-rs daemon on
PATH (distinct from the pure-Python secantusd-py console script):
import _secantus_server
from pymongo import MongoClient
srv = _secantus_server.RustServer("./secantus-data", 0) # storage_path, port (0 = OS-assigned)
host, port = srv.address
client = MongoClient(host, port, directConnection=True)
# ... use it ...
srv.stop()
secantusd-rs --host 127.0.0.1 --port 27017
Both Mongo daemons read the same secantusd.toml config (see
Configuration).
SQL / PostgreSQL server¶
The optional PostgreSQL-wire server (pip install "secantus[sql]") runs as
secantusd-py-pg:
secantusd-py-pg --host 127.0.0.1 --port 5432 --storage-path ./secantus-data
See the SQL / PostgreSQL interface.
What each server does not support¶
Both servers share the project-wide non-goals — anything that depends on real
cluster topology (multi-node replica sets, sharding, elections, cross-node
oplog), auth mechanisms beyond SCRAM (SHA-1 / SHA-256) and MONGODB-X509,
OP_COMPRESSED, text / hashed / wildcard indexes, and
$where / $function / $accumulator / JS mapReduce (no embedded JS
runtime).
These are out of scope for both servers; the per-feature detail lives in
Compatibility.
Python server¶
The Python server implements the full in-scope wire surface. Its remaining
divergences are the stopgaps and known edge cases enumerated in
Compatibility — the _id numeric-type bridge is
undefined for NaN / infinity, top counters are always zero, and a handful
of date-format and
$group-ordering edge cases. There is no feature the Python server is
missing relative to the in-scope set; it is the conformance reference the Rust
server is measured against.
Rust server¶
The Rust server now passes the same 99.5% of pymongo’s suite as the Python server. The remaining feature differences (full three-way matrix in the Feature comparison) are:
SQL / PostgreSQL frontend — the PG wire listener (
secantusd-py-pg) is Python-server-only.mapReduceandtop— the Python server ships a minimalmapReduce({out: {inline: 1}}only) and a zero-countertop; the Rust server answersCommandNotFoundfor both.Point-in-time restore over the wire —
secantusAdmin.restoreToTimestampis Python-server-only; the Rust server does the same restore via thesecantusd-rs restoreCLI subcommand.Session lifecycle —
endSessions/refreshSessions/killSessionsare acknowledged no-ops on the Rust server; the Python server tracks sessions with a 30-minute idle TTL.Operator edges — a handful of
$dateFromString/$dateToStringformat directives, Decimal128 arithmetic edges, and mixed-type sort orderings the Rust engine rejects rather than risk diverging from the Python oracle.Thinner diagnostics —
serverStatus/dbStats/collStatsreturn a smaller subset of fields than the Python server’s replies.
Both servers mint resume tokens in SecantusDB’s own {s, t, n, k} layout
rather than mongod’s keystring format — tokens round-trip within SecantusDB but
cannot be presented to a real mongod (or vice versa).
The current Rust-server pass rate, and the exact set of failing pymongo tests, is regenerated each run into the Rust-server validation report. The gap against the Python-server report is the canonical, machine-checked statement of what the Rust server doesn’t support yet.