Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RUST-885 Support snapshot sessions #390

Merged
merged 22 commits into from
Jul 14, 2021

Conversation

abr-egn
Copy link
Contributor

@abr-egn abr-egn commented Jul 9, 2021

RUST-885

This adds support for the snapshot session option, and the associated client-side machinery to track read operation session timestamps. This also fixes RUST-878 and RUST-879.

@abr-egn abr-egn marked this pull request as draft July 9, 2021 19:03
@@ -120,11 +131,21 @@ impl CommandResponse {
let cluster_time = raw_response
.get("$clusterTime")
.and_then(|subdoc| bson::from_bson(subdoc.clone()).ok());
let snapshot_time = raw_response
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial approach was to add atClusterTime as an explicit field in the output of the relevant commands (find, aggregate, distinct), but that required:

  • introducing a trait for the output type of an operation, which added a lot of churn, and
  • additional special handling in operations implemented on top of one of those three (e.g. countDocuments).

The approach here avoids both of those issues at the cost of digging a bit into the raw document.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As part of #389, I actually did have to introduce a trait for the output type of an operation (there was definitely a lot of churn, but for that work it was required I think), so we could still go with your original plan once that PR is merged. For the purposes of avoiding merge conflicts, I think it'll probably be easier to merge this PR first though and then rebase #389 off of that and adjust for atClusterTime accordingly there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, with that trait existing it definitely makes sense to go back to extracting the snapshot time that way. Your plan for merging SGTM.

#[non_exhaustive]
pub struct ReadConcern {
/// The level of the read concern.
pub level: ReadConcernLevel,

/// The snapshot read timestamp.
#[serde(skip_serializing_if = "Option::is_none")]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The server rejects commands with atClusterTime: null.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, would adding #[serde(skip_serializing_none)] to the ReadConcern struct do the trick here as well? We use that for a lot of our options structs but I'm wondering if that would break other behavior here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I'd missed that, thank you! It looks like that works as well, updated to be consistent with the rest of the codebase.

@@ -152,22 +153,20 @@ pub(crate) struct CursorSpecification {

impl CursorSpecification {
pub(crate) fn new(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This refactor was in service of being able to pass an at_cluster_time field through easily, but even without that it seemed worthwhile to leave in.

@abr-egn abr-egn marked this pull request as ready for review July 12, 2021 13:52
src/error.rs Outdated
/// The server version does not support the operation.
#[error("The server version does not support a database operation: {message}")]
#[non_exhaustive]
ServerVersion { message: String },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about naming this IncompatibleServerVersion instead for some added clarity? Or even IncompatibleServer in case there are more criteria in the future unrelated to server version that may cause an operation to fail?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, done.

@@ -120,11 +131,21 @@ impl CommandResponse {
let cluster_time = raw_response
.get("$clusterTime")
.and_then(|subdoc| bson::from_bson(subdoc.clone()).ok());
let snapshot_time = raw_response
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As part of #389, I actually did have to introduce a trait for the output type of an operation (there was definitely a lot of churn, but for that work it was required I think), so we could still go with your original plan once that PR is merged. For the purposes of avoiding merge conflicts, I think it'll probably be easier to merge this PR first though and then rebase #389 off of that and adjust for atClusterTime accordingly there.

Copy link
Contributor

@patrickfreed patrickfreed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

self.list_databases_common(filter, options, None).await
}

/// Gets information about each database present in the cluster the Client is connected to.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add "using the provided ClientSession" to this doc (in the same vein as e.g. this)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, done.

#[non_exhaustive]
pub struct ReadConcern {
/// The level of the read concern.
pub level: ReadConcernLevel,

/// The snapshot read timestamp.
#[serde(skip_serializing_if = "Option::is_none")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, would adding #[serde(skip_serializing_none)] to the ReadConcern struct do the trick here as well? We use that for a lot of our options structs but I'm wondering if that would break other behavior here.

@abr-egn abr-egn merged commit 8b808e3 into mongodb:master Jul 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants