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

Implement DruidPartialDataResponseProcessor #275

Merged
merged 2 commits into from
May 30, 2017

Conversation

QubitPi
Copy link
Contributor

@QubitPi QubitPi commented May 17, 2017

3rd PR implementing #215

@QubitPi QubitPi added the WIP label May 17, 2017
@QubitPi QubitPi force-pushed the implement-PartialDataV2ResponseProcessor branch 3 times, most recently from 7ea000c to 6547e74 Compare May 17, 2017 18:01
Copy link
Collaborator

@cdeszaq cdeszaq left a comment

Choose a reason for hiding this comment

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

Changelog and tests needed.

/**
* Response processor for partial data V2 and cache data V3.
* <p>
* The full response processor also process header information about query response.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This description doesn't tell us very much. It's not clear what "partial data v2" or "cache data v3" are (or at least it won't be clear to us 6 months from now). This doc is also rather vague about what it does or is for, since "process header information" doesn't really indicate what it's doing or why this class is interesting.

* <p>
* The full response processor also process header information about query response.
*/
public interface FullResponseProcessor extends ResponseProcessor {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this called "Full"? The doc should describe what "full" means.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Explanation added

validateJsonResponse(json);

int statusCode = json.get("status-code").asInt();
if (statusCode == 200) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should replace this status code number with one of the StatusCode enums. We do this elsewhere in the codebase I think


int statusCode = json.get("status-code").asInt();
if (statusCode == 200) {
// implementation is blocked by https://github.com/yahoo/fili/pull/262
Copy link
Collaborator

Choose a reason for hiding this comment

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

If this is still WIP because it's not complete (which this comment seems to indicate), we should add the WIP label. Is this PR still in-progress?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cdeszaq Since this PR is blocked by another PR, my thought is that we could review what we have now to save the reviewing effort latter. As a result, we should be able to land this PR quicker.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Since this PR does not really do anything, there's no point in landing it w/o what it's really supposed to do.

Copy link
Contributor Author

@QubitPi QubitPi May 18, 2017

Choose a reason for hiding this comment

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

Yeah. This PR won't merge even after review. I'll wait until the blocking PR is merged and every feature is implemented and reviewed in this PR. I'm giving out the first 50% to review, so people don't have to review large chunk all together latter.

Copy link
Collaborator

Choose a reason for hiding this comment

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

:) I'm all for getting reviews on as much as possible as soon as possible, as long as what's getting reviewed is likely to be stable against the rest of the work.

* Validates JSON response object to make sure it contains all of the following information.
* <ul>
* <li>X-Druid-Response-Context</li>
* <ol>
Copy link
Collaborator

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 list items are nesting the way you intend them to, so I don't think it will render correctly. I think the closing </li> with the header name on it should go after the closing </ol> for this list.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Beautiful!

* <li>uncoveredIntervals</li>
* <li>uncoveredIntervalsOverflowed</li>
* </ol>
* <li>status-code</li>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why does the status code matter?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If status code is 304, do nothing. It status code is 200, we do all logics of partial data V2

Copy link
Collaborator

Choose a reason for hiding this comment

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

Precisely. The javadoc should say that

logAndThrowRunTimeException("Response is missing X-Druid-Response-Context");
}
if (!json.get("X-Druid-Response-Context").has("uncoveredIntervals")) {
logAndThrowRunTimeException("Response is missing \"uncoveredIntervals\" X-Druid-Response-Context");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Use single quotes rather than escaping the double quotes.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, all of these error messages really should go in the ErrorMessages enum (or whatever it's called)

Copy link
Collaborator

Choose a reason for hiding this comment

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

And lastly, does this exist in the query if there are no uncovered intervals?

Copy link
Collaborator

Choose a reason for hiding this comment

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

It will always exist with 98% confidence, I can double check once I get my Http Requester authentication working again.

* @param message The error message passed to the logger and the exception.
*/
private static void logAndThrowRunTimeException(String message) {
LOG.error(message);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this should just be a warning, and shouldn't thrown an exception. If, for some reason, Druid doesn't give us this info, I think this processor should warn, but not assume the result is bad.

@michael-mclawhorn or @garyluoex, do you have any thoughts on this?

Copy link
Collaborator

@garyluoex garyluoex May 18, 2017

Choose a reason for hiding this comment

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

I think my original intent is to return a 500 error response or similar stating that we are not confident that the data druid gave us match the api user's expectation, after talking with tom, I think we agree that fail the query instead of giving bad result is the way to go. If we dont fail the query, it defeat the whole purpose of PartialDataV2 right?

Copy link
Collaborator

@garyluoex garyluoex May 18, 2017

Choose a reason for hiding this comment

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

That said, I don't know if there is a difference between throwing an exception directly here in comparison to preparing an actual error response by callinggetErrorCallback? (Since throwing exception means the query failed anyways and the result will most likely be a error response anyways?) @cdeszaq

Copy link
Collaborator

Choose a reason for hiding this comment

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

In general, if a chunk of code can handle an exceptional case, it should handle it, rather than making someone else handle it. The reason for this is that, if you can handle the exception, you likely have more information about what's wrong than someone else does and can provide a better error response. (ie. "something bad happened" is far less useful than "druid indicated more data was missing than we expected" and including the additional missing intervals)

Copy link
Contributor Author

@QubitPi QubitPi May 18, 2017

Choose a reason for hiding this comment

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

@cdeszaq @garyluoex OK. I guess we agree to keep as it is now?

Copy link
Collaborator

Choose a reason for hiding this comment

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

No, this class needs to handle it's response. It's not useful for it to just throw if it has a problem that should fail the request.

Copy link
Collaborator

Choose a reason for hiding this comment

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

As for the log message, it's OK to leave it error

Copy link
Collaborator

@garyluoex garyluoex May 19, 2017

Choose a reason for hiding this comment

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

@QubitPi Call error call back on the response instead of throw an exception, like this here

Copy link
Contributor Author

Choose a reason for hiding this comment

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


@Override
public void processResponse(JsonNode json, DruidAggregationQuery<?> query, LoggingContext metadata) {
validateJsonResponse(json);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't handle the validator throwing an exception. If this response processor decides to fail the request, it needs to handle doing that failure, rather than letting someone else handle it. Likely it should call either the error or failure callback (depending on which makes more sense).

@michael-mclawhorn
Copy link
Contributor

What is the thinking behind having an empty interface and leaving 'v2' in the concrete class name? Why make an empty interface? Why not just rename the response processor?

@garyluoex garyluoex self-assigned this May 20, 2017
@QubitPi QubitPi force-pushed the implement-PartialDataV2ResponseProcessor branch 3 times, most recently from 313c265 to 6fb4b59 Compare May 22, 2017 19:03
@QubitPi
Copy link
Contributor Author

QubitPi commented May 22, 2017

@cdeszaq @garyluoex @michael-mclawhorn Shall we avoid hardcoded string like

if (!json.get("X-Druid-Response-Context").has("uncoveredIntervalsOverflowed")) {
? I accessed them multiple times during implementation

@QubitPi QubitPi force-pushed the implement-PartialDataV2ResponseProcessor branch from 98ab398 to 991983b Compare May 22, 2017 19:34
@garyluoex
Copy link
Collaborator

@QubitPi Lets just make them a static string on the top of the class for now, I do not see a good place to put then in at this point.

CHANGELOG.md Outdated
- [Implement PartialDataV2ResponseProcessor](https://github.com/yahoo/fili/pull/275)
* Add `FullResponseProcessor` interface that extends `ResponseProcessor`
* Add response status code to JSON response
* Add `PartialDataV2ResponseProcessor` that checks for any missing data that's not being found
Copy link
Collaborator

Choose a reason for hiding this comment

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

Update name to DruidPartialData

@@ -30,15 +30,20 @@ public HeaderNestingJsonBuilderStrategy(Function<Response, JsonNode> baseStrateg

@Override
public JsonNode apply(Response response) {
MappingJsonFactory mappingJsonFactory = new MappingJsonFactory();
ObjectNode objectNode = JsonNodeFactory.instance.objectNode();
objectNode.set("response", baseStrategy.apply(response));
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should some how unify the naming convention of 'response', 'X-Druid-Response-Context', 'status-code' by using an enum. Maybe put the num in responseprocessors folder and name it something like FullResponseContentKeys

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Beautiful! I assume the static string you mentioned above is not needed anymore then

Copy link
Collaborator

Choose a reason for hiding this comment

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

Use DruidJsonResponseContentKeys

* <p>
* This is a "Full" response process in a sense that it extracts and incorporates header information.
*/
public interface FullResponseProcessor extends ResponseProcessor {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Try if we can override processResponse to instead of taking a JsonNode, make it take a ObjectNode in FullResponseProcessor

Copy link
Contributor Author

@QubitPi QubitPi May 23, 2017

Choose a reason for hiding this comment

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

@garyluoex processResponse is not found to use ObjectNode. Do we still need this change?

* missing interval list, we can send back an error response indicating the mismatch in data availability before the
* response is cached.
*/
public class PartialDataV2ResponseProcessor implements FullResponseProcessor {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Change name to DruidParitalData

* from Partial Data V1. If "uncoveredIntervals" contains any interval that is not present in our expected
* missing interval list, we can send back an error response indicating the mismatch in data availability before the
* response is cached.
*/
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we slice this comment down a bit..? It feels like it is a bit too long, and if we don't simplify a little bit, it feels like we can add a phd thesis here... and it doesn't feel right to add too much detail here in the code. As long as the comment can provide a simple explanation and point to the correct place if the user wants more information, I think that is sufficient. But this is my personal preference before we come up with a rule for it, so feel free to leave it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Simplified.

* @param metadata The LoggingContext to use
*/
@Override
public void processResponse(JsonNode json, DruidAggregationQuery<?> query, LoggingContext metadata) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hopefully we can make this take a ObjectNode using the FullResponseProcessor interface as mentioned above.

query.getDataSource().getPhysicalTable().getAvailableIntervals()
);
if (!overlap.isEmpty()) {
logAndGetErrorCallback(ErrorMessageFormat.DATA_AVAILABILITY_MISMATCH.format(overlap), query);
Copy link
Collaborator

Choose a reason for hiding this comment

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

We need a test for this behavior.

*
* @return uncovered intervals in a SimplifiedIntervalList.
*/
private static SimplifiedIntervalList getUncoveredIntervalsFromResponse(JsonNode json) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

It should take a ObjectNode

*/
private void validateJsonResponse(JsonNode json, DruidAggregationQuery<?> query) {
if (!json.has("X-Druid-Response-Context")) {
logAndGetErrorCallback("Response is missing X-Druid-Response-Context", query);
Copy link
Collaborator

Choose a reason for hiding this comment

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

There is one more case that this statement will be executed, the case where an arrayNode is passed in instead of objectNod. The error message should note.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@garyluoex I add a check, you can see it in the next commit

logAndGetErrorCallback("Response is missing X-Druid-Response-Context", query);
}
if (!json.get("X-Druid-Response-Context").has("uncoveredIntervals")) {
logAndGetErrorCallback("Response is missing 'uncoveredIntervals' X-Druid-Response-Context", query);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Make the message clearer by adding 'uncoveredIntervals' from 'X-Druid-Response-Context' header

@QubitPi QubitPi changed the title Implement PartialDataV2ResponseProcessor Implement DruidPartialDataResponseProcessor May 23, 2017
Copy link
Contributor

@michael-mclawhorn michael-mclawhorn left a comment

Choose a reason for hiding this comment

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

There is a lot more testing needed here.
Also, the classes should be renamed around the non numbered naming scheme.

* <p>
* This is a "Full" response process in a sense that it extracts and incorporates header information.
*/
public interface FullResponseProcessor extends ResponseProcessor {
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 thing is creating an explicit contract with the json, let's document the json contract in the class documentation. e.g. give some sample json describing the nesting strategy.

* Compare both SimplifiedIntervalLists above, if allAvailableIntervals has any overlap with
* uncoveredIntervals, invoke error response indicating druid is missing some data that are we expects to
* exists.
* </li>
Copy link
Contributor

Choose a reason for hiding this comment

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

spelling: 'that we are expecting'

* @param query The query with the schema for processing this response
*/
private void validateJsonResponse(JsonNode json, DruidAggregationQuery<?> query) {
if (!json.has("X-Druid-Response-Context")) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Extract as constant

if (json.get("X-Druid-Response-Context").get("uncoveredIntervalsOverflowed").asBoolean()) {
int limit = query.getContext().getUncoveredIntervalsLimit();
logAndGetErrorCallback(ErrorMessageFormat.TOO_MUCH_INTERVAL_MISSING.format(limit, limit), query);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

grammar: either 'TOO_MANY_INTERVALS' or 'TOO_MUCH_TIME'

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, 'TOO_MUCH_INTERVAL_MISSING' really shouldn't need the same number twice.
It can probably be reworded as:
"Query is returning more than the configured limit of ‘%s’ missing intervals. There may be a problem with your data."
I don't think end users should ever be contemplating reconfiguring this parameter.

@@ -50,7 +51,8 @@ class AsyncDruidWebServiceImplWithHeaderNestingSpec extends Specification {
"2016-12-25T00:00:00.000Z/2017-01-03T00:00:00.000Z"
],
"uncoveredIntervalsOverflowed": true
}
},
"status-code": 200
Copy link
Contributor

Choose a reason for hiding this comment

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

it looks to me like this is a test of the HeaderNestingJsonBuilderStrategy, not of the webservice itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah. I agree. I think I should rename it to make it correspond to HeaderNestingJsonBuilderStrategy.java

1 * next.getResponseContext() >> responseContext
1 * next.getFailureCallback(druidAggregationQuery) >> failureCallback
1 * next.getErrorCallback(druidAggregationQuery) >> httpErrorCallback
}
Copy link
Contributor

Choose a reason for hiding this comment

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

What is this even testing? I don't see the point of this.

"status-code": 200
}
''' | ["2016-11-22T00:00:00.000Z/2016-12-18T00:00:00.000Z", "2016-12-25T00:00:00.000Z/2017-01-03T00:00:00.000Z"]
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a good test. However if we're only doing one value, there's not much point in doing a data table.

}
''' | ["2016-11-22T00:00:00.000Z/2016-12-18T00:00:00.000Z", "2016-12-25T00:00:00.000Z/2017-01-03T00:00:00.000Z"]
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I assume there are more tests coming here.
Specifically:
processResponse -> overflow message
processResponse -> success message
processResponse -> data availability mismatch
validateJsonResponse error paths
checkOverflow success and failure
getUncoveredIntervalFromResponse (optional, but might make for good low level testing)

Copy link
Collaborator

@garyluoex garyluoex left a comment

Choose a reason for hiding this comment

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

Minor stuff

@@ -176,19 +152,29 @@ public void processResponse(JsonNode json, DruidAggregationQuery<?> query, Loggi
* @param query The query with the schema for processing this response
*/
private void validateJsonResponse(JsonNode json, DruidAggregationQuery<?> query) {
if (!json.has("X-Druid-Response-Context")) {
if (json instanceof ArrayNode) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

@@ -176,19 +152,29 @@ public void processResponse(JsonNode json, DruidAggregationQuery<?> query, Loggi
* @param query The query with the schema for processing this response
*/
private void validateJsonResponse(JsonNode json, DruidAggregationQuery<?> query) {
if (!json.has("X-Druid-Response-Context")) {
if (json instanceof ArrayNode) {
logAndGetErrorCallback("Response is missing X-Druid-Response-Context and status code", query);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we should make the message more explicit such that Response refers to json being passed to ResponseHandler so that people don't mistake it as being Response from druid. Apply to all.

logAndGetErrorCallback("Response is missing X-Druid-Response-Context", query);
}
if (!json.get("X-Druid-Response-Context").has("uncoveredIntervals")) {
logAndGetErrorCallback("Response is missing 'uncoveredIntervals' X-Druid-Response-Context", query);
if (!json.get(FullResponseContentKeys.DRUID_RESPONSE_CONTEXT.getName())
Copy link
Collaborator

Choose a reason for hiding this comment

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

It is repeated four or more times, we should take it out as its own variable

/**
* Enumerates the list of keys expected to be found in the FullResponseProcessor.
*/
public enum FullResponseContentKeys {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Lets change it to DruidJsonResponseContentKeys?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@garyluoex Shall we change FullResponseProcessor to DruidJsonResponseProcessor?

@@ -39,4 +47,21 @@
*
*/
public interface FullResponseProcessor extends ResponseProcessor {
@Override
default void processResponse(JsonNode json, DruidAggregationQuery<?> query, LoggingContext metadata) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do we have a default?

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 only way to override is to implement processResponse and default is needed to implement this method

Copy link
Contributor Author

Choose a reason for hiding this comment

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

An alternative is to tranform JSON node to Object node in DruidPartialDataResponseProcessor

Copy link
Collaborator

Choose a reason for hiding this comment

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

Are you sure? I think just overriding the method as an interface without default should be fine. Let me know the compilation error you get if possible.

Copy link
Collaborator

Choose a reason for hiding this comment

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

never mind, revert it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok

@@ -30,15 +30,20 @@ public HeaderNestingJsonBuilderStrategy(Function<Response, JsonNode> baseStrateg

@Override
public JsonNode apply(Response response) {
MappingJsonFactory mappingJsonFactory = new MappingJsonFactory();
ObjectNode objectNode = JsonNodeFactory.instance.objectNode();
objectNode.set("response", baseStrategy.apply(response));
try {
objectNode.set(
"X-Druid-Response-Context",
Copy link
Collaborator

Choose a reason for hiding this comment

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

DruidJsonResponseContentKeys

.createParser(response.getHeader("X-Druid-Response-Context"))
.readValueAsTree()
);
objectNode.set(
"status-code",
Copy link
Collaborator

Choose a reason for hiding this comment

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

DruidJsonResponseContentKeys

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Beautiful!

@QubitPi QubitPi force-pushed the implement-PartialDataV2ResponseProcessor branch from 4a130e9 to 3b07f2a Compare May 26, 2017 15:45
Copy link
Collaborator

@garyluoex garyluoex left a comment

Choose a reason for hiding this comment

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

Minor comment

UNCOVERED_INTERVALS("uncoveredIntervals"),
UNCOVERED_INTERVALS_OVERFLOWED("uncoveredIntervalsOverflowed"),
STATUS_CODE("status-code"),
RESPONSE("response");
Copy link
Collaborator

Choose a reason for hiding this comment

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

semi colon to next line

)
dataSource.getPhysicalTable() >> constrainedTable
druidAggregationQuery.getDataSource() >> dataSource

Copy link
Collaborator

Choose a reason for hiding this comment

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

extra new line

JsonNode json = MAPPER.readTree(
jsonInString
.replace(" ", "")
.replace("\n", "")
Copy link
Collaborator

Choose a reason for hiding this comment

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

why are these two replace needed?

Copy link
Contributor Author

@QubitPi QubitPi May 26, 2017

Choose a reason for hiding this comment

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

Good catch! They are not needed after a refactor but I forget to delete them

}
}

next.processResponse(json, query, metadata);
Copy link
Collaborator

Choose a reason for hiding this comment

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

If it is 304 and the next response processor is not fullResponseProcessor, we should throw error saying, received 304, but no etag cache response processor is available to process 304 response

"2016-11-22T00:00:00.000Z/2016-12-18T00:00:00.000Z",
"2016-12-25T00:00:00.000Z/2017-01-03T00:00:00.000Z"
],
"uncoveredIntervalsOverflowed": true
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are all over flow set to true????

Copy link
Collaborator

@garyluoex garyluoex May 26, 2017

Choose a reason for hiding this comment

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

And.... this test only have a given: ????

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK. Setting it to false makes more sense

json.get(DruidJsonResponseContentKeys.DRUID_RESPONSE_CONTEXT.getName())
.get(DruidJsonResponseContentKeys.UNCOVERED_INTERVALS.getName())
) {
intervals.add(new Interval(jsonNode.asText()));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we add a test showing what this jsonNode is? Or let me know if you know the answer, is this jsonNode a arraynode or objectnode and what is the content?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

According to Javadoc of this method

X-Druid-Response-Context: {
    "uncoveredIntervals": [
        "2016-11-22T00:00:00.000Z/2016-12-18T00:00:00.000Z","2016-12-25T00:00:00.000Z/2017-
        01-03T00:00:00.000Z","2017-01-31T00:00:00.000Z/2017-02-01T00:00:00.000Z","2017-02-
        08T00:00:00.000Z/2017-02-09T00:00:00.000Z","2017-02-10T00:00:00.000Z/2017-02-
        13T00:00:00.000Z","2017-02-16T00:00:00.000Z/2017-02-20T00:00:00.000Z","2017-02-
        22T00:00:00.000Z/2017-02-25T00:00:00.000Z","2017-02-26T00:00:00.000Z/2017-03-
        01T00:00:00.000Z","2017-03-04T00:00:00.000Z/2017-03-05T00:00:00.000Z","2017-03-
        08T00:00:00.000Z/2017-03-09T00:00:00.000Z"
    ],
    "uncoveredIntervalsOverflowed": true
}

Each is a ObjectNode containing a String like "2016-11-22T00:00:00.000Z/2016-12-18T00:00:00.000Z"

Copy link
Collaborator

Choose a reason for hiding this comment

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

If it is a ObjectNode, it is some kind of key value mapping right? So what is the key for each individual string like "2016-11-22T00:00:00.000Z/2016-12-18T00:00:00.000Z"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What I mean by ObjectNode is that it is a type of JsonNode that can be serialized to text in this way

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you show me some documentation or a test that confirms this behavior?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I modified tests to make sure this method works as expected

Copy link
Contributor

@michael-mclawhorn michael-mclawhorn May 26, 2017

Choose a reason for hiding this comment

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

Isn't this a text node inside a list?

Re: @michael-mclawhorn Yes, which is why I call .asText(). Any specific problem?

@@ -131,9 +132,14 @@ public void processResponse(JsonNode json, DruidAggregationQuery<?> query, Loggi
} else {
next.processResponse(json.get(DruidJsonResponseContentKeys.RESPONSE.getName()), query, metadata);
}
} else if (statusCode == Status.NOT_MODIFIED.getStatusCode() && next instanceof FullResponseProcessor) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are you sure this if statement is 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.

Maybe adding a pair of parenthesis around latter?

Copy link
Collaborator

Choose a reason for hiding this comment

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

if 304, and the next response Processor is FullResponseProcessor (which can be etagCacheResponseProcessor), we throw an error?

druidPartialDataResponseProcessor.next == next;
}

def "getOverlap returns intersection between Druid intervals and Fili intervals in case of #caseDescription"() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This test only have a given: and where: which does not test anything right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm...somehow a refactor removes it. Anyway it's back

@@ -50,7 +51,8 @@ class AsyncDruidWebServiceImplWithHeaderNestingSpec extends Specification {
"2016-12-25T00:00:00.000Z/2017-01-03T00:00:00.000Z"
],
"uncoveredIntervalsOverflowed": true
}
},
"status-code": 200
}
'''.replace(" ", "").replace("\n", "")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure if this is needed.

@@ -28,6 +28,7 @@ class AsyncDruidWebServiceImplWithHeaderNestingSpec extends Specification {
"uncoveredIntervalsOverflowed": true
}
'''.replace(" ", "").replace("\n", "")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure if this is needed.

@QubitPi QubitPi force-pushed the implement-PartialDataV2ResponseProcessor branch from 6a9c85d to 6919466 Compare May 26, 2017 18:23
@QubitPi QubitPi force-pushed the implement-PartialDataV2ResponseProcessor branch from 6919466 to 5131965 Compare May 26, 2017 20:03
Copy link
Contributor

@michael-mclawhorn michael-mclawhorn left a comment

Choose a reason for hiding this comment

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

Readability of tests should be improved, otherwise this is pretty good. I'm going to 👍 this, but I'd like you to make the changes I've described.

json.get(DruidJsonResponseContentKeys.DRUID_RESPONSE_CONTEXT.getName())
.get(DruidJsonResponseContentKeys.UNCOVERED_INTERVALS.getName())
) {
intervals.add(new Interval(jsonNode.asText()));
Copy link
Contributor

@michael-mclawhorn michael-mclawhorn May 26, 2017

Choose a reason for hiding this comment

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

Isn't this a text node inside a list?

Re: @michael-mclawhorn Yes, which is why I call .asText(). Any specific problem?

private void validateJsonResponse(JsonNode json, DruidAggregationQuery<?> query) {
if (json.getNodeType() == JsonNodeType.ARRAY) {
logAndGetErrorCallback("JSON response is missing X-Druid-Response-Context and status code", query);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

All of these error strings should be moved into constants and referenced by the constants in the tests so that they'll stay in sync.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Beautiful!

}
if (!json.has(DruidJsonResponseContentKeys.STATUS_CODE.getName())) {
logAndGetErrorCallback("JSON response is missing response status code", query);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

All of these error strings should be moved into constants and referenced by the constants in the tests so that they'll stay in sync.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Beautiful!

"Query is returning more than the configured limit of '10' missing intervals. " +
"There may be a problem with your data.")
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Use the constants for these errors rather than copying them into the tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Beautiful!

],
"uncoveredIntervalsOverflowed": false
},
"status-code": 200
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like your Json instring is the same across all the test cases. If so, lift it up out of the where clause and put it into the test.

@QubitPi QubitPi force-pushed the implement-PartialDataV2ResponseProcessor branch from 9b34856 to 3a5e0e0 Compare May 27, 2017 06:50
@QubitPi
Copy link
Contributor Author

QubitPi commented May 30, 2017

@cdeszaq Since merging is blocked, could you take a quick look at it and approve it? Thanks!

@QubitPi QubitPi mentioned this pull request May 30, 2017
@garyluoex garyluoex dismissed cdeszaq’s stale review May 30, 2017 18:51

Unblock merging.

@garyluoex
Copy link
Collaborator

@QubitPi @cdeszaq I dismissed the comment so that merging is not blocked since it's got 2 reviews already.

@QubitPi
Copy link
Contributor Author

QubitPi commented May 30, 2017

@garyluoex Thanks Gary!

@QubitPi QubitPi merged commit f9db95a into master May 30, 2017
@garyluoex garyluoex deleted the implement-PartialDataV2ResponseProcessor branch May 30, 2017 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants