Merge pull request #14432 from s1monw/add_shard_failure_as_suppressed

Deduplicate cause if already contained in shard failures
This commit is contained in:
Simon Willnauer 2015-11-03 12:06:23 +01:00
commit d76ae6718e
6 changed files with 46 additions and 17 deletions

View File

@ -38,13 +38,11 @@ public class SearchPhaseExecutionException extends ElasticsearchException {
private final ShardSearchFailure[] shardFailures;
public SearchPhaseExecutionException(String phaseName, String msg, ShardSearchFailure[] shardFailures) {
super(msg);
this.phaseName = phaseName;
this.shardFailures = shardFailures;
this(phaseName, msg, null, shardFailures);
}
public SearchPhaseExecutionException(String phaseName, String msg, Throwable cause, ShardSearchFailure[] shardFailures) {
super(msg, cause);
super(msg, deduplicateCause(cause, shardFailures));
this.phaseName = phaseName;
this.shardFailures = shardFailures;
}
@ -63,12 +61,26 @@ public class SearchPhaseExecutionException extends ElasticsearchException {
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeOptionalString(phaseName);
out.writeVInt(shardFailures == null ? 0 : shardFailures.length);
if (shardFailures != null) {
out.writeVInt(shardFailures.length);
for (ShardSearchFailure failure : shardFailures) {
failure.writeTo(out);
}
}
private static final Throwable deduplicateCause(Throwable cause, ShardSearchFailure[] shardFailures) {
if (shardFailures == null) {
throw new IllegalArgumentException("shardSearchFailures must not be null");
}
// if the cause of this exception is also the cause of one of the shard failures we don't add it
// to prevent duplication in stack traces rendered to the REST layer
if (cause != null) {
for (ShardSearchFailure failure : shardFailures) {
failure.writeTo(out);
if (failure.getCause() == cause) {
return null;
}
}
}
return cause;
}
@Override

View File

@ -114,7 +114,7 @@ public class TransportSearchScrollQueryAndFetchAction extends AbstractComponent
public void start() {
if (scrollId.getContext().length == 0) {
listener.onFailure(new SearchPhaseExecutionException("query", "no nodes to search on", null));
listener.onFailure(new SearchPhaseExecutionException("query", "no nodes to search on", ShardSearchFailure.EMPTY_ARRAY));
return;
}
@ -175,7 +175,7 @@ public class TransportSearchScrollQueryAndFetchAction extends AbstractComponent
successfulOps.decrementAndGet();
if (counter.decrementAndGet() == 0) {
if (successfulOps.get() == 0) {
listener.onFailure(new SearchPhaseExecutionException("query_fetch", "all shards failed", buildShardFailures()));
listener.onFailure(new SearchPhaseExecutionException("query_fetch", "all shards failed", t, buildShardFailures()));
} else {
finishHim();
}

View File

@ -123,7 +123,7 @@ public class TransportSearchScrollQueryThenFetchAction extends AbstractComponent
public void start() {
if (scrollId.getContext().length == 0) {
listener.onFailure(new SearchPhaseExecutionException("query", "no nodes to search on", null));
listener.onFailure(new SearchPhaseExecutionException("query", "no nodes to search on", ShardSearchFailure.EMPTY_ARRAY));
return;
}
final AtomicInteger counter = new AtomicInteger(scrollId.getContext().length);
@ -143,7 +143,7 @@ public class TransportSearchScrollQueryThenFetchAction extends AbstractComponent
try {
executeFetchPhase();
} catch (Throwable e) {
listener.onFailure(new SearchPhaseExecutionException("query", "Fetch failed", e, null));
listener.onFailure(new SearchPhaseExecutionException("query", "Fetch failed", e, ShardSearchFailure.EMPTY_ARRAY));
return;
}
}
@ -181,12 +181,12 @@ public class TransportSearchScrollQueryThenFetchAction extends AbstractComponent
successfulOps.decrementAndGet();
if (counter.decrementAndGet() == 0) {
if (successfulOps.get() == 0) {
listener.onFailure(new SearchPhaseExecutionException("query", "all shards failed", buildShardFailures()));
listener.onFailure(new SearchPhaseExecutionException("query", "all shards failed", t, buildShardFailures()));
} else {
try {
executeFetchPhase();
} catch (Throwable e) {
listener.onFailure(new SearchPhaseExecutionException("query", "Fetch failed", e, null));
listener.onFailure(new SearchPhaseExecutionException("query", "Fetch failed", e, ShardSearchFailure.EMPTY_ARRAY));
}
}
}

View File

@ -220,17 +220,19 @@ public abstract class TransportSearchTypeAction extends TransportAction<SearchRe
logger.trace("{}: Failed to execute [{}]", t, shard, request);
}
}
final ShardSearchFailure[] shardSearchFailures = buildShardFailures();
if (successfulOps.get() == 0) {
if (logger.isDebugEnabled()) {
logger.debug("All shards failed for phase: [{}]", t, firstPhaseName());
}
// no successful ops, raise an exception
raiseEarlyFailure(new SearchPhaseExecutionException(firstPhaseName(), "all shards failed", buildShardFailures()));
raiseEarlyFailure(new SearchPhaseExecutionException(firstPhaseName(), "all shards failed", t, shardSearchFailures));
} else {
try {
innerMoveToSecondPhase();
} catch (Throwable e) {
raiseEarlyFailure(new ReduceSearchPhaseException(firstPhaseName(), "", e, buildShardFailures()));
raiseEarlyFailure(new ReduceSearchPhaseException(firstPhaseName(), "", e, shardSearchFailures));
}
}
} else {

View File

@ -140,7 +140,7 @@ public class ESExceptionTests extends ESTestCase {
new SearchShardTarget("node_1", "foo", 1));
ShardSearchFailure failure1 = new ShardSearchFailure(new ParsingException(1, 2, "foobar", null),
new SearchShardTarget("node_1", "foo", 2));
SearchPhaseExecutionException ex = new SearchPhaseExecutionException("search", "all shards failed", new ShardSearchFailure[]{failure, failure1});
SearchPhaseExecutionException ex = new SearchPhaseExecutionException("search", "all shards failed", randomBoolean() ? failure1.getCause() : failure.getCause(), new ShardSearchFailure[]{failure, failure1});
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
ex.toXContent(builder, PARAMS);
@ -163,6 +163,21 @@ public class ESExceptionTests extends ESTestCase {
String expected = "{\"type\":\"search_phase_execution_exception\",\"reason\":\"all shards failed\",\"phase\":\"search\",\"grouped\":true,\"failed_shards\":[{\"shard\":1,\"index\":\"foo\",\"node\":\"node_1\",\"reason\":{\"type\":\"parsing_exception\",\"reason\":\"foobar\",\"line\":1,\"col\":2}},{\"shard\":1,\"index\":\"foo1\",\"node\":\"node_1\",\"reason\":{\"type\":\"query_shard_exception\",\"reason\":\"foobar\",\"index\":\"foo1\"}}]}";
assertEquals(expected, builder.string());
}
{
ShardSearchFailure failure = new ShardSearchFailure(new ParsingException(1, 2, "foobar", null),
new SearchShardTarget("node_1", "foo", 1));
ShardSearchFailure failure1 = new ShardSearchFailure(new ParsingException(1, 2, "foobar", null),
new SearchShardTarget("node_1", "foo", 2));
NullPointerException nullPointerException = new NullPointerException();
SearchPhaseExecutionException ex = new SearchPhaseExecutionException("search", "all shards failed", nullPointerException, new ShardSearchFailure[]{failure, failure1});
assertEquals(nullPointerException, ex.getCause());
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
ex.toXContent(builder, PARAMS);
builder.endObject();
String expected = "{\"type\":\"search_phase_execution_exception\",\"reason\":\"all shards failed\",\"phase\":\"search\",\"grouped\":true,\"failed_shards\":[{\"shard\":1,\"index\":\"foo\",\"node\":\"node_1\",\"reason\":{\"type\":\"parsing_exception\",\"reason\":\"foobar\",\"line\":1,\"col\":2}}],\"caused_by\":{\"type\":\"null_pointer_exception\",\"reason\":null}}";
assertEquals(expected, builder.string());
}
}
public void testGetRootCause() {

View File

@ -307,7 +307,7 @@ public class TemplateQueryIT extends ESIntegTestCase {
templateParams)).get();
fail("Expected SearchPhaseExecutionException");
} catch (SearchPhaseExecutionException e) {
assertThat(e.getCause().getMessage(), containsString("Illegal index script format"));
assertThat(e.toString(), containsString("Illegal index script format"));
}
}