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

Fix #483, #484 and above all handle errors happening in search stream leaves. #487

Merged
merged 10 commits into from
Sep 1, 2021

Conversation

fmassot
Copy link
Contributor

@fmassot fmassot commented Aug 29, 2021

Fixes #483 #484

Bonus:

  • the leaf stream return a search error and not a tonic status
  • add tests at the root and leaf levels
  • add test on the cli (csv output)

Not included:

  • tests on collector: some important changes are coming soon and I would prefer to implement tests at this moment
  • tests on performance would be nice

@fmassot fmassot requested a review from evanxg852000 August 29, 2021 21:11
@fmassot fmassot changed the title Fix #483, #484 and above all handle errors happening in leaves. Fix #483, #484 and above all handle errors happening in search stream leaves. Aug 29, 2021
@fmassot fmassot force-pushed the fix-stream-search branch from db82dac to 9c55514 Compare August 30, 2021 14:34
@fmassot fmassot force-pushed the fix-stream-search branch from c6287a7 to 0b8b095 Compare August 31, 2021 19:37
Copy link
Member

@guilload guilload left a comment

Choose a reason for hiding this comment

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

After reading this PR, I vote for changing SearchError::InternalError(String) to SearchError::InternalError(anyhow::Error).

quickwit-cli/tests/cli.rs Outdated Show resolved Hide resolved
quickwit-cli/tests/cli.rs Outdated Show resolved Hide resolved
quickwit-cli/tests/cli.rs Outdated Show resolved Hide resolved
quickwit-cli/tests/cli.rs Outdated Show resolved Hide resolved
assert_eq!(metadata_file_exist, false);

Ok(())
}
Copy link
Member

Choose a reason for hiding this comment

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

We could also test that the split file no longer exists.

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 SearchError gets serialized/deserialized... anyhow cannot be serialized, hence the msg.

Copy link
Member

Choose a reason for hiding this comment

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

I like anyhow because it tends to do a better job at tracking the underlying error while we do a poor job at it. We could serialize the anyhow error as a string using the debug format, which displays the cause and a backtrace if one is present.

result_sender.send(Ok(result)).map_err(|_| {
SearchError::InternalError("Could not send leaf result".into())
})?;
loop {
Copy link
Member

Choose a reason for hiding this comment

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

I find this logic hard to follow. results_stream is a Streaming<T> struct which implements Stream. We can greatly simplify the whole thing:

let mut results_stream = grpc_client_clone
                        .leaf_search_stream(tonic_request)
                        .await
                        .map_err(|tonic_error| parse_grpc_error(&tonic_error))?
                        .into_inner()
                        .take_while(|grpc_result| futures::future::ready(grpc_result.is_ok()))
                        .map_err(|tonic_error| parse_grpc_error(&tonic_error));

                    while let Some(search_result) = results_stream.next().await {
                        result_sender.send(search_result).map_err(|_| {
                            SearchError::InternalError(
                                "Sender closed, could not send leaf result.".into(),
                            )
                        })?;
                    }

Copy link
Member

Choose a reason for hiding this comment

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

I think this is actually going to swallow the last error :x

Copy link
Member

Choose a reason for hiding this comment

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

This is what I want rust-lang/rust#62208. Anyway t_t

Copy link
Contributor Author

@fmassot fmassot Sep 1, 2021

Choose a reason for hiding this comment

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

the last element of the stream is None so I think it should work, I really like your version, I did not think about the take_while

@@ -168,11 +168,13 @@ impl FastFieldCollectorBuilder {
}

pub fn fast_field_to_warm(&self) -> Vec<String> {
Copy link
Member

Choose a reason for hiding this comment

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

Had this return type be a Set, we wouldn't have to do this. Is tag_fields on IndexConfig also a Vec instead of a Set?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

agreed

Result::<(), SearchError>::Ok(())
});
}
let request_clone = request.clone();
Copy link
Member

Choose a reason for hiding this comment

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

We could "own" that request and not clone it as you did in some other parts of this PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1... Generally speaking if ownership is required, it is better to reflect it in the prototype. It does not necessarily avoid the clone, but at least it might.

let mut stream =
leaf_search_results_stream(request_clone, storage, splits, index_config).await;
while let Some(item) = stream.next().await {
if let Err(error) = result_sender.send(item) {
Copy link
Member

Choose a reason for hiding this comment

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

Just my personal preference, but I like the map_err(...)? pattern better.

Copy link
Contributor

Choose a reason for hiding this comment

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

I prefer the if let Err here.

The body here is just doing logging (so a side effect).
map_err is more about converting an error isn't it?

storage.clone(),
)
})
.map(|(split, index_config_clone, request_clone, storage)| {
Copy link
Member

Choose a reason for hiding this comment

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

Why the double map? Readability?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

readability and compiler issue I had but it's no more relevant.

@guilload
Copy link
Member

I mostly made syntactical comments. The functional changes are great and good job on those tests.

Co-authored-by: Adrien Guillo <adrien@quickwit.io>
Copy link
Contributor Author

@fmassot fmassot left a comment

Choose a reason for hiding this comment

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

After reading this PR, I vote for changing SearchError::InternalError(String) to SearchError::InternalError(anyhow::Error).

We serialize SearchError to pass it through the network so I'm not sure how to handle it on the serialization side. We could serialize the error as a string but then we're back to square one. Nevertheless, we could at least have real errors on the root because these errors are not serialized.

Right now, I have the feeling that we already need to improve the errors we are handling (SearchError, NodeSearchError), I found it a little bit messy.

@@ -168,11 +168,13 @@ impl FastFieldCollectorBuilder {
}

pub fn fast_field_to_warm(&self) -> Vec<String> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

agreed

@fulmicoton
Copy link
Contributor

Glad to see unit tests on thjis part of the code!

@fmassot fmassot merged commit b76a468 into main Sep 1, 2021
@fmassot fmassot deleted the fix-stream-search branch September 1, 2021 09: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.

Use spawn_blocking in leaf stream search
4 participants