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-48 Causal consistency support #493

Merged
merged 15 commits into from
Nov 10, 2021

Conversation

awitten1
Copy link
Contributor

This PR provides support for causal consistency.

The change that is needed to support causally consistent sessions is that readConcern.afterClusterTime now needs to be included in all commands that are part of a causally consistent session that take a readConcern. readConcern.afterClusterTime must be set to the operationTime field of the ClientSession struct (initialized to None). The operationTime field of the ClientSession struct must get updated to the operationTime field of the server's response to any command that is part of a causally consistent session (this field is included on success or error).

The main difficulty is that readConcern.level now is not always included when readConcern is included. To address that I introduced a new type readConcernInternal that takes the role of readConcern in certain cases (when level is optional).

Currently there is a bug in this implementation where there are duplicate readConcern fields being included. Most likely this is because the readConcern in FindOptions (for example) and the readConcern that is set on the session are both being serialized.

@awitten1 awitten1 marked this pull request as draft October 15, 2021 20:19
@patrickfreed patrickfreed force-pushed the RUST-48_Causal-Consistency branch from 9b721da to da602c1 Compare November 2, 2021 22:22
@patrickfreed patrickfreed marked this pull request as ready for review November 4, 2021 23:45
@@ -466,6 +466,7 @@ pub struct ClientOptions {
/// Specifies the default read concern for operations performed on the Client. See the
/// ReadConcern type documentation for more details.
#[builder(default)]
#[serde(skip_serializing)]
Copy link
Contributor

Choose a reason for hiding this comment

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

Why does this need to be skipped?

Copy link
Contributor

Choose a reason for hiding this comment

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

Read concern is now included in the Command struct, so it needs to be skipped here otherwise it'll be serialized twice.

Copy link
Contributor

Choose a reason for hiding this comment

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

That makes sense for the individual command options updated elsewhere, but I don't think ClientOptions is included in the serialized command form? AFAICT ClientOptions only implements Serialize / Deserialize for test code.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ohh I see, this was just a search/replace mistake. Fixed.

s,
)));

ops
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: can remove a little bit of noise here by preemptively returning ops.into_iter() and updating the signature to return impl Iterator.

Copy link
Contributor

Choose a reason for hiding this comment

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

good idea, fixed

at_cluster_time: None,
after_cluster_time: None,
});
inner.level = Some(read_concern.level.clone());
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this now only sets the level, it seems like it'd be clearer to have it only accept the level as a parameter.

Copy link
Contributor

Choose a reason for hiding this comment

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

done

@@ -124,6 +127,12 @@ pub(crate) trait Operation {
None
}

/// Returns whether or not this command supports the `readConcern` field, and if so, the read
Copy link
Contributor

Choose a reason for hiding this comment

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

Comment doesn't seem accurate?

Copy link
Contributor

Choose a reason for hiding this comment

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

good catch, fixed.

Copy link
Contributor

@abr-egn abr-egn left a comment

Choose a reason for hiding this comment

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

LGTM!

///
/// Defaults to true.
pub causal_consistency: Option<bool>,

/// If true, all read operations performed using this client session will share the same
/// snapshot. Defaults to false.
// TODO RUST-18 enforce snapshot exclusivity with causalConsistency.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can delete this TODO (looks like it's pointing to the wrong ticket)

Copy link
Contributor

Choose a reason for hiding this comment

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

removed

/// If true, all operations performed in the context of this session
/// will be [causally consistent](https://docs.mongodb.com/manual/core/causal-consistency-read-write-concerns/).
///
/// Defaults to true.
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 clarify this to indicate that this field only defaults to true if snapshot is unspecified?

Copy link
Contributor

Choose a reason for hiding this comment

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

good idea, added

@@ -91,6 +92,12 @@ impl Operation for Aggregate {
.and_then(|opts| opts.selection_criteria.as_ref())
}

fn supports_read_concern(&self, description: &StreamDescription) -> bool {
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this have to do with causal consistency or is this a validation we were missing?

Copy link
Contributor

Choose a reason for hiding this comment

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

Causal consistency requires that we set a read concern in the executor now, whereas before individual operations were in charge of serializing read concerns. Now that the executor is in charge of that, it needs to know when it can set them, hence this method. The check for it can be seen here: https://github.com/awitten1/mongo-rust-driver/blob/RUST-48_Causal-Consistency/src/client/executor.rs#L430

I think users setting read concerns on operations that don't support them is one of those things we're meant to leave to the server to validate, but we do need to validate that the driver doesn't accidentally set a read concern behind the scenes when it shouldn't.

@patrickfreed patrickfreed merged commit b843bfa into mongodb:master Nov 10, 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.

4 participants