|
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