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