Skip to content

Commit 6cdfc42

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

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
@@ -128,15 +128,16 @@ void recoverFromLocalShards(
128128
mappingUpdateConsumer.accept(sourceMetadata.mapping(), mappingStep);
129129
}
130130
mappingStep.addListener(outerListener.delegateFailure((listener, ignored) -> {
131-
indexShard.mapperService().merge(sourceMetadata, MapperService.MergeReason.MAPPING_RECOVERY);
132-
// now that the mapping is merged we can validate the index sort configuration.
133-
Sort indexSort = indexShard.getIndexSort();
134-
final boolean hasNested = indexShard.mapperService().hasNested();
135-
final boolean isSplit = sourceMetadata.getNumberOfShards() < indexShard.indexSettings().getNumberOfShards();
136-
137131
final var recoveryListener = recoveryListener(indexShard, listener);
138-
logger.debug("starting recovery from local shards {}", shards);
132+
139133
try {
134+
indexShard.mapperService().merge(sourceMetadata, MapperService.MergeReason.MAPPING_RECOVERY);
135+
// now that the mapping is merged we can validate the index sort configuration.
136+
Sort indexSort = indexShard.getIndexSort();
137+
final boolean hasNested = indexShard.mapperService().hasNested();
138+
final boolean isSplit = sourceMetadata.getNumberOfShards() < indexShard.indexSettings().getNumberOfShards();
139+
140+
logger.debug("starting recovery from local shards {}", shards);
140141
final Directory directory = indexShard.store().directory(); // don't close this directory!!
141142
final Directory[] sources = shards.stream().map(LocalShardSnapshot::getSnapshotDirectory).toArray(Directory[]::new);
142143
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
@@ -209,6 +209,8 @@
209209
import static org.hamcrest.Matchers.nullValue;
210210
import static org.hamcrest.Matchers.oneOf;
211211
import static org.hamcrest.Matchers.sameInstance;
212+
import static org.mockito.Mockito.doThrow;
213+
import static org.mockito.Mockito.spy;
212214

213215
/**
214216
* Simple unit-test IndexShard related operations.
@@ -3395,6 +3397,14 @@ public void testRecoverFromLocalShard() throws IOException {
33953397
});
33963398
closeShards(differentIndex);
33973399

3400+
// check that an error from the mapper service is handled correctly
3401+
final PlainActionFuture<Boolean> badMapperFuture = new PlainActionFuture<>();
3402+
final IndexShard badMapper = spy(targetShard);
3403+
doThrow(IllegalArgumentException.class).when(badMapper).mapperService();
3404+
final BiConsumer<MappingMetadata, ActionListener<Void>> noopConsumer = (mapping, listener) -> listener.onResponse(null);
3405+
badMapper.recoverFromLocalShards(noopConsumer, List.of(sourceShard), badMapperFuture);
3406+
assertThrows(IndexShardRecoveryException.class, badMapperFuture::actionGet);
3407+
33983408
final PlainActionFuture<Boolean> future = new PlainActionFuture<>();
33993409
targetShard.recoverFromLocalShards(mappingConsumer, Arrays.asList(sourceShard), future);
34003410
assertTrue(future.actionGet());

0 commit comments

Comments
 (0)