Skip to content

Commit e459915

Browse files
MapperService has to be passed in as null for EnginePlugins CodecService constructor (#2177) (#2413)
* MapperService has to be passed in as null for EnginePlugins CodecService constructor Signed-off-by: Andriy Redko <[email protected]> * Addressing code review comments Signed-off-by: Andriy Redko <[email protected]> * Delayed CodecService instantiation up to the shard initialization Signed-off-by: Andriy Redko <[email protected]> * Added logger (associated with shard) to CodecServiceConfig Signed-off-by: Andriy Redko <[email protected]> * Refactored the EngineConfigFactory / IndexShard instantiation of the CodecService Signed-off-by: Andriy Redko <[email protected]> (cherry picked from commit 9c679cb) Co-authored-by: Andriy Redko <[email protected]>
1 parent 5e5a629 commit e459915

File tree

6 files changed

+200
-7
lines changed

6 files changed

+200
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*/
8+
9+
package org.opensearch.index.codec;
10+
11+
import org.apache.logging.log4j.Logger;
12+
import org.opensearch.common.Nullable;
13+
import org.opensearch.index.IndexSettings;
14+
import org.opensearch.index.mapper.MapperService;
15+
16+
import java.util.Objects;
17+
18+
/**
19+
* The configuration parameters necessary for the {@link CodecService} instance construction.
20+
*/
21+
public final class CodecServiceConfig {
22+
private final IndexSettings indexSettings;
23+
private final MapperService mapperService;
24+
private final Logger logger;
25+
26+
public CodecServiceConfig(IndexSettings indexSettings, @Nullable MapperService mapperService, @Nullable Logger logger) {
27+
this.indexSettings = Objects.requireNonNull(indexSettings);
28+
this.mapperService = mapperService;
29+
this.logger = logger;
30+
}
31+
32+
public IndexSettings getIndexSettings() {
33+
return indexSettings;
34+
}
35+
36+
@Nullable
37+
public MapperService getMapperService() {
38+
return mapperService;
39+
}
40+
41+
@Nullable
42+
public Logger getLogger() {
43+
return logger;
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*/
8+
9+
package org.opensearch.index.codec;
10+
11+
/**
12+
* A factory for creating new {@link CodecService} instance
13+
*/
14+
@FunctionalInterface
15+
public interface CodecServiceFactory {
16+
/**
17+
* Create new {@link CodecService} instance
18+
* @param config code service configuration
19+
* @return new {@link CodecService} instance
20+
*/
21+
CodecService createCodecService(CodecServiceConfig config);
22+
}

server/src/main/java/org/opensearch/index/engine/EngineConfigFactory.java

+53-6
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,21 @@
88

99
package org.opensearch.index.engine;
1010

11+
import org.apache.logging.log4j.Logger;
1112
import org.apache.lucene.analysis.Analyzer;
1213
import org.apache.lucene.index.MergePolicy;
1314
import org.apache.lucene.search.QueryCache;
1415
import org.apache.lucene.search.QueryCachingPolicy;
1516
import org.apache.lucene.search.ReferenceManager;
1617
import org.apache.lucene.search.Sort;
1718
import org.apache.lucene.search.similarities.Similarity;
19+
import org.opensearch.common.Nullable;
1820
import org.opensearch.common.unit.TimeValue;
1921
import org.opensearch.index.IndexSettings;
2022
import org.opensearch.index.codec.CodecService;
23+
import org.opensearch.index.codec.CodecServiceConfig;
24+
import org.opensearch.index.codec.CodecServiceFactory;
25+
import org.opensearch.index.mapper.MapperService;
2126
import org.opensearch.index.seqno.RetentionLeases;
2227
import org.opensearch.index.shard.ShardId;
2328
import org.opensearch.index.store.Store;
@@ -39,7 +44,7 @@
3944
* A factory to create an EngineConfig based on custom plugin overrides
4045
*/
4146
public class EngineConfigFactory {
42-
private final CodecService codecService;
47+
private final CodecServiceFactory codecServiceFactory;
4348
private final TranslogDeletionPolicyFactory translogDeletionPolicyFactory;
4449

4550
/** default ctor primarily used for tests without plugins */
@@ -58,14 +63,16 @@ public EngineConfigFactory(PluginsService pluginsService, IndexSettings idxSetti
5863
EngineConfigFactory(Collection<EnginePlugin> enginePlugins, IndexSettings idxSettings) {
5964
Optional<CodecService> codecService = Optional.empty();
6065
String codecServiceOverridingPlugin = null;
66+
Optional<CodecServiceFactory> codecServiceFactory = Optional.empty();
67+
String codecServiceFactoryOverridingPlugin = null;
6168
Optional<TranslogDeletionPolicyFactory> translogDeletionPolicyFactory = Optional.empty();
6269
String translogDeletionPolicyOverridingPlugin = null;
6370
for (EnginePlugin enginePlugin : enginePlugins) {
6471
// get overriding codec service from EnginePlugin
6572
if (codecService.isPresent() == false) {
6673
codecService = enginePlugin.getCustomCodecService(idxSettings);
6774
codecServiceOverridingPlugin = enginePlugin.getClass().getName();
68-
} else {
75+
} else if (enginePlugin.getCustomCodecService(idxSettings).isPresent()) {
6976
throw new IllegalStateException(
7077
"existing codec service already overridden in: "
7178
+ codecServiceOverridingPlugin
@@ -76,20 +83,45 @@ public EngineConfigFactory(PluginsService pluginsService, IndexSettings idxSetti
7683
if (translogDeletionPolicyFactory.isPresent() == false) {
7784
translogDeletionPolicyFactory = enginePlugin.getCustomTranslogDeletionPolicyFactory();
7885
translogDeletionPolicyOverridingPlugin = enginePlugin.getClass().getName();
79-
} else {
86+
} else if (enginePlugin.getCustomTranslogDeletionPolicyFactory().isPresent()) {
8087
throw new IllegalStateException(
8188
"existing TranslogDeletionPolicyFactory is already overridden in: "
8289
+ translogDeletionPolicyOverridingPlugin
8390
+ " attempting to override again by: "
8491
+ enginePlugin.getClass().getName()
8592
);
8693
}
94+
// get overriding CodecServiceFactory from EnginePlugin
95+
if (codecServiceFactory.isPresent() == false) {
96+
codecServiceFactory = enginePlugin.getCustomCodecServiceFactory(idxSettings);
97+
codecServiceFactoryOverridingPlugin = enginePlugin.getClass().getName();
98+
} else if (enginePlugin.getCustomCodecServiceFactory(idxSettings).isPresent()) {
99+
throw new IllegalStateException(
100+
"existing codec service factory already overridden in: "
101+
+ codecServiceFactoryOverridingPlugin
102+
+ " attempting to override again by: "
103+
+ enginePlugin.getClass().getName()
104+
);
105+
}
106+
}
107+
108+
if (codecService.isPresent() && codecServiceFactory.isPresent()) {
109+
throw new IllegalStateException(
110+
"both codec service and codec service factory are present, codec service provided by: "
111+
+ codecServiceOverridingPlugin
112+
+ " conflicts with codec service factory provided by: "
113+
+ codecServiceFactoryOverridingPlugin
114+
);
87115
}
88-
this.codecService = codecService.orElse(null);
116+
117+
final CodecService instance = codecService.orElse(null);
118+
this.codecServiceFactory = (instance != null) ? (config) -> instance : codecServiceFactory.orElse(null);
89119
this.translogDeletionPolicyFactory = translogDeletionPolicyFactory.orElse((idxs, rtls) -> null);
90120
}
91121

92-
/** Instantiates a new EngineConfig from the provided custom overrides */
122+
/**
123+
* Instantiates a new EngineConfig from the provided custom overrides
124+
*/
93125
public EngineConfig newEngineConfig(
94126
ShardId shardId,
95127
ThreadPool threadPool,
@@ -114,6 +146,10 @@ public EngineConfig newEngineConfig(
114146
LongSupplier primaryTermSupplier,
115147
EngineConfig.TombstoneDocSupplier tombstoneDocSupplier
116148
) {
149+
CodecService codecServiceToUse = codecService;
150+
if (codecService == null && this.codecServiceFactory != null) {
151+
codecServiceToUse = newCodecServiceOrDefault(indexSettings, null, null, null);
152+
}
117153

118154
return new EngineConfig(
119155
shardId,
@@ -124,7 +160,7 @@ public EngineConfig newEngineConfig(
124160
mergePolicy,
125161
analyzer,
126162
similarity,
127-
this.codecService != null ? this.codecService : codecService,
163+
codecServiceToUse,
128164
eventListener,
129165
queryCache,
130166
queryCachingPolicy,
@@ -141,4 +177,15 @@ public EngineConfig newEngineConfig(
141177
tombstoneDocSupplier
142178
);
143179
}
180+
181+
public CodecService newCodecServiceOrDefault(
182+
IndexSettings indexSettings,
183+
@Nullable MapperService mapperService,
184+
Logger logger,
185+
CodecService defaultCodecService
186+
) {
187+
return this.codecServiceFactory != null
188+
? this.codecServiceFactory.createCodecService(new CodecServiceConfig(indexSettings, mapperService, logger))
189+
: defaultCodecService;
190+
}
144191
}

server/src/main/java/org/opensearch/index/shard/IndexShard.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -3172,6 +3172,7 @@ private EngineConfig newEngineConfig(LongSupplier globalCheckpointSupplier) {
31723172
this.warmer.warm(reader);
31733173
}
31743174
};
3175+
31753176
return this.engineConfigFactory.newEngineConfig(
31763177
shardId,
31773178
threadPool,
@@ -3181,7 +3182,7 @@ private EngineConfig newEngineConfig(LongSupplier globalCheckpointSupplier) {
31813182
indexSettings.getMergePolicy(),
31823183
mapperService != null ? mapperService.indexAnalyzer() : null,
31833184
similarityService.similarity(mapperService),
3184-
codecService,
3185+
engineConfigFactory.newCodecServiceOrDefault(indexSettings, mapperService, logger, codecService),
31853186
shardEventListener,
31863187
indexCache != null ? indexCache.query() : null,
31873188
cachingPolicy,

server/src/main/java/org/opensearch/plugins/EnginePlugin.java

+16
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
import org.opensearch.index.IndexSettings;
3636
import org.opensearch.index.codec.CodecService;
37+
import org.opensearch.index.codec.CodecServiceFactory;
3738
import org.opensearch.index.engine.EngineFactory;
3839
import org.opensearch.index.seqno.RetentionLeases;
3940
import org.opensearch.index.translog.TranslogDeletionPolicy;
@@ -63,11 +64,26 @@ public interface EnginePlugin {
6364
* to determine if a custom {@link CodecService} should be provided for the given index. A plugin that is not overriding
6465
* the {@link CodecService} through the plugin can ignore this method and the Codec specified in the {@link IndexSettings}
6566
* will be used.
67+
*
68+
* @deprecated Please use {@code getCustomCodecServiceFactory()} instead as it provides more context for {@link CodecService}
69+
* instance construction.
6670
*/
71+
@Deprecated
6772
default Optional<CodecService> getCustomCodecService(IndexSettings indexSettings) {
6873
return Optional.empty();
6974
}
7075

76+
/**
77+
* EXPERT:
78+
* When an index is created this method is invoked for each engine plugin. Engine plugins can inspect the index settings
79+
* to determine if a custom {@link CodecServiceFactory} should be provided for the given index. A plugin that is not overriding
80+
* the {@link CodecServiceFactory} through the plugin can ignore this method and the default Codec specified in the
81+
* {@link IndexSettings} will be used.
82+
*/
83+
default Optional<CodecServiceFactory> getCustomCodecServiceFactory(IndexSettings indexSettings) {
84+
return Optional.empty();
85+
}
86+
7187
/**
7288
* When an index is created this method is invoked for each engine plugin. Engine plugins that need to provide a
7389
* custom {@link TranslogDeletionPolicy} can override this method to return a function that takes the {@link IndexSettings}

server/src/test/java/org/opensearch/index/engine/EngineConfigFactoryTests.java

+62
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.opensearch.common.unit.TimeValue;
1515
import org.opensearch.index.IndexSettings;
1616
import org.opensearch.index.codec.CodecService;
17+
import org.opensearch.index.codec.CodecServiceFactory;
1718
import org.opensearch.index.seqno.RetentionLeases;
1819
import org.opensearch.index.translog.TranslogDeletionPolicy;
1920
import org.opensearch.index.translog.TranslogDeletionPolicyFactory;
@@ -84,6 +85,18 @@ public void testCreateEngineConfigFromFactoryMultipleCodecServiceIllegalStateExc
8485
expectThrows(IllegalStateException.class, () -> new EngineConfigFactory(plugins, indexSettings));
8586
}
8687

88+
public void testCreateEngineConfigFromFactoryMultipleCodecServiceAndFactoryIllegalStateException() {
89+
IndexMetadata meta = IndexMetadata.builder("test")
90+
.settings(settings(Version.CURRENT))
91+
.numberOfShards(1)
92+
.numberOfReplicas(1)
93+
.build();
94+
List<EnginePlugin> plugins = Arrays.asList(new FooEnginePlugin(), new BakEnginePlugin());
95+
IndexSettings indexSettings = IndexSettingsModule.newIndexSettings("test", meta.getSettings());
96+
97+
expectThrows(IllegalStateException.class, () -> new EngineConfigFactory(plugins, indexSettings));
98+
}
99+
87100
public void testCreateEngineConfigFromFactoryMultipleCustomTranslogDeletionPolicyFactoryIllegalStateException() {
88101
IndexMetadata meta = IndexMetadata.builder("test")
89102
.settings(settings(Version.CURRENT))
@@ -96,6 +109,43 @@ public void testCreateEngineConfigFromFactoryMultipleCustomTranslogDeletionPolic
96109
expectThrows(IllegalStateException.class, () -> new EngineConfigFactory(plugins, indexSettings));
97110
}
98111

112+
public void testCreateCodecServiceFromFactory() {
113+
IndexMetadata meta = IndexMetadata.builder("test")
114+
.settings(settings(Version.CURRENT))
115+
.numberOfShards(1)
116+
.numberOfReplicas(1)
117+
.build();
118+
List<EnginePlugin> plugins = Arrays.asList(new BakEnginePlugin());
119+
IndexSettings indexSettings = IndexSettingsModule.newIndexSettings("test", meta.getSettings());
120+
121+
EngineConfigFactory factory = new EngineConfigFactory(plugins, indexSettings);
122+
EngineConfig config = factory.newEngineConfig(
123+
null,
124+
null,
125+
indexSettings,
126+
null,
127+
null,
128+
null,
129+
null,
130+
null,
131+
null,
132+
null,
133+
null,
134+
null,
135+
null,
136+
TimeValue.timeValueMinutes(5),
137+
null,
138+
null,
139+
null,
140+
null,
141+
null,
142+
() -> new RetentionLeases(0, 0, Collections.emptyList()),
143+
null,
144+
null
145+
);
146+
assertNotNull(config.getCodec());
147+
}
148+
99149
private static class FooEnginePlugin extends Plugin implements EnginePlugin {
100150
@Override
101151
public Optional<EngineFactory> getEngineFactory(final IndexSettings indexSettings) {
@@ -125,6 +175,18 @@ public Optional<CodecService> getCustomCodecService(IndexSettings indexSettings)
125175
}
126176
}
127177

178+
private static class BakEnginePlugin extends Plugin implements EnginePlugin {
179+
@Override
180+
public Optional<EngineFactory> getEngineFactory(final IndexSettings indexSettings) {
181+
return Optional.empty();
182+
}
183+
184+
@Override
185+
public Optional<CodecServiceFactory> getCustomCodecServiceFactory(IndexSettings indexSettings) {
186+
return Optional.of(config -> new CodecService(config.getMapperService(), LogManager.getLogger(getClass())));
187+
}
188+
}
189+
128190
private static class BazEnginePlugin extends Plugin implements EnginePlugin {
129191
@Override
130192
public Optional<EngineFactory> getEngineFactory(final IndexSettings indexSettings) {

0 commit comments

Comments
 (0)