Skip to content

Commit 1bbfec0

Browse files
authored
[8.x] Handle empty index case in LuceneSyntheticSourceChangesSnapshot (#119089)
Backport of #118996 to 8.x branch. In case of synthetic recovery source when the mapping is empty. A test that reproduces failure in #118955 consistently with a potential fix. `MapperService#updateMapping(...)` doesn't set the mapper field if a mapping has no fields, which is what is used in InternalEngine#newChangesSnapshot(...) . This happens when `newMappingMetadata` variable in `MapperService updateMapping(...)` is `null`. Causing an assertion to trip. This change adjusts that assertion to handle an empty index. Closes #118955
1 parent 7b2a12a commit 1bbfec0

File tree

4 files changed

+43
-8
lines changed

4 files changed

+43
-8
lines changed

rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/indices.create/20_synthetic_source.yml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2036,14 +2036,12 @@ create index with use_synthetic_source:
20362036
- is_true: test.settings.index.recovery.use_synthetic_source
20372037

20382038
- do:
2039-
bulk:
2039+
index:
20402040
index: test
2041+
id: 1
20412042
refresh: true
2042-
body:
2043-
- '{ "create": { } }'
2044-
- '{ "field": "aaaa" }'
2045-
- '{ "create": { } }'
2046-
- '{ "field": "bbbb" }'
2043+
body: { foo: bar }
2044+
- match: { _version: 1 }
20472045

20482046
- do:
20492047
indices.disk_usage:
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
test recovery empty index with use_synthetic_source:
3+
- requires:
4+
cluster_features: ["mapper.synthetic_recovery_source"]
5+
reason: requires synthetic recovery source
6+
7+
- do:
8+
indices.create:
9+
index: test
10+
body:
11+
settings:
12+
index:
13+
number_of_replicas: 0
14+
recovery:
15+
use_synthetic_source: true
16+
mapping:
17+
source:
18+
mode: synthetic
19+
20+
- do:
21+
indices.get_settings: {}
22+
- match: { test.settings.index.mapping.source.mode: synthetic}
23+
- is_true: test.settings.index.recovery.use_synthetic_source
24+
25+
- do:
26+
indices.put_settings:
27+
index: test
28+
body:
29+
index.number_of_replicas: 1
30+
31+
- do:
32+
cluster.health:
33+
wait_for_events: languid

server/src/main/java/org/elasticsearch/index/IndexSettings.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,9 @@ public IndexSettings(final IndexMetadata indexMetadata, final Settings nodeSetti
10361036
recoverySourceEnabled = RecoverySettings.INDICES_RECOVERY_SOURCE_ENABLED_SETTING.get(nodeSettings);
10371037
recoverySourceSyntheticEnabled = scopedSettings.get(RECOVERY_USE_SYNTHETIC_SOURCE_SETTING);
10381038
if (recoverySourceSyntheticEnabled) {
1039+
if (DiscoveryNode.isStateless(settings)) {
1040+
throw new IllegalArgumentException("synthetic recovery source is only allowed in stateful");
1041+
}
10391042
// Verify that all nodes can handle this setting
10401043
if (version.before(IndexVersions.USE_SYNTHETIC_SOURCE_FOR_RECOVERY_BACKPORT)) {
10411044
throw new IllegalArgumentException(

server/src/main/java/org/elasticsearch/index/engine/LuceneSyntheticSourceChangesSnapshot.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,13 @@ public LuceneSyntheticSourceChangesSnapshot(
7777
IndexVersion indexVersionCreated
7878
) throws IOException {
7979
super(engineSearcher, searchBatchSize, fromSeqNo, toSeqNo, requiredFullRange, accessStats, indexVersionCreated);
80-
assert mappingLookup.isSourceSynthetic();
80+
// a MapperService#updateMapping(...) of empty index may not have been invoked and then mappingLookup is empty
81+
assert engineSearcher.getDirectoryReader().maxDoc() == 0 || mappingLookup.isSourceSynthetic()
82+
: "either an empty index or synthetic source must be enabled for proper functionality.";
8183
// ensure we can buffer at least one document
8284
this.maxMemorySizeInBytes = maxMemorySizeInBytes > 0 ? maxMemorySizeInBytes : 1;
8385
this.sourceLoader = mappingLookup.newSourceLoader(null, SourceFieldMetrics.NOOP);
8486
Set<String> storedFields = sourceLoader.requiredStoredFields();
85-
assert mappingLookup.isSourceSynthetic() : "synthetic source must be enabled for proper functionality.";
8687
this.storedFieldLoader = StoredFieldLoader.create(false, storedFields);
8788
this.lastSeenSeqNo = fromSeqNo - 1;
8889
}

0 commit comments

Comments
 (0)