diff --git a/core/src/main/java/org/elasticsearch/action/search/SearchPhaseExecutionException.java b/core/src/main/java/org/elasticsearch/action/search/SearchPhaseExecutionException.java index 68bcf6d269c..40e8b0730ff 100644 --- a/core/src/main/java/org/elasticsearch/action/search/SearchPhaseExecutionException.java +++ b/core/src/main/java/org/elasticsearch/action/search/SearchPhaseExecutionException.java @@ -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 diff --git a/core/src/main/java/org/elasticsearch/action/search/type/TransportSearchScrollQueryAndFetchAction.java b/core/src/main/java/org/elasticsearch/action/search/type/TransportSearchScrollQueryAndFetchAction.java index cd4238ccdea..2a953f9b732 100644 --- a/core/src/main/java/org/elasticsearch/action/search/type/TransportSearchScrollQueryAndFetchAction.java +++ b/core/src/main/java/org/elasticsearch/action/search/type/TransportSearchScrollQueryAndFetchAction.java @@ -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(); } diff --git a/core/src/main/java/org/elasticsearch/action/search/type/TransportSearchScrollQueryThenFetchAction.java b/core/src/main/java/org/elasticsearch/action/search/type/TransportSearchScrollQueryThenFetchAction.java index 85b06ea7860..8f2df714319 100644 --- a/core/src/main/java/org/elasticsearch/action/search/type/TransportSearchScrollQueryThenFetchAction.java +++ b/core/src/main/java/org/elasticsearch/action/search/type/TransportSearchScrollQueryThenFetchAction.java @@ -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)); } } } diff --git a/core/src/main/java/org/elasticsearch/action/search/type/TransportSearchTypeAction.java b/core/src/main/java/org/elasticsearch/action/search/type/TransportSearchTypeAction.java index fa5776387dd..31cd3986d2f 100644 --- a/core/src/main/java/org/elasticsearch/action/search/type/TransportSearchTypeAction.java +++ b/core/src/main/java/org/elasticsearch/action/search/type/TransportSearchTypeAction.java @@ -220,17 +220,19 @@ public abstract class TransportSearchTypeAction extends TransportAction