-
Notifications
You must be signed in to change notification settings - Fork 986
DRILL-8307: Ensure thread safety in the Druid plugin HTTP client #2650
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,38 +17,36 @@ | |
| */ | ||
| package org.apache.drill.exec.store.druid.rest; | ||
|
|
||
| import org.apache.http.HttpEntity; | ||
| import org.apache.http.HttpResponse; | ||
| import org.apache.http.client.HttpClient; | ||
| import org.apache.http.client.methods.HttpGet; | ||
| import org.apache.http.client.methods.HttpPost; | ||
| import org.apache.http.entity.StringEntity; | ||
| import org.apache.http.impl.client.DefaultHttpClient; | ||
|
|
||
| import javax.ws.rs.core.HttpHeaders; | ||
| import java.io.IOException; | ||
| import java.nio.charset.Charset; | ||
| import java.nio.charset.StandardCharsets; | ||
| import okhttp3.OkHttpClient; | ||
| import okhttp3.Request; | ||
| import okhttp3.RequestBody; | ||
| import okhttp3.Response; | ||
|
|
||
| import static javax.ws.rs.core.MediaType.APPLICATION_JSON; | ||
| import static org.apache.http.protocol.HTTP.CONTENT_TYPE; | ||
| import java.nio.charset.StandardCharsets; | ||
| import java.io.IOException; | ||
|
|
||
| public class RestClientWrapper implements RestClient { | ||
| private static final HttpClient httpClient = new DefaultHttpClient(); | ||
| private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8; | ||
| // OkHttp client is designed to be shared across threads. | ||
| private final OkHttpClient httpClient = new OkHttpClient(); | ||
|
|
||
| public Response get(String url) throws IOException { | ||
| Request get = new Request.Builder() | ||
| .url(url) | ||
| .addHeader("Content-Type", "application/json") | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why would a get request need a content-type? Content-Type on a request refers to the type of the request body but for GETs, this is empty. Maybe I've misunderstood the intent, but shouldn't this be an Accept header? An Accept header is used to tell the HTTP server that the client (us) would prefer to get the response with a particular content-type. See https://en.wikipedia.org/wiki/List_of_HTTP_header_fields which has a description of what the headers mean.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @pjfanning: also a valid question, but remember that this PR was a thread safety fix intended for backporting to stable so I strove to disturb as little possible while fixing the bug. Since the plugin specified this content-type here before, and we have no bug report related to it doing so, it continues to do that after this PR. Maybe when @cgivre sends in the EVF version of this plugin we can see if Druid is indeed happy for this content-type header to disappear. I'm almost sure you're right and that will be the case. |
||
| .build(); | ||
|
|
||
| public HttpResponse get(String url) throws IOException { | ||
| HttpGet httpget = new HttpGet(url); | ||
| httpget.addHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); | ||
| return httpClient.execute(httpget); | ||
| return httpClient.newCall(get).execute(); | ||
| } | ||
|
|
||
| public HttpResponse post(String url, String body) throws IOException { | ||
| HttpPost httppost = new HttpPost(url); | ||
| httppost.addHeader(CONTENT_TYPE, APPLICATION_JSON); | ||
| HttpEntity entity = new StringEntity(body, DEFAULT_ENCODING); | ||
| httppost.setEntity(entity); | ||
| public Response post(String url, String body) throws IOException { | ||
| RequestBody postBody = RequestBody.create(body.getBytes(StandardCharsets.UTF_8)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be possible to use the RequestBody.create method that takes a String instead of converting to a byte[]?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Ugh I missed that. @cgivre please may we incorporate @pjfanning's suggestion here in the EVF conversion PR. |
||
|
|
||
| Request post = new Request.Builder() | ||
| .url(url) | ||
| .addHeader("Content-Type", "application/json") | ||
| .post(postBody) | ||
| .build(); | ||
|
|
||
| return httpClient.execute(httppost); | ||
| return httpClient.newCall(post).execute(); | ||
| } | ||
| } | ||
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.
Would it be possible to get the
errorContextfrom theDruidBatchReaderso that we get good error messages?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 see that these objects are created in the
DruidPlguinbut maybe we could add a methodaddErrorContextor something like that and call it in the constructor of the Batch Reader.Uh oh!
There was an error while loading. Please reload this page.
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.
@cgivre thanks, I'll check that out. I'd have thought that any error information available in the batch reader would have to also be present here in the HTTP response. Even if that's true, there might be some more response body unpacking to do to expose it.
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.
@cgivre I wasn't aware of the CustomErrorContext, thanks for pointing it out. It looks to me like it's an EVF construct that isn't accessible to pre-EVF plugins like storage-druid. If I've got that right then will we only be able to start it using in this plugin's error messages when its conversion to EVF arrives?
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.
Ahh... you're right. In that case, would you please put some
TODOcomments in the rest clients and then we can update once the EVF conversion is done?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'm good with merging this once that's done. +1