v2.0.0
Description
The MongoDB Rust driver team is pleased to announce the v2.0.0
release of the mongodb
crate. This release is the culmination of several months of work, and it contains a number of new features, API improvements, and bug fixes. It is intended that this release will be very stable and that mongodb
will not have another major release for quite a long time.
Note that the new minimum supported Rust version (MSRV) is now 1.48.0.
Highlighted changes
The following sections detail some of the more important breaking changes included in this release. For a full list of changes, see the Full Release Notes section below.
Update dependency on tokio
to v1.x
(RUST-633)
The async runtime crate tokio
reached 1.0, and the driver's dependency on it was updated to 1.0 accordingly. This is a breaking change, since the driver will no longer work with earlier versions of tokio
.
Update dependency on bson
to v2.0.0
(RUST-1006)
The exported version of bson
was updated to v2.0.0
, which includes its own set of breaking changes. Check out the bson
release notes for more information.
Transactions support (RUST-90)
This release adds driver support for transactions, which are supported on replica sets in MongoDB 4.0+ and on sharded clusters in MongoDB 4.2+. Transactions require the use of a ClientSession
. Each operation in the transaction must pass the ClientSession
into it via the _with_session
suffixed version of the operation. For more information and detailed examples, see the ClientSession
documentation.
use mongodb::options::{Acknowledgment, ReadConcern, TransactionOptions};
use mongodb::{
bson::{doc, Document},
options::WriteConcern,
};
let mut session = client.start_session(None).await?;
let txn_options = TransactionOptions::builder()
.write_concern(WriteConcern::builder().w(Acknowledgment::Majority).build())
.read_concern(ReadConcern::majority())
.build();
session.start_transaction(txn_options).await?;
collection
.insert_one_with_session(doc! { "x": 1 }, None, &mut session)
.await?;
collection
.delete_one_with_session(doc! { "x": 2 }, None, &mut session)
.await?;
session.commit_transaction().await?;
The "snapshot" read concern level was also introduced as part of this feature.
Remove Document
as the default generic type for Collection
and Cursor
(RUST-735)
The generic parameter must now always be explicitly specified when referring to these types. Additionally, the Database::collection
and Database::collection_with_options
helpers now require a generic parameter to be specified as well. This was done to ease and promote the use of serde with the driver. As part of this, Database::collection_with_type
was removed as it was no longer necessary.
// old
let collection = db.collection("foo");
let typed_collection = db.collection_with_type::<MySerdeType>("foo");
struct C { cursor: Cursor }
struct Tc { cursor: Cursor<MySerdeType> }
// new
let collection = db.collection::<Document>("foo");
let typed_collection = db.collection::<MySerdeType>("foo");
struct C { cursor: Cursor<Document> }
struct Tc { cursor: Cursor<MySerdeType> }
Performance Improvements (RUST-518)
The driver was updated to leverage the new raw BSON serialization / deserialization functionality introduced in version 2.0.0
of the bson
crate, significantly improving the performance of reads and inserts (RUST-870, RUST-871). Additionally, many redundant clones were eliminated (RUST-536) and writes and reads to sockets are now buffered, yielding further performance improvements. Initial benchmarks indicate that large inserts and reads could execute in half the time or less in 2.0.0
than in 1.2.3
.
Index Management API (RUST-273)
The driver now exposes an API for creating, listing, and deleting indexes.
e.g.
let new_index = IndexModel::builder()
.keys(doc! { "x": 1 })
.options(IndexOptions::builder().unique(true).build())
.build();
let index_name = collection.create_index(new_index, None).await?.index_name;
let index_names = collection.list_index_names().await?;
assert!(index_names.contains(&index_name));
collection.drop_indexes(None).await?;
let index_names = collection.list_index_names().await?;
assert!(!index_names.contains(&index_name));
Versioned API support (#401)
MongoDB 5.0 introduced the Versioned API, and this release includes support for specifying it via the ClientOptions
.
Reduce the default max_pool_size
to 10 (RUST-823)
In prior versions of the driver, the default max_pool_size
was 100, but this is likely far too high to be a default. For some background on the motivation, see here and here. Note that this is also in line with the defaults for r2d2
and bb8
.
Ensure API meets the Rust API Guidelines (RUST-765)
There is a community-maintained list of API guidelines that every stable Rust library is recommended to meet. The driver's current API wasn't conforming to these guidelines exactly, so a number of improvements were made to ensure that it does. Here we highlight a few of the more important changes made in this effort.
Various error API improvements (RUST-739, RUST-765)
Several improvements were made to the ErrorKind
enum according to the guidelines to provide a more consistent and stable API:
- The variants no longer wrap error types from unstable dependencies (C-STABLE)
- The variant are named more consistently (C-WORD-ORDER)
- Drop redundant
Error
suffix from each variant name
- Drop redundant
- Redundant error variants were consolidated
The total list of breaking changes is as follows:
- All error variants dropped the "Error" suffix (e.g.
ErrorKind::ServerSelectionError
=>ErrorKind::ServerSelection
) ErrorKind::ArgumentError
=>ErrorKind::InvalidArgument
ErrorKind::InvalidHostname
=> removed, consolidated intoErrorKind::InvalidArgument
ErrorKind::BsonDecode
=>ErrorKind::BsonDeserialization
ErrorKind::BsonEncode
=>ErrorKind::BsonSerialization
ErrorKind::ResponseError
=>ErrorKind::InvalidResponse
ErrorKind::DnsResolve(trust_dns_resolver::error::ResolveError)
=>ErrorKind::DnsResolve { message: String }
ErrorKind::InvalidDnsName
=> removed, consolidated intoErrorKind::DnsResolve
ErrorKind::NoDnsResults
=> removed, consolidated intoErrorKind::DnsResolve
ErrorKind::SrvLookupError
=> removed, consolidated intoErrorKind::DnsResolve
ErrorKind::TxtLookupError
=> removed, consolidated intoErrorKind::DnsResolve
ErrorKind::RustlsConfig(rustls::TLSerror)
=>ErrorKind::InvalidTlsConfig { message: String }
ErrorKind::ParseError
=> removed, consolidated intoErrorKind::InvalidTlsConfig
ErrorKind::WaitQueueTimeoutError
=> removed, thewait_queue_timeout
option is no longer supported (RUST-757)ErrorKind::OperationError
=> removed, consolidated intoErrorKind::InvalidResponse
andErrorKind::Internal
as appropriate
Stabilize or eliminate public dependencies on unstable types (C-STABLE, RUST-739)
The driver included types from a number of unstable (pre-1.0) dependencies in its public API, which presented a problem for the stability of the driver itself. tokio
was one such example of this, which is why when it went 1.0, the driver needed a 2.0 release. In an effort to ensure that the driver will no longer be subject to the semver breaks of unstable dependencies and can stay on 2.0 for the foreseeable future, the public dependencies on unstable types were removed altogether or stabilized such that they will always be present.
Here are the notable changes made as part of that:
- Cursor types now implement the
Stream
trait fromfutures-core
rather thanfutures
.futures-core
will be moving directly to1.0
next, whereasfutures
may have several semver-incompatible versions.- The 2.0 version of the driver will continue to depend on
futures-core 0.3
(current release), even afterfutures-core 1.0
is released and/or theStream
trait is included in the standard library. The cursor types will also implement each of theStream
traits fromfutures-core 1.0
andstd
as necessary, and users can depend on and import the one they wish to use. - It's possible no changes will need to be made in the driver to transition to
std::Stream
. See (rust-lang/futures-rs#2362)
ErrorKind
variants that wrapped unstable errors were removed or refactored (see above)- Introduced a
ResolverConfig
type that opaquely wraps atrust_dns_resolver::ResolverConfig
TlsOptions::into_rustls_config
was removed from the public API
Wrap Error::kind
in a Box
(RUST-742)
As an ergonomic improvement to the Error
type, the ErrorKind
field of Error
was updated to be wrapped in a Box
instead of an Arc
. This will allow you to get an owned ErrorKind
via the *
operator, which was previously impossible with the Arc
wrapper.
Accept impl Borrow<T>
in various CRUD methods (RUST-754)
Prior to this release, methods such as Collection::insert_one
accepted an owned T
despite not actually requiring ownership of the value. This could lead to wasteful clones that hurt performance. As an improvement, these methods were updated to accept impl Borrow<T>
, which means either owned or borrowed types may be passed in.
Return types that implement Deserialize
from Client::list_databases
and Database::list_collections
(RUST-740)
These methods used to return Vec<Document>
and Cursor<Document>
respectively, both of which do not take advantage of the fact that the format of the returned documents is known and stable. To improve on that, these methods were updated to return Vec<DatabaseSpecification>
and Cursor<CollectionSpecification>
instead, which should make the responses more ergonomic to work with.
Refactor StreamAddress
(RUST-760)
StreamAddress
was used to specify via the ClientOptions
which hosts the driver was to connect to. This type was inaccurate though, since it usually contained DNS names that get resolved to one or more socket addresses rather than the socket address itself. Furthermore, in the future the driver may want to support other ways of connecting to MongoDB servers, such as Unix Domain Sockets, which would further make the StreamAddress
name confusing. To improve the accuracy of the type's name enable it to be more easily extended in the future, it was refactored to the following type:
#[non_exhaustive]
pub enum ServerAddress {
Tcp { host: String, port: Option<u16> }
}
This is similar to the equivalent types provided by the tokio-postgres
and redis
crates.
Note: this change only affects users that construct their own ClientOptions
structs (as opposed to parsing them from a connection string) or consumers of CMAP events.
Move trait bounds from Collection
to implementation blocks (RUST-852)
In prior releases, the generic type T
on Collection
had a few trait bounds (e.g. DeserializeOwned
and Serialize
). These bounds could become cumbersome in certain situations where only a subset of them was required, such as when performing a find
with a projection (i.e. a read-only type only needs to implement DeserializeOwned
). To resolve this issue, the trait bounds were moved from Collection
itself to the implementation blocks for the methods that require them, so the T
only needs to implement the trait requirements for the methods it's used in.
For example, if a collection is only used for insertion, T
only needs to implement Serialize
:
#[derive(Debug, Serialize)]
struct Foo {
name: String,
}
// wouldn't compile before because Foo isn't DeserializeOwned, but now compiles because `T` has no trait bounds
let collection = db.collection::<Foo>("foo");
// compiles because Foo is Serialize
collection.insert_one(Foo { name: "Foo".to_string() }, None).await?;
// doesn't compile since Foo isn't DeserializeOwned
collection.find_one(doc! {}, None).await?;
This also has the added benefit of allowing other structs and enums to contain Collection<T>
without also having to inherit the trait bounds, as Collection<T>
no longer has any.
SDAM Monitoring support (RUST-232)
The driver now exposes an API for monitoring Server Discover and Monitoring events (SDAM), which can be useful when debugging connectivity issues with the driver.
e.g.
struct FailedHeartbeatLogger;
impl SdamEventHandler for FailedHeartbeatLogger {
fn handle_server_heartbeat_failed_event(&self, event: ServerHeartbeatFailedEvent) {
eprintln!("Failed server heartbeat: {:?}", event);
}
}
let handler: Arc<dyn SdamEventHandler> = Arc::new(FailedHeartbeatLogger);
let options = ClientOptions::builder()
.sdam_event_handler(handler)
.build();
let client = Client::with_options(options)?;
// Do things with the client, and failed server heartbeats will be logged to stderr.
Full Release Notes
New features
- RUST-1006 Upgrade
bson
to2.0.0
(breaking) - RUST-90, RUST-734 Implement transactions support
- RUST-273 Index management API
- RUST-232 SDAM monitoring API
- RUST-732 Mark the versioned API options public. (#401)
- RUST-885 Support snapshot sessions (#390)
- RUST-666 Add options for timeseries collection creation (#381)
- RUST-824 Add
Snapshot
variant toReadConcernLevel
enum - RUST-738 Implement Clone on BSON error types (breaking)
- RUST-740 Return Deserialize types from list_databases and list_collections (breaking)
- RUST-754 Accept references in insert and replace methods (breaking)
- RUST-796 Provide easy way to reborrow session in between cursor iterations (breaking)
- RUST-52 Drivers sessions API
- RUST-735 Collection helpers return
Collection<T>
(breaking) - RUST-662 Expose the Reason an Operation Fails Document Validation
- RUST-836 Support the 'let' option for aggregate (#391)
- RUST-1002 Allow authentication to all server types except arbiters
Improvements
- RUST-633 Update dependency on
tokio
tov1.x
(breaking) - RUST-870 Deserialize server response directly from raw BSON bytes (#389) (breaking)
- RUST-871 Serialize directly to BSON bytes in insert operations (#406)
- RUST-766 Gate MONGODB-AWS authentication behind the
aws-auth
feature flag (breaking) - RUST-725 Use "hello" for handshake and heartbeat when an API version is declared (#380)
- RUST-768 Pass versioned API parameters to
getMore
and transaction-continuing commands. (#397) - RUST-887 Use
HashMap::contains
inError::contains_label
(#386) - RUST-615 Upgrade
typed-builder
to0.9.0
- RUST-739 Don't re-export types from unstable dependencies (breaking)
- RUST-742 Reduce size of
Error
andErrorKind
(breaking) - RUST-760 Refactor
StreamAddress
toServerAddress
enum (breaking) - RUST-757 Remove
wait_queue_timeout
(breaking) - RUST-761 Rename
CreateCollectionOptions::validation
toCreateCollectionOptions::validator
(breaking) - RUST-764 Use unsigned integers for values that should always be positive (breaking)
- RUST-765 Ensure API follows Rust API Guidelines (breaking)
- RUST-784 Mark
WriteConcern::validate
aspub(crate)
(breaking) - RUST-786 Update collation options to use custom types rather than integers and strings (breaking)
- RUST-788 Accept
impl AsRef<str>
instead of&str
(breaking) - RUST-791 Accept
PathBuf
instead ofString
for paths in options (breaking) - RUST-811 Add feature flags for
chrono
anduuid
interop inbson
- RUST-823 Reduce the default
max_pool_size
to 10 (breaking) - RUST-830 Consolidate error labels to
Error::labels
(breaking) - minor: update
semver
to 1.0 (thanks @dtolnay!) - RUST-719 Correct casing in
ServerType
variants (breaking) - RUST-705 Switch from
err-derive
tothiserror
- RUST-658 Change
estimated_document_count()
to use the$collStats
aggregation stage - RUST-536 Eliminate redundant clones
- RUST-852 Move trait bounds to implementation instead of Collection struct (thanks @univerz for suggesting!)
- RUST-695 Add test that ensures the error returned from being evicted from the WaitQueue is retryable
- RUST-777 Fix race condition in pool-clear-clears-waitqueue.yml test
- RUST-835 Bump maxWireVersion for MongoDB 5.0
- RUST-840 Buffer all reads and writes to sockets
- RUST-847 Redact
Debug
forCredential
- RUST-849 Remove extra fields from
ConnectionPoolOptions
included in events (breaking) - RUST-970 Upgrade to
hmac
0.11 (thanks @seanpianka!)
Bug fixes
- RUST-591 ConnectionPoolOptions is used for event monitoring and pool internals (breaking)
- RUST-759 DropCollectionOptions should skip serializing fields with a None value
- RUST-714 Deadlock possible during retry
- RUST-675 Server selection fails despite having a selectable server
- RUST-717 Hint should be in
deletes
array for command, not in top-level document - RUST-718 Enforce update versus replace semantics
- RUST-728 Inherit Collection options in
find
method - RUST-571 Fix race between SDAM and SRV Polling
- RUST-853 Connection pools must be created and eventually marked ready for any server if a direct connection is used
- RUST-570 Improve compile times of the test suite (#412)
- RUST-793 Reduce size of returned futures (#417)
- RUST-945 Check that explicit sessions were created on the correct client (#405)
- RUST-926 Allow direct connections to hidden nodes
Tasks
- RUST-736 Update documentation for 2.0 release (#437)
- RUST-730 Add MSRV policy to documentation (#444)
- RUST-1001 Add warning about not polling futures to completion (#439)
- RUST-162 Test driver on ARM Linux platforms
- RUST-310 Rewrite URI options tests to use serde
- RUST-814 Test on newer Ubuntu version(s)
- RUST-820 Test against 5.0 servers
- RUST-35 Add integration tests for writeConcern using command monitoring
- RUST-652 Add script to run all linter tests
- RUST-810 Add test for security-sensitive command monitoring event redaction
- RUST-795 Update versioned api connection examples (#400)
- RUST-670 Expect unified test format operations to succeed (#388)
- RUST-665 Sync spec tests for field names with dots and dollars (#385)
- RUST-734 Document support for sharded transactions
- RUST-605 Update Versioned API Documentation
- RUST-873 Test redaction of replies to security-sensitive commands
- RUST-881 Run test suite with requireApiVersion 1
- RUST-895 Update documentation for Time Series
- RUST-944 Integration tests for observeSensitiveCommands
- RUST-749 Convert CRUD tests to unified format (#410)
- RUST-773 Update CMAP spec tests to prevent cross-test failpoint interference (#395)
- RUST-774 Allow tests to specify
backgroundThreadIntervalMS
to fix a race condition. (#396) - RUST-775 CMAP integration test waits for wrong event
- RUST-859 Improve bson_util function consistency (#411)
- RUST-905 Try reading the default server URI from a local file if $MONGODB_URI is unset (#409)