You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
PYTHON-6207 [Spike] back bson encode and decode with Rust and run the full BSON performance suite - #3170
Adds a Rust implementation of the BSON codec as a drop-in replacement for the C extension. On the perf host it is faster than C on all six benchmarks, from 1.02x on FullDecoding to 1.71x on encoding.
Motivation
The C extensions hold the repo's highest memory-safety and reviewability risk. This ticket is the first step of the rust-shared-core program (PYTHON-6162): prove the codec can move to Rust with byte-exact parity and no performance regression before any larger migration.
Changes
Added a Rust implementation of the BSON codec under rust/bson, differential-tested against the C extension.
Added a benchmark selector that switches the performance suite between the C and Rust codecs.
Added an Evergreen task that builds both codecs on the perf host and publishes the comparison.
Testing
Differential suite against the C extension: 124 passed.
BSON micro-benchmarks: 6 passed per codec.
Full comparison protocol run on the perf host: task results.
Throughput, megabytes per second, perf host (October 31 run):
Benchmark
C MB/s
Rust MB/s
Rust/C
FlatEncoding
508.3
870.7
1.71x
DeepEncoding
229.6
391.8
1.71x
FullEncoding
287.8
331.6
1.15x
DeepDecoding
188.7
267.0
1.42x
FlatDecoding
455.7
515.5
1.13x
FullDecoding
143.3
145.6
1.02x
Rust is at parity or better on every benchmark. The run also captured DeepDecoding profiles for both codecs as task artifacts.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Unresolved critical defects risk undefined behavior when decoding writable buffers and BSON length overflow from unchecked cumulative growth, alongside codec compatibility and CI regressions.
Adds an experimental Rust-backed BSON codec alongside PyMongo’s C extension, with differential tests and benchmark tooling to evaluate compatibility and throughput before broader migration.
Changes:
Implements six BSON codec entry points using PyO3, including codec options and BSON-specific types.
Adds differential tests, benchmark fixtures, and a BSON_IMPL selector.
Adds Evergreen comparison runs, optional decoding profiles, and artifact publishing.
blink1073
changed the title
PYTHON-6207 back bson encode and decode with Rust and run the full BSON performance suite
PYTHON-6207 [Spike] back bson encode and decode with Rust and run the full BSON performance suite
Nov 2, 2026
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Raw-buffer initialization can execute Python that mutates memory borrowed as an immutable Rust slice, leaving a critical safety issue alongside unresolved codec-parity defects.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Malformed UTF-8 field names can trigger a custom error handler that re-enters decoding while the key-cache mutex is held, deadlocking the process.
No open issues 🎉
7 previously missed issues
In code that hasn't changed since last review
Bypass UTF-8 cache for invalid input
rust/bson/src/decode.rs:1028
The strict error handler can be replaced with codecs.register_error("strict", handler), and PyUnicode_DecodeUTF8 invokes that Python handler even when its errors argument is NULL. For a malformed short field name, a handler that calls BSON decoding again therefore re-enters decode_key_cached while its non-reentrant mutex is held, deadlocking the process. Bypass the cache for invalid UTF-8 before taking the lock; this also prevents caching handler-dependent replacements as though they were strict decoding results.
Mark Evergreen task as patch-only
.evergreen/scripts/generate_config.py:1211
Omitting batchtime does not make an Evergreen variant patch-only, and this task has no patch_only setting. The Rust build and four benchmark passes can therefore run on normal commits despite the stated patch-only intent. Set patch_only=True on this task and regenerate the Evergreen configuration.
Restrict DBRef shortcut to exact dicts
rust/bson/src/decode.rs:312
The no-dollar-key shortcut is only valid for an exact dict. A supported custom document_class can add DBRef keys in its constructor or rewrite ref/id to $ref/$id in __setitem__. The C codec checks the resulting mapping and returns a DBRef, but this gate skips the hook and returns the custom mapping instead. Please restrict this shortcut to the exact-dict case and add a differential regression test for a mapping that rewrites keys.
Propagate top-level TypeDecoder exceptions
rust/bson/src/decode.rs:620
A registered TypeDecoder that raises ValueError for a top-level scalar produces InvalidBSON with Rust, while C preserves ValueError, breaking callers that handle their decoder's exceptions. Match C's exception boundary: wrap parsing and construction failures before invoking the converter, and propagate its failure without another wrapper at that level.
Preserve mapping lookups for dict subclasses
rust/bson/src/decode.rs:654
cast::<PyDict>() also accepts dict subclasses, so this fast path bypasses their __getitem__ overrides. The C DBRef hook uses mapping lookups even for those subclasses. For example, a custom document_class that normalizes the $ref value on lookup produces a different DBRef.collection with Rust because this code reads the unnormalized stored value. Please use the raw-storage fast path only for an exact dict and preserve mapping lookups for subclasses.
Propagate exceptions outside the Exception hierarchy
rust/bson/src/decode.rs:1038
This wraps every PyErr, including KeyboardInterrupt and SystemExit, as InvalidBSON. For example, a registered TypeDecoder raising KeyboardInterrupt is turned into a data error instead of interrupting the operation. The C reference explicitly wraps only subclasses of Exception; preserve exceptions outside that hierarchy before performing the conversion.
Accept signed-byte buffers in BSON decoding
rust/bson/src/lib.rs:97
PyBuffer::<u8>::get rejects signed-byte buffers such as memoryview(encoded).cast("b") and array.array("b", encoded), although the C codec accepts them, so valid BSON fails to decode. Use a shared format-independent buffer acquisition helper that preserves contiguity, item-size, ownership, release and snapshot checks. The same issue affects raw-document decoding at rust/bson/src/lib.rs:72 and raw-document encoding at rust/bson/src/encode.rs:711.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
The raw-byte shortcut misses decoded $ref and $id keys produced by a registered strict handler, causing Rust to return a dict where the C decoder returns a DBRef.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
The callback-induced panic risk, benchmark-selection inconsistency, incomplete Rust clamping coverage, and large-document copying overhead require human assessment of their combined impact.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Rust-selected benchmarks can silently measure the C codec, while allocation failures during decoding can abort Python and dictionary mutation during encoding can trigger Rust panics.
# Importing triggers codec selection (side effect; see bson_impl_select.py).
from test.performance import bson_impl_select
This branch has not been deployed
No deployments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PYTHON-6207
Summary
Adds a Rust implementation of the BSON codec as a drop-in replacement for the C extension. On the perf host it is faster than C on all six benchmarks, from 1.02x on FullDecoding to 1.71x on encoding.
Motivation
The C extensions hold the repo's highest memory-safety and reviewability risk. This ticket is the first step of the rust-shared-core program (PYTHON-6162): prove the codec can move to Rust with byte-exact parity and no performance regression before any larger migration.
Changes
rust/bson, differential-tested against the C extension.Testing
Throughput, megabytes per second, perf host (October 31 run):
Rust is at parity or better on every benchmark. The run also captured DeepDecoding profiles for both codecs as task artifacts.