Skip to content

Commit fb5008a

Browse files
authored
Catch exceptions from mapperService in StoreRecovery.recoverFromLocalShards (elastic#137077) (elastic#137114)
The inline listener there must not throw, or the recovery task will leak.
1 parent 3f4c117 commit fb5008a

File tree

3 files changed

+23
-7
lines changed

3 files changed

+23
-7
lines changed

docs/changelog/137077.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 137077
2+
summary: Catch exceptions from `mapperService` in `StoreRecovery.recoverFromLocalShards`
3+
area: Recovery
4+
type: bug
5+
issues: []

server/src/main/java/org/elasticsearch/index/shard/StoreRecovery.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,16 @@ void recoverFromLocalShards(
126126
mappingUpdateConsumer.accept(sourceMetadata.mapping(), mappingStep);
127127
}
128128
mappingStep.addListener(outerListener.delegateFailure((listener, ignored) -> {
129-
indexShard.mapperService().merge(sourceMetadata, MapperService.MergeReason.MAPPING_RECOVERY);
130-
// now that the mapping is merged we can validate the index sort configuration.
131-
Sort indexSort = indexShard.getIndexSort();
132-
final boolean hasNested = indexShard.mapperService().hasNested();
133-
final boolean isSplit = sourceMetadata.getNumberOfShards() < indexShard.indexSettings().getNumberOfShards();
134-
135129
final var recoveryListener = recoveryListener(indexShard, listener);
136-
logger.debug("starting recovery from local shards {}", shards);
130+
137131
try {
132+
indexShard.mapperService().merge(sourceMetadata, MapperService.MergeReason.MAPPING_RECOVERY);
133+
// now that the mapping is merged we can validate the index sort configuration.
134+
Sort indexSort = indexShard.getIndexSort();
135+
final boolean hasNested = indexShard.mapperService().hasNested();
136+
final boolean isSplit = sourceMetadata.getNumberOfShards() < indexShard.indexSettings().getNumberOfShards();
137+
138+
logger.debug("starting recovery from local shards {}", shards);
138139
final Directory directory = indexShard.store().directory(); // don't close this directory!!
139140
final Directory[] sources = shards.stream().map(LocalShardSnapshot::getSnapshotDirectory).toArray(Directory[]::new);
140141
final long maxSeqNo = shards.stream().mapToLong(LocalShardSnapshot::maxSeqNo).max().getAsLong();

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@
203203
import static org.hamcrest.Matchers.nullValue;
204204
import static org.hamcrest.Matchers.oneOf;
205205
import static org.hamcrest.Matchers.sameInstance;
206+
import static org.mockito.Mockito.doThrow;
207+
import static org.mockito.Mockito.spy;
206208

207209
/**
208210
* Simple unit-test IndexShard related operations.
@@ -3374,6 +3376,14 @@ public void testRecoverFromLocalShard() throws IOException {
33743376
});
33753377
closeShards(differentIndex);
33763378

3379+
// check that an error from the mapper service is handled correctly
3380+
final PlainActionFuture<Boolean> badMapperFuture = new PlainActionFuture<>();
3381+
final IndexShard badMapper = spy(targetShard);
3382+
doThrow(IllegalArgumentException.class).when(badMapper).mapperService();
3383+
final BiConsumer<MappingMetadata, ActionListener<Void>> noopConsumer = (mapping, listener) -> listener.onResponse(null);
3384+
badMapper.recoverFromLocalShards(noopConsumer, List.of(sourceShard), badMapperFuture);
3385+
assertThrows(IndexShardRecoveryException.class, badMapperFuture::actionGet);
3386+
33773387
final PlainActionFuture<Boolean> future = new PlainActionFuture<>();
33783388
targetShard.recoverFromLocalShards(mappingConsumer, Arrays.asList(sourceShard), future);
33793389
assertTrue(future.actionGet());

0 commit comments

Comments
 (0)