Skip to content

Commit 8ca98f6

Browse files
authored
[8.x] Avoid serializing empty _source fields in mappings. (#124199)
* [8.x] Avoid serializing empty _source fields in mappings. Backporting #122606 to 8.x branch. * Fix initialize builder for merging * iter
1 parent 6e10b86 commit 8ca98f6

File tree

16 files changed

+169
-74
lines changed

16 files changed

+169
-74
lines changed

docs/changelog/122606.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 122606
2+
summary: Avoid serializing empty `_source` fields in mappings
3+
area: Mapping
4+
type: bug
5+
issues: []

qa/full-cluster-restart/src/javaRestTest/java/org/elasticsearch/upgrades/FullClusterRestartDownsampleIT.java

+21-10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import com.carrotsearch.randomizedtesting.annotations.Name;
1313

14+
import org.elasticsearch.Version;
1415
import org.elasticsearch.client.Request;
1516
import org.elasticsearch.client.Response;
1617
import org.elasticsearch.common.Strings;
@@ -44,16 +45,26 @@ public class FullClusterRestartDownsampleIT extends ParameterizedFullClusterRest
4445

4546
protected static LocalClusterConfigProvider clusterConfig = c -> {};
4647

47-
private static ElasticsearchCluster cluster = ElasticsearchCluster.local()
48-
.distribution(DistributionType.DEFAULT)
49-
.version(getOldClusterTestVersion())
50-
.nodes(2)
51-
.setting("xpack.security.enabled", "false")
52-
.setting("indices.lifecycle.poll_interval", "5s")
53-
.apply(() -> clusterConfig)
54-
.feature(FeatureFlag.TIME_SERIES_MODE)
55-
.feature(FeatureFlag.FAILURE_STORE_ENABLED)
56-
.build();
48+
private static ElasticsearchCluster cluster = buildCluster();
49+
50+
private static ElasticsearchCluster buildCluster() {
51+
Version oldVersion = Version.fromString(OLD_CLUSTER_VERSION);
52+
var cluster = ElasticsearchCluster.local()
53+
.distribution(DistributionType.DEFAULT)
54+
.version(getOldClusterTestVersion())
55+
.nodes(2)
56+
.setting("xpack.security.enabled", "false")
57+
.setting("indices.lifecycle.poll_interval", "5s")
58+
.apply(() -> clusterConfig)
59+
.feature(FeatureFlag.TIME_SERIES_MODE)
60+
.feature(FeatureFlag.FAILURE_STORE_ENABLED);
61+
62+
if (oldVersion.before(Version.fromString("8.19.0"))) {
63+
cluster.jvmArg("-da:org.elasticsearch.index.mapper.DocumentMapper");
64+
cluster.jvmArg("-da:org.elasticsearch.index.mapper.MapperService");
65+
}
66+
return cluster.build();
67+
}
5768

5869
@ClassRule
5970
public static TestRule ruleChain = RuleChain.outerRule(repoDirectory).around(cluster);

qa/full-cluster-restart/src/javaRestTest/java/org/elasticsearch/upgrades/FullClusterRestartIT.java

+23-12
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import org.apache.http.util.EntityUtils;
1717
import org.elasticsearch.Build;
18+
import org.elasticsearch.Version;
1819
import org.elasticsearch.action.admin.cluster.settings.RestClusterGetSettingsResponse;
1920
import org.elasticsearch.client.Request;
2021
import org.elasticsearch.client.Response;
@@ -108,18 +109,28 @@ public class FullClusterRestartIT extends ParameterizedFullClusterRestartTestCas
108109

109110
protected static LocalClusterConfigProvider clusterConfig = c -> {};
110111

111-
private static ElasticsearchCluster cluster = ElasticsearchCluster.local()
112-
.distribution(DistributionType.DEFAULT)
113-
.version(getOldClusterTestVersion())
114-
.nodes(2)
115-
.setting("path.repo", () -> repoDirectory.getRoot().getPath())
116-
.setting("xpack.security.enabled", "false")
117-
// some tests rely on the translog not being flushed
118-
.setting("indices.memory.shard_inactive_time", "60m")
119-
.apply(() -> clusterConfig)
120-
.feature(FeatureFlag.TIME_SERIES_MODE)
121-
.feature(FeatureFlag.FAILURE_STORE_ENABLED)
122-
.build();
112+
private static ElasticsearchCluster cluster = buildCluster();
113+
114+
private static ElasticsearchCluster buildCluster() {
115+
Version oldVersion = Version.fromString(OLD_CLUSTER_VERSION);
116+
var cluster = ElasticsearchCluster.local()
117+
.distribution(DistributionType.DEFAULT)
118+
.version(getOldClusterTestVersion())
119+
.nodes(2)
120+
.setting("path.repo", () -> repoDirectory.getRoot().getPath())
121+
.setting("xpack.security.enabled", "false")
122+
// some tests rely on the translog not being flushed
123+
.setting("indices.memory.shard_inactive_time", "60m")
124+
.apply(() -> clusterConfig)
125+
.feature(FeatureFlag.TIME_SERIES_MODE)
126+
.feature(FeatureFlag.FAILURE_STORE_ENABLED);
127+
128+
if (oldVersion.before(Version.fromString("8.19.0"))) {
129+
cluster.jvmArg("-da:org.elasticsearch.index.mapper.DocumentMapper");
130+
cluster.jvmArg("-da:org.elasticsearch.index.mapper.MapperService");
131+
}
132+
return cluster.build();
133+
}
123134

124135
@ClassRule
125136
public static TestRule ruleChain = RuleChain.outerRule(repoDirectory).around(cluster);

qa/full-cluster-restart/src/javaRestTest/java/org/elasticsearch/upgrades/LogsIndexModeFullClusterRestartIT.java

+22-11
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import com.carrotsearch.randomizedtesting.annotations.Name;
1313

14+
import org.elasticsearch.Version;
1415
import org.elasticsearch.client.Request;
1516
import org.elasticsearch.client.Response;
1617
import org.elasticsearch.client.RestClient;
@@ -33,17 +34,27 @@
3334
public class LogsIndexModeFullClusterRestartIT extends ParameterizedFullClusterRestartTestCase {
3435

3536
@ClassRule
36-
public static final ElasticsearchCluster cluster = ElasticsearchCluster.local()
37-
.distribution(DistributionType.DEFAULT)
38-
.version(getOldClusterTestVersion())
39-
.module("constant-keyword")
40-
.module("data-streams")
41-
.module("mapper-extras")
42-
.module("x-pack-aggregate-metric")
43-
.module("x-pack-stack")
44-
.setting("xpack.security.enabled", "false")
45-
.setting("xpack.license.self_generated.type", "trial")
46-
.build();
37+
public static final ElasticsearchCluster cluster = buildCluster();
38+
39+
private static ElasticsearchCluster buildCluster() {
40+
Version oldVersion = Version.fromString(OLD_CLUSTER_VERSION);
41+
var cluster = ElasticsearchCluster.local()
42+
.distribution(DistributionType.DEFAULT)
43+
.version(getOldClusterTestVersion())
44+
.module("constant-keyword")
45+
.module("data-streams")
46+
.module("mapper-extras")
47+
.module("x-pack-aggregate-metric")
48+
.module("x-pack-stack")
49+
.setting("xpack.security.enabled", "false")
50+
.setting("xpack.license.self_generated.type", "trial");
51+
52+
if (oldVersion.before(Version.fromString("8.19.0"))) {
53+
cluster.jvmArg("-da:org.elasticsearch.index.mapper.DocumentMapper");
54+
cluster.jvmArg("-da:org.elasticsearch.index.mapper.MapperService");
55+
}
56+
return cluster.build();
57+
}
4758

4859
public LogsIndexModeFullClusterRestartIT(@Name("cluster") FullClusterRestartUpgradeStatus upgradeStatus) {
4960
super(upgradeStatus);

qa/full-cluster-restart/src/javaRestTest/java/org/elasticsearch/upgrades/ParameterizedFullClusterRestartTestCase.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
@TestCaseOrdering(FullClusterRestartTestOrdering.class)
3939
public abstract class ParameterizedFullClusterRestartTestCase extends ESRestTestCase {
4040
private static final Version MINIMUM_WIRE_COMPATIBLE_VERSION = Version.fromString("7.17.0");
41-
private static final String OLD_CLUSTER_VERSION = System.getProperty("tests.old_cluster_version");
41+
protected static final String OLD_CLUSTER_VERSION = System.getProperty("tests.old_cluster_version");
4242
private static IndexVersion oldIndexVersion;
4343
private static boolean upgradeFailed = false;
4444
private static boolean upgraded = false;

qa/mixed-cluster/build.gradle

+4
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ buildParams.bwcVersions.withWireCompatible { bwcVersion, baseName ->
8585
setting 'health.master_history.no_master_transitions_threshold', '10'
8686
}
8787
requiresFeature 'es.index_mode_feature_flag_registered', Version.fromString("8.0.0")
88+
if (bwcVersion.before(Version.fromString("8.19.0"))) {
89+
jvmArgs '-da:org.elasticsearch.index.mapper.DocumentMapper'
90+
jvmArgs '-da:org.elasticsearch.index.mapper.MapperService'
91+
}
8892
}
8993

9094
tasks.register("${baseName}#mixedClusterTest", StandaloneRestIntegTestTask) {

qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/upgrades/AbstractRollingUpgradeTestCase.java

+25-14
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.elasticsearch.test.cluster.ElasticsearchCluster;
1616
import org.elasticsearch.test.cluster.FeatureFlag;
1717
import org.elasticsearch.test.cluster.local.distribution.DistributionType;
18+
import org.elasticsearch.test.cluster.util.Version;
1819
import org.junit.ClassRule;
1920
import org.junit.rules.RuleChain;
2021
import org.junit.rules.TemporaryFolder;
@@ -26,20 +27,30 @@ public abstract class AbstractRollingUpgradeTestCase extends ParameterizedRollin
2627

2728
private static final TemporaryFolder repoDirectory = new TemporaryFolder();
2829

29-
private static final ElasticsearchCluster cluster = ElasticsearchCluster.local()
30-
.distribution(DistributionType.DEFAULT)
31-
.version(getOldClusterTestVersion())
32-
.nodes(NODE_NUM)
33-
.setting("path.repo", new Supplier<>() {
34-
@Override
35-
@SuppressForbidden(reason = "TemporaryFolder only has io.File methods, not nio.File")
36-
public String get() {
37-
return repoDirectory.getRoot().getPath();
38-
}
39-
})
40-
.setting("xpack.security.enabled", "false")
41-
.feature(FeatureFlag.TIME_SERIES_MODE)
42-
.build();
30+
private static final ElasticsearchCluster cluster = buildCluster();
31+
32+
private static ElasticsearchCluster buildCluster() {
33+
Version oldVersion = Version.fromString(OLD_CLUSTER_VERSION);
34+
var cluster = ElasticsearchCluster.local()
35+
.distribution(DistributionType.DEFAULT)
36+
.version(getOldClusterTestVersion())
37+
.nodes(NODE_NUM)
38+
.setting("path.repo", new Supplier<>() {
39+
@Override
40+
@SuppressForbidden(reason = "TemporaryFolder only has io.File methods, not nio.File")
41+
public String get() {
42+
return repoDirectory.getRoot().getPath();
43+
}
44+
})
45+
.setting("xpack.security.enabled", "false")
46+
.feature(FeatureFlag.TIME_SERIES_MODE);
47+
48+
if (oldVersion.before(Version.fromString("8.19.0"))) {
49+
cluster.jvmArg("-da:org.elasticsearch.index.mapper.DocumentMapper");
50+
cluster.jvmArg("-da:org.elasticsearch.index.mapper.MapperService");
51+
}
52+
return cluster.build();
53+
}
4354

4455
@ClassRule
4556
public static TestRule ruleChain = RuleChain.outerRule(repoDirectory).around(cluster);

qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/upgrades/ParameterizedRollingUpgradeTestCase.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

3737
public abstract class ParameterizedRollingUpgradeTestCase extends ESRestTestCase {
3838
protected static final int NODE_NUM = 3;
39-
private static final String OLD_CLUSTER_VERSION = System.getProperty("tests.old_cluster_version");
39+
protected static final String OLD_CLUSTER_VERSION = System.getProperty("tests.old_cluster_version");
4040
private static final Set<Integer> upgradedNodes = new HashSet<>();
4141
private static TestFeatureService oldClusterTestFeatureService = null;
4242
private static boolean upgradeFailed = false;

server/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java

+22-9
Original file line numberDiff line numberDiff line change
@@ -172,14 +172,18 @@ public Builder(IndexMode indexMode, final Settings settings, boolean supportsChe
172172
this.supportsNonDefaultParameterValues = supportsCheckForNonDefaultParams == false
173173
|| settings.getAsBoolean(LOSSY_PARAMETERS_ALLOWED_SETTING_NAME, true);
174174
this.serializeMode = serializeMode;
175-
this.mode = new Parameter<>(
176-
"mode",
177-
true,
178-
() -> null,
179-
(n, c, o) -> Mode.valueOf(o.toString().toUpperCase(Locale.ROOT)),
180-
m -> toType(m).enabled.explicit() ? null : toType(m).mode,
175+
this.mode = new Parameter<>("mode", true, () -> null, (n, c, o) -> Mode.valueOf(o.toString().toUpperCase(Locale.ROOT)), m -> {
176+
var sfm = toType(m);
177+
if (sfm.enabled.explicit()) {
178+
return null;
179+
} else if (sfm.serializeMode) {
180+
return sfm.mode;
181+
} else {
182+
return null;
183+
}
184+
},
181185
(b, n, v) -> b.field(n, v.toString().toLowerCase(Locale.ROOT)),
182-
v -> v.toString().toLowerCase(Locale.ROOT)
186+
v -> v != null ? v.toString().toLowerCase(Locale.ROOT) : null
183187
).setMergeValidator((previous, current, conflicts) -> (previous == current) || current != Mode.STORED)
184188
// don't emit if `enabled` is configured
185189
.setSerializerCheck((includeDefaults, isConfigured, value) -> serializeMode && value != null);
@@ -300,11 +304,20 @@ private static SourceFieldMapper resolveStaticInstance(final Mode sourceMode) {
300304
if (indexMode == IndexMode.STANDARD && settingSourceMode == Mode.STORED) {
301305
return DEFAULT;
302306
}
307+
SourceFieldMapper sourceFieldMapper;
303308
if (c.indexVersionCreated().onOrAfter(IndexVersions.DEPRECATE_SOURCE_MODE_MAPPER)) {
304-
return resolveStaticInstance(settingSourceMode);
309+
sourceFieldMapper = resolveStaticInstance(settingSourceMode);
305310
} else {
306-
return new SourceFieldMapper(settingSourceMode, Explicit.IMPLICIT_TRUE, Strings.EMPTY_ARRAY, Strings.EMPTY_ARRAY, true);
311+
sourceFieldMapper = new SourceFieldMapper(
312+
settingSourceMode,
313+
Explicit.IMPLICIT_TRUE,
314+
Strings.EMPTY_ARRAY,
315+
Strings.EMPTY_ARRAY,
316+
true
317+
);
307318
}
319+
indexMode.validateSourceFieldMapper(sourceFieldMapper);
320+
return sourceFieldMapper;
308321
},
309322
c -> new Builder(
310323
c.getIndexSettings().getMode(),

server/src/test/java/org/elasticsearch/index/mapper/SourceFieldMapperTests.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -253,14 +253,14 @@ public void testSyntheticSourceInTimeSeries() throws IOException {
253253
});
254254
DocumentMapper mapper = createTimeSeriesModeDocumentMapper(mapping);
255255
assertTrue(mapper.sourceMapper().isSynthetic());
256-
assertEquals("{\"_source\":{}}", mapper.sourceMapper().toString());
256+
assertEquals("{}", mapper.sourceMapper().toString());
257257
}
258258

259259
public void testSyntheticSourceWithLogsIndexMode() throws IOException {
260260
XContentBuilder mapping = fieldMapping(b -> { b.field("type", "keyword"); });
261261
DocumentMapper mapper = createLogsModeDocumentMapper(mapping);
262262
assertTrue(mapper.sourceMapper().isSynthetic());
263-
assertEquals("{\"_source\":{}}", mapper.sourceMapper().toString());
263+
assertEquals("{}", mapper.sourceMapper().toString());
264264
}
265265

266266
public void testSupportsNonDefaultParameterValues() throws IOException {

x-pack/plugin/downsample/qa/mixed-cluster/src/yamlRestTest/java/org/elasticsearch/xpack/downsample/MixedClusterDownsampleRestIT.java

+17-7
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,23 @@
1919
public class MixedClusterDownsampleRestIT extends ESClientYamlSuiteTestCase {
2020

2121
@ClassRule
22-
public static ElasticsearchCluster cluster = ElasticsearchCluster.local()
23-
.distribution(DistributionType.DEFAULT)
24-
.withNode(node -> node.version(getOldVersion()))
25-
.withNode(node -> node.version(Version.CURRENT))
26-
.setting("xpack.security.enabled", "false")
27-
.setting("xpack.license.self_generated.type", "trial")
28-
.build();
22+
public static ElasticsearchCluster cluster = buildCluster();
23+
24+
private static ElasticsearchCluster buildCluster() {
25+
Version oldVersion = getOldVersion();
26+
var cluster = ElasticsearchCluster.local()
27+
.distribution(DistributionType.DEFAULT)
28+
.withNode(node -> node.version(getOldVersion()))
29+
.withNode(node -> node.version(Version.CURRENT))
30+
.setting("xpack.security.enabled", "false")
31+
.setting("xpack.license.self_generated.type", "trial");
32+
33+
if (oldVersion.before(Version.fromString("8.19.0"))) {
34+
cluster.jvmArg("-da:org.elasticsearch.index.mapper.DocumentMapper");
35+
cluster.jvmArg("-da:org.elasticsearch.index.mapper.MapperService");
36+
}
37+
return cluster.build();
38+
}
2939

3040
static Version getOldVersion() {
3141
return Version.fromString(System.getProperty("tests.old_cluster_version"));

x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/Clusters.java

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ public static ElasticsearchCluster mixedVersionCluster() {
2525
if (supportRetryOnShardFailures(oldVersion) == false) {
2626
cluster.setting("cluster.routing.rebalance.enable", "none");
2727
}
28+
if (oldVersion.before(Version.fromString("8.19.0"))) {
29+
cluster.jvmArg("-da:org.elasticsearch.index.mapper.DocumentMapper");
30+
cluster.jvmArg("-da:org.elasticsearch.index.mapper.MapperService");
31+
}
2832
return cluster.build();
2933
}
3034

x-pack/plugin/logsdb/src/javaRestTest/java/org/elasticsearch/xpack/logsdb/LogsdbSnapshotRestoreIT.java

-4
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,6 @@ public class LogsdbSnapshotRestoreIT extends ESRestTestCase {
5353
.setting("cluster.logsdb.enabled", "true")
5454
.setting("xpack.security.enabled", "false")
5555
.setting("xpack.license.self_generated.type", "trial")
56-
// TODO: remove when initializing / serializing default SourceFieldMapper instance have been fixed:
57-
// (SFM's mode attribute often gets initialized, even when mode attribute isn't set)
58-
.jvmArg("-da:org.elasticsearch.index.mapper.DocumentMapper")
59-
.jvmArg("-da:org.elasticsearch.index.mapper.MapperService")
6056
.build();
6157

6258
@ClassRule

x-pack/plugin/logsdb/src/yamlRestTest/resources/rest-api-spec/test/40_source_mode_setting.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ modify logsdb index source mode to stored after index creation:
754754
_source:
755755
mode: stored
756756
- match: { error.type: "illegal_argument_exception" }
757-
- match: { error.reason: "Mapper for [_source] conflicts with existing mapper:\n\tCannot update parameter [mode] from [synthetic] to [stored]" }
757+
- match: { error.reason: "Mapper for [_source] conflicts with existing mapper:\n\tCannot update parameter [mode] from [null] to [stored]" }
758758

759759
---
760760
modify time_series index source mode to disabled after index creation:
@@ -812,4 +812,4 @@ modify time_series index source mode to stored after index creation:
812812
_source:
813813
mode: stored
814814
- match: { error.type: "illegal_argument_exception" }
815-
- match: { error.reason: "Mapper for [_source] conflicts with existing mapper:\n\tCannot update parameter [mode] from [synthetic] to [stored]" }
815+
- match: { error.reason: "Mapper for [_source] conflicts with existing mapper:\n\tCannot update parameter [mode] from [null] to [stored]" }

x-pack/qa/rolling-upgrade/build.gradle

+4
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ buildParams.bwcVersions.withWireCompatible { bwcVersion, baseName ->
6060
setting 'xpack.security.transport.ssl.key', 'testnode.pem'
6161
setting 'xpack.security.transport.ssl.certificate', 'testnode.crt'
6262
keystore 'xpack.security.transport.ssl.secure_key_passphrase', 'testnode'
63+
if (bwcVersion.before('8.19.0')) {
64+
jvmArgs '-da:org.elasticsearch.index.mapper.MapperService'
65+
jvmArgs '-da:org.elasticsearch.index.mapper.DocumentMapper'
66+
}
6367

6468
if (bwcVersion.onOrAfter('7.0.0')) {
6569
setting 'xpack.security.authc.realms.file.file1.order', '0'

0 commit comments

Comments
 (0)