Skip to content

Commit 461ce98

Browse files
committed
Merge pull request #14107 from s1monw/release_searcher_on_wrapper_failure
Ensure searcher is release if wrapping fails
2 parents da12290 + c133bec commit 461ce98

File tree

2 files changed

+88
-15
lines changed

2 files changed

+88
-15
lines changed

core/src/main/java/org/elasticsearch/index/shard/IndexShard.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
import org.elasticsearch.common.Nullable;
4242
import org.elasticsearch.common.inject.Inject;
4343
import org.elasticsearch.common.io.stream.BytesStreamOutput;
44+
import org.elasticsearch.common.lease.Releasable;
45+
import org.elasticsearch.common.lease.Releasables;
4446
import org.elasticsearch.common.logging.ESLogger;
4547
import org.elasticsearch.common.logging.support.LoggerMessageFormat;
4648
import org.elasticsearch.common.lucene.Lucene;
@@ -717,11 +719,20 @@ public void failShard(String reason, @Nullable Throwable e) {
717719

718720
public Engine.Searcher acquireSearcher(String source) {
719721
readAllowed();
720-
Engine engine = getEngine();
722+
final Engine engine = getEngine();
723+
final Engine.Searcher searcher = engine.acquireSearcher(source);
724+
boolean success = false;
721725
try {
722-
return searcherWrapper == null ? engine.acquireSearcher(source) : searcherWrapper.wrap(engineConfig, engine.acquireSearcher(source));
726+
final Engine.Searcher wrappedSearcher = searcherWrapper == null ? searcher : searcherWrapper.wrap(engineConfig, searcher);
727+
assert wrappedSearcher != null;
728+
success = true;
729+
return wrappedSearcher;
723730
} catch (IOException ex) {
724731
throw new ElasticsearchException("failed to wrap searcher", ex);
732+
} finally {
733+
if (success == false) {
734+
Releasables.close(success, searcher);
735+
}
725736
}
726737
}
727738

core/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
import java.util.concurrent.CyclicBarrier;
9696
import java.util.concurrent.ExecutionException;
9797
import java.util.concurrent.atomic.AtomicBoolean;
98+
import java.util.concurrent.atomic.AtomicInteger;
9899

99100
import static org.elasticsearch.cluster.metadata.IndexMetaData.*;
100101
import static org.elasticsearch.common.settings.Settings.settingsBuilder;
@@ -911,10 +912,6 @@ public void testSearcherWrapperIsUsed() throws IOException {
911912
search = searcher.searcher().search(new TermQuery(new Term("foobar", "bar")), 10);
912913
assertEquals(search.totalHits, 1);
913914
}
914-
915-
ShardRouting routing = new ShardRouting(shard.routingEntry());
916-
shard.close("simon says", true);
917-
IndexServicesProvider indexServices = indexService.getIndexServices();
918915
IndexSearcherWrapper wrapper = new IndexSearcherWrapper() {
919916
@Override
920917
public DirectoryReader wrap(DirectoryReader reader) throws IOException {
@@ -927,16 +924,8 @@ public IndexSearcher wrap(EngineConfig engineConfig, IndexSearcher searcher) thr
927924
}
928925
};
929926

930-
IndexServicesProvider newProvider = new IndexServicesProvider(indexServices.getIndicesLifecycle(), indexServices.getThreadPool(), indexServices.getMapperService(), indexServices.getQueryParserService(), indexServices.getIndexCache(), indexServices.getIndicesQueryCache(), indexServices.getCodecService(), indexServices.getTermVectorsService(), indexServices.getIndexFieldDataService(), indexServices.getWarmer(), indexServices.getSimilarityService(), indexServices.getFactory(), indexServices.getBigArrays(), wrapper, indexServices.getIndexingMemoryController());
931-
IndexShard newShard = new IndexShard(shard.shardId(), shard.indexSettings, shard.shardPath(), shard.store(), newProvider);
927+
IndexShard newShard = reinitWithWrapper(indexService, shard, wrapper);
932928
try {
933-
ShardRoutingHelper.reinit(routing);
934-
newShard.updateRoutingEntry(routing, false);
935-
DiscoveryNode localNode = new DiscoveryNode("foo", DummyTransportAddress.INSTANCE, Version.CURRENT);
936-
assertTrue(newShard.recoverFromStore(routing, localNode));
937-
routing = new ShardRouting(routing);
938-
ShardRoutingHelper.moveToStarted(routing);
939-
newShard.updateRoutingEntry(routing, true);
940929
try (Engine.Searcher searcher = newShard.acquireSearcher("test")) {
941930
TopDocs search = searcher.searcher().search(new TermQuery(new Term("foo", "bar")), 10);
942931
assertEquals(search.totalHits, 0);
@@ -948,7 +937,34 @@ public IndexSearcher wrap(EngineConfig engineConfig, IndexSearcher searcher) thr
948937
assertNotNull(getResult.searcher()); // make sure get uses the wrapped reader
949938
assertTrue(getResult.searcher().reader() instanceof FieldMaskingReader);
950939
getResult.release();
940+
} finally {
941+
newShard.close("just do it", randomBoolean());
942+
}
943+
}
944+
945+
public void testSearcherWrapperWorksWithGlobaOrdinals() throws IOException {
946+
createIndex("test");
947+
ensureGreen();
948+
IndicesService indicesService = getInstanceFromNode(IndicesService.class);
949+
IndexService indexService = indicesService.indexService("test");
950+
IndexShard shard = indexService.getShardOrNull(0);
951+
client().prepareIndex("test", "test", "0").setSource("{\"foo\" : \"bar\"}").setRefresh(true).get();
952+
client().prepareIndex("test", "test", "1").setSource("{\"foobar\" : \"bar\"}").setRefresh(true).get();
951953

954+
IndexSearcherWrapper wrapper = new IndexSearcherWrapper() {
955+
@Override
956+
public DirectoryReader wrap(DirectoryReader reader) throws IOException {
957+
return new FieldMaskingReader("foo", reader);
958+
}
959+
960+
@Override
961+
public IndexSearcher wrap(EngineConfig engineConfig, IndexSearcher searcher) throws EngineException {
962+
return searcher;
963+
}
964+
};
965+
966+
IndexShard newShard = reinitWithWrapper(indexService, shard, wrapper);
967+
try {
952968
// test global ordinals are evicted
953969
MappedFieldType foo = newShard.mapperService().indexName("foo");
954970
IndexFieldData.Global ifd = shard.indexFieldDataService().getForField(foo);
@@ -970,7 +986,53 @@ public IndexSearcher wrap(EngineConfig engineConfig, IndexSearcher searcher) thr
970986
} finally {
971987
newShard.close("just do it", randomBoolean());
972988
}
989+
}
990+
991+
public void testSearchIsReleaseIfWrapperFails() throws IOException {
992+
createIndex("test");
993+
ensureGreen();
994+
IndicesService indicesService = getInstanceFromNode(IndicesService.class);
995+
IndexService indexService = indicesService.indexService("test");
996+
IndexShard shard = indexService.getShardOrNull(0);
997+
client().prepareIndex("test", "test", "0").setSource("{\"foo\" : \"bar\"}").setRefresh(true).get();
998+
IndexSearcherWrapper wrapper = new IndexSearcherWrapper() {
999+
@Override
1000+
public DirectoryReader wrap(DirectoryReader reader) throws IOException {
1001+
throw new RuntimeException("boom");
1002+
}
1003+
1004+
@Override
1005+
public IndexSearcher wrap(EngineConfig engineConfig, IndexSearcher searcher) throws EngineException {
1006+
return searcher;
1007+
}
1008+
};
1009+
1010+
IndexShard newShard = reinitWithWrapper(indexService, shard, wrapper);
1011+
try {
1012+
newShard.acquireSearcher("test");
1013+
fail("exception expected");
1014+
} catch (RuntimeException ex) {
1015+
//
1016+
} finally {
1017+
newShard.close("just do it", randomBoolean());
1018+
}
1019+
// test will fail due to unclosed searchers if the searcher is not released
1020+
}
9731021

1022+
private final IndexShard reinitWithWrapper(IndexService indexService, IndexShard shard, IndexSearcherWrapper wrapper) throws IOException {
1023+
ShardRouting routing = new ShardRouting(shard.routingEntry());
1024+
shard.close("simon says", true);
1025+
IndexServicesProvider indexServices = indexService.getIndexServices();
1026+
IndexServicesProvider newProvider = new IndexServicesProvider(indexServices.getIndicesLifecycle(), indexServices.getThreadPool(), indexServices.getMapperService(), indexServices.getQueryParserService(), indexServices.getIndexCache(), indexServices.getIndicesQueryCache(), indexServices.getCodecService(), indexServices.getTermVectorsService(), indexServices.getIndexFieldDataService(), indexServices.getWarmer(), indexServices.getSimilarityService(), indexServices.getFactory(), indexServices.getBigArrays(), wrapper, indexServices.getIndexingMemoryController());
1027+
IndexShard newShard = new IndexShard(shard.shardId(), shard.indexSettings, shard.shardPath(), shard.store(), newProvider);
1028+
ShardRoutingHelper.reinit(routing);
1029+
newShard.updateRoutingEntry(routing, false);
1030+
DiscoveryNode localNode = new DiscoveryNode("foo", DummyTransportAddress.INSTANCE, Version.CURRENT);
1031+
assertTrue(newShard.recoverFromStore(routing, localNode));
1032+
routing = new ShardRouting(routing);
1033+
ShardRoutingHelper.moveToStarted(routing);
1034+
newShard.updateRoutingEntry(routing, true);
1035+
return newShard;
9741036
}
9751037

9761038
private static class FieldMaskingReader extends FilterDirectoryReader {

0 commit comments

Comments
 (0)