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-52 Implement Sessions API #304

Merged
merged 2 commits into from
Mar 29, 2021
Merged

Conversation

isabelatkinson
Copy link
Contributor

No description provided.

@isabelatkinson isabelatkinson marked this pull request as draft March 15, 2021 14:59
src/client/options/mod.rs Show resolved Hide resolved
src/error.rs Show resolved Hide resolved
src/sdam/description/topology/mod.rs Show resolved Hide resolved
src/test/spec/sessions/mod.rs Outdated Show resolved Hide resolved
let result = match operation.object {
OperationObject::Collection => {
let result = operation.execute_on_collection(&coll, session).await;
if test.description == "Server supports implicit sessions" {
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 one particular test runs two operations with implicit sessions in sequence and then checks to see if they used the same lsid. Delaying here has the same effect as delaying after calling drop (since drop is called when the implicit session goes out of scope); made it conditional to avoid slowing down the tests a ton.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds good, could you add a comment into the code here explaining that?

}
OperationObject::TestRunner => {
match operation.name.as_str() {
"assertDifferentLsidOnLastTwoCommands" => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

All of these operations take in different arguments so it didn't make much sense to integrate them into the usual operation parsing -- I'll abstract this out a little more if it gets too unwieldy when the additional transactions operations are introduced.

@@ -0,0 +1,1178 @@
use std::{collections::HashMap, fmt::Debug, ops::Deref};
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 is all quite similar to the operations stuff in the other runners, just some minor adjustments to fit in with the specific test schema for sessions/transactions.

Copy link
Contributor

Choose a reason for hiding this comment

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

The README for the runner claims it has the same format as the transactions runner, which should mean it has the v2 format (transactions / retryable reads / crud v2). Is there any chance we'll be able to reuse code there instead of introducing an entirely new runner?

for (k, v) in &expected.command {
if k == "lsid" {
match v.as_str().unwrap() {
"session0" => {
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 tests specify lsids as the name of the session (e.g.)

src/client/executor.rs Outdated Show resolved Hide resolved
src/client/options/mod.rs Show resolved Hide resolved
src/coll/mod.rs Show resolved Hide resolved
src/cursor/session.rs Outdated Show resolved Hide resolved
src/selection_criteria.rs Outdated Show resolved Hide resolved
src/test/spec/sessions/mod.rs Outdated Show resolved Hide resolved
@isabelatkinson isabelatkinson marked this pull request as ready for review March 16, 2021 17:30
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.

Looks really good so far! I haven't gotten a chance to review the whole thing yet, but I do have a few minor comments / suggestions on the bits I have seen.

src/coll/mod.rs Outdated Show resolved Hide resolved
src/db/mod.rs Show resolved Hide resolved
src/sdam/description/topology/mod.rs Show resolved Hide resolved
let result = match operation.object {
OperationObject::Collection => {
let result = operation.execute_on_collection(&coll, session).await;
if test.description == "Server supports implicit sessions" {
Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds good, could you add a comment into the code here explaining that?

@@ -0,0 +1,1178 @@
use std::{collections::HashMap, fmt::Debug, ops::Deref};
Copy link
Contributor

Choose a reason for hiding this comment

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

The README for the runner claims it has the same format as the transactions runner, which should mean it has the v2 format (transactions / retryable reads / crud v2). Is there any chance we'll be able to reuse code there instead of introducing an entirely new runner?

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.

Looks great! I just have a few minor comments about the ClientSession type and the tests.

src/client/session/mod.rs Outdated Show resolved Hide resolved
/// Returns a mutable reference to this session wrapped in an option. This method is necessary
/// to bypass the construction of an option taking ownership of a mutable reference.
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn as_mut_ref_option(&mut self) -> Option<&mut Self> {
Copy link
Contributor

Choose a reason for hiding this comment

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

I looked into this some more, and the issue has to do with reborrowing (well actually, the fact that a reborrow is not occurring). A reborrow seems to basically be an implicit copy of the reference that the compiler will insert in certain situations such as a function call. What's surprising is that hits behavior works even for mutable references, which do not implement Copy or Clone. It seems that due to the non-lexical-lifetimes feature, the compiler can tell when having multiple mutable references is okay or not. It also seems that the compiler is no longer able to / does not attempt to determine if a reborrow is safe when putting the mutable reference into an enum for passing into execute_operation (I think this is because Option is generic and does not have any &mut specified, see here for an explanation). Calling as_mut_ref_option does work though, since it first reborrows &mut self and then moves that reference into an Option, preventing a use-after-move compiler error. This could similarly be achieved by doing an explicit reborrow like Some(&mut *session). Feel free to keep this method if you think it's clearer or easier to use though.

This is all not documented very well, so most of what I understand of this situation comes from various forums / stackoverflow posts. Check out rust-lang/reference#788 for some useful links (and the request for better documentation on reborrows).

As a funny side note: I introduced MutableSessionRef to actually do the opposite of what our problem here is--I needed a way to force a reference to move rather than reborrow, so I wrapped it in a struct which I could move around.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Huh that's super interesting; I'm surprised there isn't better documentation of this in the Rust book. Updated to use an explicit reborrow.

src/test/spec/v2_runner/test_event.rs Outdated Show resolved Hide resolved
src/test/util/event.rs Outdated Show resolved Hide resolved
src/test/util/event.rs Outdated Show resolved Hide resolved
src/client/session/mod.rs Show resolved Hide resolved
src/coll/mod.rs Outdated Show resolved Hide resolved
@patrickfreed
Copy link
Contributor

Code changes LGTM, it looks like this just needs to be rebased to fix the merge conflict. I think the compilation issue on 1.45 should go away after that too.

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! Great job with this!

Side note: there may be some tricky merge conflicts with the error changes in #301, particularly with cursors. It may help to coordinate somehow with @saghm on merging them in.

@isabelatkinson
Copy link
Contributor Author

Side note: there may be some tricky merge conflicts with the error changes in #301, particularly with cursors. It may help to coordinate somehow with @saghm on merging them in.

@saghm I think it would be easiest for you to merge the error changes first; once that's in I can rebase and you can review whatever changes are needed to apply that work to this PR.

Copy link
Contributor

@saghm saghm left a comment

Choose a reason for hiding this comment

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

One question/suggestion about making something public and one clarification question about the v2 runner, but other than those, this looks good to me. Great job on this!

pub(crate) struct ClusterTime {
cluster_time: Timestamp,
pub struct ClusterTime {
pub cluster_time: Timestamp,
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think these should be public; this allows a user who owns a ClusterTime to modify the timestamp or the signature, which is not useful since it would presumably break it. If users do actually need to inspect these values, we should make them private and add getters, but I think that this is supposed to be a mostly opaque value to users (that they receive from the driver and then can pass back in other places without needing to care about the internals), in which case we wouldn't need getters. Since the struct derives Debug, users will still be able to log cluster times even if we don't add getters, so that wouldn't be a reason to add getters either.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That makes sense to me, the reasoning for exposing these was mainly for inspecting, but I think deriving Debug should take care of that.

@@ -0,0 +1,304 @@
pub mod operation;
Copy link
Contributor

Choose a reason for hiding this comment

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

This (and the rest of the v2 test runner) is just moved from the previous location in the CRUD spec tests, correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yep, I just did some renaming for the sake of clarity

@isabelatkinson isabelatkinson merged commit 9cb95fe into mongodb:master Mar 29, 2021
@isabelatkinson isabelatkinson deleted the RUST-52 branch March 29, 2021 17:39
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.

3 participants