|
27 | 27 | import org.apache.lucene.search.TermQuery;
|
28 | 28 | import org.apache.lucene.search.TopDocs;
|
29 | 29 | import org.apache.lucene.store.AlreadyClosedException;
|
| 30 | +import org.apache.lucene.store.Directory; |
| 31 | +import org.apache.lucene.store.FilterDirectory; |
30 | 32 | import org.apache.lucene.store.IOContext;
|
31 | 33 | import org.apache.lucene.util.Constants;
|
32 | 34 | import org.elasticsearch.Version;
|
|
111 | 113 | import org.elasticsearch.test.FieldMaskingReader;
|
112 | 114 | import org.elasticsearch.test.VersionUtils;
|
113 | 115 | import org.elasticsearch.threadpool.ThreadPool;
|
| 116 | +import org.elasticsearch.ElasticsearchException; |
114 | 117 |
|
115 | 118 | import java.io.IOException;
|
116 | 119 | import java.nio.charset.Charset;
|
|
137 | 140 | import java.util.function.BiConsumer;
|
138 | 141 | import java.util.function.Consumer;
|
139 | 142 | import java.util.function.LongFunction;
|
| 143 | +import java.util.function.Supplier; |
140 | 144 | import java.util.stream.Collectors;
|
141 | 145 | import java.util.stream.IntStream;
|
142 | 146 |
|
@@ -1161,6 +1165,81 @@ public void testShardStats() throws IOException {
|
1161 | 1165 | closeShards(shard);
|
1162 | 1166 | }
|
1163 | 1167 |
|
| 1168 | + |
| 1169 | + public void testShardStatsWithFailures() throws IOException { |
| 1170 | + allowShardFailures(); |
| 1171 | + final ShardId shardId = new ShardId("index", "_na_", 0); |
| 1172 | + final ShardRouting shardRouting = newShardRouting(shardId, "node", true, RecoverySource.StoreRecoverySource.EMPTY_STORE_INSTANCE, ShardRoutingState.INITIALIZING); |
| 1173 | + final NodeEnvironment.NodePath nodePath = new NodeEnvironment.NodePath(createTempDir()); |
| 1174 | + |
| 1175 | + |
| 1176 | + ShardPath shardPath = new ShardPath(false, nodePath.resolve(shardId), nodePath.resolve(shardId), shardId); |
| 1177 | + Settings settings = Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) |
| 1178 | + .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0) |
| 1179 | + .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1) |
| 1180 | + .build(); |
| 1181 | + IndexMetaData metaData = IndexMetaData.builder(shardRouting.getIndexName()) |
| 1182 | + .settings(settings) |
| 1183 | + .primaryTerm(0, 1) |
| 1184 | + .build(); |
| 1185 | + |
| 1186 | + // Override two Directory methods to make them fail at our will |
| 1187 | + // We use AtomicReference here to inject failure in the middle of the test not immediately |
| 1188 | + // We use Supplier<IOException> instead of IOException to produce meaningful stacktrace |
| 1189 | + // (remember stack trace is filled when exception is instantiated) |
| 1190 | + AtomicReference<Supplier<IOException>> exceptionToThrow = new AtomicReference<>(); |
| 1191 | + AtomicBoolean throwWhenMarkingStoreCorrupted = new AtomicBoolean(false); |
| 1192 | + Directory directory = new FilterDirectory(newFSDirectory(shardPath.resolveIndex())) { |
| 1193 | + //fileLength method is called during storeStats try block |
| 1194 | + //it's not called when store is marked as corrupted |
| 1195 | + @Override |
| 1196 | + public long fileLength(String name) throws IOException { |
| 1197 | + Supplier<IOException> ex = exceptionToThrow.get(); |
| 1198 | + if (ex == null) { |
| 1199 | + return super.fileLength(name); |
| 1200 | + } else { |
| 1201 | + throw ex.get(); |
| 1202 | + } |
| 1203 | + } |
| 1204 | + |
| 1205 | + //listAll method is called when marking store as corrupted |
| 1206 | + @Override |
| 1207 | + public String[] listAll() throws IOException { |
| 1208 | + Supplier<IOException> ex = exceptionToThrow.get(); |
| 1209 | + if (throwWhenMarkingStoreCorrupted.get() && ex != null) { |
| 1210 | + throw ex.get(); |
| 1211 | + } else { |
| 1212 | + return super.listAll(); |
| 1213 | + } |
| 1214 | + } |
| 1215 | + }; |
| 1216 | + |
| 1217 | + try (Store store = createStore(shardId, new IndexSettings(metaData, Settings.EMPTY), directory)) { |
| 1218 | + IndexShard shard = newShard(shardRouting, shardPath, metaData, store, |
| 1219 | + null, new InternalEngineFactory(), () -> { |
| 1220 | + }, EMPTY_EVENT_LISTENER); |
| 1221 | + AtomicBoolean failureCallbackTriggered = new AtomicBoolean(false); |
| 1222 | + shard.addShardFailureCallback((ig)->failureCallbackTriggered.set(true)); |
| 1223 | + |
| 1224 | + recoverShardFromStore(shard); |
| 1225 | + |
| 1226 | + final boolean corruptIndexException = randomBoolean(); |
| 1227 | + |
| 1228 | + if (corruptIndexException) { |
| 1229 | + exceptionToThrow.set(() -> new CorruptIndexException("Test CorruptIndexException", "Test resource")); |
| 1230 | + throwWhenMarkingStoreCorrupted.set(randomBoolean()); |
| 1231 | + } else { |
| 1232 | + exceptionToThrow.set(() -> new IOException("Test IOException")); |
| 1233 | + } |
| 1234 | + ElasticsearchException e = expectThrows(ElasticsearchException.class, shard::storeStats); |
| 1235 | + assertTrue(failureCallbackTriggered.get()); |
| 1236 | + |
| 1237 | + if (corruptIndexException && !throwWhenMarkingStoreCorrupted.get()) { |
| 1238 | + assertTrue(store.isMarkedCorrupted()); |
| 1239 | + } |
| 1240 | + } |
| 1241 | + } |
| 1242 | + |
1164 | 1243 | public void testRefreshMetric() throws IOException {
|
1165 | 1244 | IndexShard shard = newStartedShard();
|
1166 | 1245 | assertThat(shard.refreshStats().getTotal(), equalTo(2L)); // refresh on: finalize and end of recovery
|
@@ -1867,6 +1946,7 @@ public IndexSearcher wrap(IndexSearcher searcher) throws EngineException {
|
1867 | 1946 | ShardRoutingHelper.initWithSameId(shard.routingEntry(), RecoverySource.StoreRecoverySource.EXISTING_STORE_INSTANCE),
|
1868 | 1947 | shard.shardPath(),
|
1869 | 1948 | shard.indexSettings().getIndexMetaData(),
|
| 1949 | + null, |
1870 | 1950 | wrapper,
|
1871 | 1951 | new InternalEngineFactory(),
|
1872 | 1952 | () -> {},
|
@@ -2018,6 +2098,7 @@ public IndexSearcher wrap(IndexSearcher searcher) throws EngineException {
|
2018 | 2098 | ShardRoutingHelper.initWithSameId(shard.routingEntry(), RecoverySource.StoreRecoverySource.EXISTING_STORE_INSTANCE),
|
2019 | 2099 | shard.shardPath(),
|
2020 | 2100 | shard.indexSettings().getIndexMetaData(),
|
| 2101 | + null, |
2021 | 2102 | wrapper,
|
2022 | 2103 | new InternalEngineFactory(),
|
2023 | 2104 | () -> {},
|
@@ -2504,7 +2585,7 @@ public void testReadSnapshotAndCheckIndexConcurrently() throws Exception {
|
2504 | 2585 | .put(IndexSettings.INDEX_CHECK_ON_STARTUP.getKey(), randomFrom("false", "true", "checksum", "fix")))
|
2505 | 2586 | .build();
|
2506 | 2587 | final IndexShard newShard = newShard(shardRouting, indexShard.shardPath(), indexMetaData,
|
2507 |
| - null, indexShard.engineFactory, indexShard.getGlobalCheckpointSyncer(), EMPTY_EVENT_LISTENER); |
| 2588 | + null, null, indexShard.engineFactory, indexShard.getGlobalCheckpointSyncer(), EMPTY_EVENT_LISTENER); |
2508 | 2589 |
|
2509 | 2590 | Store.MetadataSnapshot storeFileMetaDatas = newShard.snapshotStoreMetadata();
|
2510 | 2591 | assertTrue("at least 2 files, commit and data: " + storeFileMetaDatas.toString(), storeFileMetaDatas.size() > 1);
|
@@ -2861,7 +2942,7 @@ public void testFlushOnInactive() throws Exception {
|
2861 | 2942 | ShardPath shardPath = new ShardPath(false, nodePath.resolve(shardId), nodePath.resolve(shardId), shardId);
|
2862 | 2943 | AtomicBoolean markedInactive = new AtomicBoolean();
|
2863 | 2944 | AtomicReference<IndexShard> primaryRef = new AtomicReference<>();
|
2864 |
| - IndexShard primary = newShard(shardRouting, shardPath, metaData, null, new InternalEngineFactory(), () -> { |
| 2945 | + IndexShard primary = newShard(shardRouting, shardPath, metaData, null, null, new InternalEngineFactory(), () -> { |
2865 | 2946 | }, new IndexEventListener() {
|
2866 | 2947 | @Override
|
2867 | 2948 | public void onShardInactive(IndexShard indexShard) {
|
|
0 commit comments