-
Notifications
You must be signed in to change notification settings - Fork 173
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-1384 Implement auto encryption #717
Conversation
// can return a helpful error if things get into a broken state rather than panicing. | ||
let mut ctx = Ok(ctx); | ||
loop { | ||
let state = result_ref(&ctx)?.state()?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
result_ref
and result_mut
are needed because as_ref
/as_mut
on Results
also applies to the error type, which causes an error when using ?
because the types don't match the return type.
while let Some(kms_ctx) = scope.next_kms_ctx() { | ||
kms_ctxen.push(Ok(kms_ctx)); | ||
} | ||
stream::iter(kms_ctxen) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just using spawn
for concurrency here wouldn't work because that requires a 'static
bound; it's a little odd that the non-static equivalent is only found when operating on streams, but 🤷
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the stream versoin works basically the same as FuturesUnordered
: the current thread polls all the futures, rather than having potentially many threads doing it in parallel.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, there it is. Yup, it's polling rather than parallel, which seems fine for this because these futures are going to be IO-bound anyway.
I'm going to stick with using the stream method rather than FuturesUnordered
directly because the semantics of try_for_each_concurrent
are very handy here.
csfle: &'a super::csfle::ClientState, | ||
command: &'a RawDocument, | ||
target_db: &'a str, | ||
) -> BoxFuture<'a, Result<RawDocumentBuf>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be boxed because it's technically recursive (run_mongocrypt_ctx
can execute operations).
pub(crate) use run_command::RunCommand; | ||
pub(crate) use update::Update; | ||
|
||
const SERVER_4_2_0_WIRE_VERSION: i32 = 8; | ||
|
||
/// A trait modeling the behavior of a server side operation. | ||
/// | ||
/// No methods in this trait should have default behaviors to ensure that wrapper operations | ||
/// replicate all behavior. Default behavior is provided by the `OperationDefault` trait. | ||
pub(crate) trait Operation { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Trait
/ TraitWithDefaults
pattern introduced here solves a gripe I've had for a while, which is that when implementing something that delegates most trait logic (e.g. raw_output::RawOutput
) you won't get any help from the compiler if new trait methods are added that have defaults, which in turn could cause nasty logic bugs downstream. It's definitely a little awkward and not worth using for most traits, but Operation
is critical enough that it seems worth using here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good overall! just a couple comments re: spec details
@@ -49,7 +54,7 @@ impl<'a, T> Insert<'a, T> { | |||
} | |||
} | |||
|
|||
impl<'a, T: Serialize> Operation for Insert<'a, T> { | |||
impl<'a, T: Serialize> OperationWithDefaults for Insert<'a, T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed the spec talks about some differences in batch splitting behavior when automatic encryption is being used - it sounds like we might need to use 2MiB rather than max_bson_obj_size
as the split boundary below?
cc @isabelatkinson - I think we'll need to keep the differing size limit in mind with the new bulk spec and API
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, you're right - I'd initially read that as applying only to the bulk write API, but it also applies here. Updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I filed RUST-1438 so we remember to do the same for bulk writes when the time comes
let db = self.database(db.as_ref().ok_or_else(|| { | ||
Error::internal("db required for NeedMongoCollinfo state") | ||
})?); | ||
let mut cursor = db.list_collections(filter, None).await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this operation is actually supposed to use the metadata client to avoid potential deadlocks, as described in this section of the spec. I see the integration guide mentions using the encrypted MongoClient
, but I think we maybe forgot to update that back when SPEC-1768 was done (if so, it would be good to make a PR to update it for future readers).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, fixed. I'll send a PR for the integration guide.
115e6fd
to
6bbd8c1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! I just have some clarifying questions
while let Some(kms_ctx) = scope.next_kms_ctx() { | ||
kms_ctxen.push(Ok(kms_ctx)); | ||
} | ||
stream::iter(kms_ctxen) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the stream versoin works basically the same as FuturesUnordered
: the current thread polls all the futures, rather than having potentially many threads doing it in parallel.
|
||
use super::Operation; | ||
|
||
pub(crate) struct RawOutput<Op>(pub(crate) Op); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a docstring indicating this type's purpose? If I'm understanding it right, it forwards all implementation to the underlying op except that it performs no validation or parsing of the response, is that right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, that's correct - added a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the commit for this didn't actually get pushed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops, fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! (bar a commit from a previous comment, no need for me to re-review)
|
||
use super::Operation; | ||
|
||
pub(crate) struct RawOutput<Op>(pub(crate) Op); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the commit for this didn't actually get pushed.
Oh and it looks like the clippy task failed. |
Looks like those failures are in |
src/operation/mod.rs
Outdated
@@ -398,3 +391,140 @@ macro_rules! remove_empty_write_concern { | |||
} | |||
|
|||
pub(crate) use remove_empty_write_concern; | |||
|
|||
// A mirror of the `Operation` trait, with default behavior where appropriate. Should only be | |||
// implemented by leaf operation types. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you mean by leaf operation types here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Derp, my inner terminology leaking out. Updated the comment to clarify.
src/operation/run_command/test.rs
Outdated
@@ -20,7 +22,8 @@ fn build() { | |||
command | |||
.body | |||
.get("hello") | |||
.and_then(crate::bson_util::get_int), | |||
.unwrap() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should just remove this rather than updating
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call, done. Sorry that I keep forgetting that!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like the format task failed but lgtm otherwise!
RUST-1384
This implements support for auto encryption and decryption; the large majority of the complexity is in
state_machine.rs
; the changes needed to the main executor were pretty minor.This is the companion PR to mongodb/libmongocrypt-rust#11 (and its ill-fated predecessor mongodb/libmongocrypt-rust#9).