Improve 404 on missing scroll id

This relates to #6040, the fix is twofold, first, not handling missing context specifically in the search code, but behave the same as we do in non scroll search, where if all the shards failed, raise an exception. The second is to apply this logic in both scroll cases.
This commit is contained in:
Shay Banon 2014-05-06 14:59:53 +02:00
parent 7b0efcbd96
commit 44fd962a9f
4 changed files with 53 additions and 25 deletions

View File

@ -181,9 +181,13 @@ public class TransportSearchScrollQueryAndFetchAction extends AbstractComponent
addShardFailure(shardIndex, new ShardSearchFailure(t)); addShardFailure(shardIndex, new ShardSearchFailure(t));
successfulOps.decrementAndGet(); successfulOps.decrementAndGet();
if (counter.decrementAndGet() == 0) { if (counter.decrementAndGet() == 0) {
if (successfulOps.get() == 0) {
listener.onFailure(new SearchPhaseExecutionException("query_fetch", "all shards failed", buildShardFailures()));
} else {
finishHim(); finishHim();
} }
} }
}
private void finishHim() { private void finishHim() {
try { try {

View File

@ -174,13 +174,8 @@ public class TransportSearchScrollQueryThenFetchAction extends AbstractComponent
@Override @Override
public void onFailure(Throwable t) { public void onFailure(Throwable t) {
Throwable cause = ExceptionsHelper.unwrapCause(t);
if (cause instanceof SearchContextMissingException) {
listener.onFailure(t);
} else {
onQueryPhaseFailure(shardIndex, counter, searchId, t); onQueryPhaseFailure(shardIndex, counter, searchId, t);
} }
}
}); });
} }
@ -191,6 +186,9 @@ public class TransportSearchScrollQueryThenFetchAction extends AbstractComponent
addShardFailure(shardIndex, new ShardSearchFailure(t)); addShardFailure(shardIndex, new ShardSearchFailure(t));
successfulOps.decrementAndGet(); successfulOps.decrementAndGet();
if (counter.decrementAndGet() == 0) { if (counter.decrementAndGet() == 0) {
if (successfulOps.get() == 0) {
listener.onFailure(new SearchPhaseExecutionException("query", "all shards failed", buildShardFailures()));
} else {
try { try {
executeFetchPhase(); executeFetchPhase();
} catch (Throwable e) { } catch (Throwable e) {
@ -198,6 +196,7 @@ public class TransportSearchScrollQueryThenFetchAction extends AbstractComponent
} }
} }
} }
}
private void executeFetchPhase() throws Exception { private void executeFetchPhase() throws Exception {
if (useSlowScroll) { if (useSlowScroll) {

View File

@ -291,8 +291,8 @@ public class SearchScrollTests extends ElasticsearchIntegrationTest {
.execute().actionGet(); .execute().actionGet();
assertThat(clearResponse.isSucceeded(), equalTo(true)); assertThat(clearResponse.isSucceeded(), equalTo(true));
assertThrows(client().prepareSearchScroll(searchResponse1.getScrollId()).setScroll(TimeValue.timeValueMinutes(2)), SearchContextMissingException.class); assertThrows(client().prepareSearchScroll(searchResponse1.getScrollId()).setScroll(TimeValue.timeValueMinutes(2)), RestStatus.NOT_FOUND);
assertThrows(client().prepareSearchScroll(searchResponse2.getScrollId()).setScroll(TimeValue.timeValueMinutes(2)), SearchContextMissingException.class); assertThrows(client().prepareSearchScroll(searchResponse2.getScrollId()).setScroll(TimeValue.timeValueMinutes(2)), RestStatus.NOT_FOUND);
} }
@Test @Test
@ -397,8 +397,8 @@ public class SearchScrollTests extends ElasticsearchIntegrationTest {
.execute().actionGet(); .execute().actionGet();
assertThat(clearResponse.isSucceeded(), equalTo(true)); assertThat(clearResponse.isSucceeded(), equalTo(true));
assertThrows(cluster().transportClient().prepareSearchScroll(searchResponse1.getScrollId()).setScroll(TimeValue.timeValueMinutes(2)), SearchContextMissingException.class); assertThrows(cluster().transportClient().prepareSearchScroll(searchResponse1.getScrollId()).setScroll(TimeValue.timeValueMinutes(2)), RestStatus.NOT_FOUND);
assertThrows(cluster().transportClient().prepareSearchScroll(searchResponse2.getScrollId()).setScroll(TimeValue.timeValueMinutes(2)), SearchContextMissingException.class); assertThrows(cluster().transportClient().prepareSearchScroll(searchResponse2.getScrollId()).setScroll(TimeValue.timeValueMinutes(2)), RestStatus.NOT_FOUND);
} }
@Test @Test
@ -436,17 +436,12 @@ public class SearchScrollTests extends ElasticsearchIntegrationTest {
client().prepareIndex("index", "type", "1").setSource("field", "value").execute().get(); client().prepareIndex("index", "type", "1").setSource("field", "value").execute().get();
refresh(); refresh();
try {
SearchResponse searchResponse = client().prepareSearch("index").setSize(1).setScroll("1m").get(); SearchResponse searchResponse = client().prepareSearch("index").setSize(1).setScroll("1m").get();
assertThat(searchResponse.getScrollId(), is(notNullValue())); assertThat(searchResponse.getScrollId(), is(notNullValue()));
ClearScrollResponse clearScrollResponse = client().prepareClearScroll().addScrollId(searchResponse.getScrollId()).get(); ClearScrollResponse clearScrollResponse = client().prepareClearScroll().addScrollId(searchResponse.getScrollId()).get();
assertThat(clearScrollResponse.isSucceeded(), is(true)); assertThat(clearScrollResponse.isSucceeded(), is(true));
cluster().transportClient().prepareSearchScroll(searchResponse.getScrollId()).get(); assertThrows(cluster().transportClient().prepareSearchScroll(searchResponse.getScrollId()), RestStatus.NOT_FOUND);
fail("Expected exception to happen due to non-existing scroll id");
} catch (ElasticsearchException e) {
assertThat(e.status(), is(RestStatus.NOT_FOUND));
}
} }
} }

View File

@ -23,6 +23,7 @@ import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchIllegalStateException; import org.elasticsearch.ElasticsearchIllegalStateException;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionRequest;
@ -413,6 +414,35 @@ public class ElasticsearchAssertions {
} }
} }
public static <E extends Throwable> void assertThrows(ActionRequestBuilder<?, ?, ?> builder, RestStatus status) {
assertThrows(builder.execute(), status);
}
public static <E extends Throwable> void assertThrows(ActionRequestBuilder<?, ?, ?> builder, RestStatus status, String extraInfo) {
assertThrows(builder.execute(), status, extraInfo);
}
public static <E extends Throwable> void assertThrows(ActionFuture future, RestStatus status) {
assertThrows(future, status, null);
}
public static void assertThrows(ActionFuture future, RestStatus status, String extraInfo) {
boolean fail = false;
extraInfo = extraInfo == null || extraInfo.isEmpty() ? "" : extraInfo + ": ";
extraInfo += "expected a " + status + " status exception to be thrown";
try {
future.actionGet();
fail = true;
} catch (Throwable e) {
assertThat(extraInfo, ExceptionsHelper.status(e), equalTo(status));
}
// has to be outside catch clause to get a proper message
if (fail) {
throw new AssertionError(extraInfo);
}
}
private static BytesReference serialize(Version version, Streamable streamable) throws IOException { private static BytesReference serialize(Version version, Streamable streamable) throws IOException {
BytesStreamOutput output = new BytesStreamOutput(); BytesStreamOutput output = new BytesStreamOutput();
output.setVersion(version); output.setVersion(version);