-
Notifications
You must be signed in to change notification settings - Fork 25.2k
synthetic source index setting provider should check source field mapper #113522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
727e359
e426d0e
0e7422b
6bd4d67
348352a
fa39345
aaec9f8
e685c6c
087aa69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,28 +9,41 @@ | |
|
||
import org.apache.logging.log4j.LogManager; | ||
import org.apache.logging.log4j.Logger; | ||
import org.elasticsearch.cluster.metadata.IndexMetadata; | ||
import org.elasticsearch.cluster.metadata.Metadata; | ||
import org.elasticsearch.common.UUIDs; | ||
import org.elasticsearch.common.compress.CompressedXContent; | ||
import org.elasticsearch.common.settings.Settings; | ||
import org.elasticsearch.core.CheckedFunction; | ||
import org.elasticsearch.index.IndexMode; | ||
import org.elasticsearch.index.IndexSettingProvider; | ||
import org.elasticsearch.index.IndexSettings; | ||
import org.elasticsearch.index.IndexVersion; | ||
import org.elasticsearch.index.mapper.MapperService; | ||
|
||
import java.io.IOException; | ||
import java.io.UncheckedIOException; | ||
import java.time.Instant; | ||
import java.util.List; | ||
import java.util.Locale; | ||
|
||
import static org.elasticsearch.cluster.metadata.IndexMetadata.INDEX_ROUTING_PATH; | ||
|
||
/** | ||
* An index setting provider that overwrites the source mode from synthetic to stored if synthetic source isn't allowed to be used. | ||
*/ | ||
public class SyntheticSourceIndexSettingsProvider implements IndexSettingProvider { | ||
final class SyntheticSourceIndexSettingsProvider implements IndexSettingProvider { | ||
|
||
private static final Logger LOGGER = LogManager.getLogger(SyntheticSourceIndexSettingsProvider.class); | ||
|
||
private final SyntheticSourceLicenseService syntheticSourceLicenseService; | ||
private final CheckedFunction<IndexMetadata, MapperService, IOException> mapperServiceFactory; | ||
|
||
public SyntheticSourceIndexSettingsProvider(SyntheticSourceLicenseService syntheticSourceLicenseService) { | ||
SyntheticSourceIndexSettingsProvider( | ||
SyntheticSourceLicenseService syntheticSourceLicenseService, | ||
CheckedFunction<IndexMetadata, MapperService, IOException> mapperServiceFactory | ||
) { | ||
this.syntheticSourceLicenseService = syntheticSourceLicenseService; | ||
this.mapperServiceFactory = mapperServiceFactory; | ||
} | ||
|
||
@Override | ||
|
@@ -43,19 +56,68 @@ public Settings getAdditionalIndexSettings( | |
Settings indexTemplateAndCreateRequestSettings, | ||
List<CompressedXContent> combinedTemplateMappings | ||
) { | ||
if (newIndexHasSyntheticSourceUsage(indexTemplateAndCreateRequestSettings) | ||
if (newIndexHasSyntheticSourceUsage(indexName, isTimeSeries, indexTemplateAndCreateRequestSettings, combinedTemplateMappings) | ||
&& syntheticSourceLicenseService.fallbackToStoredSource()) { | ||
LOGGER.debug("creation of index [{}] with synthetic source without it being allowed", indexName); | ||
// TODO: handle falling back to stored source | ||
} | ||
return Settings.EMPTY; | ||
} | ||
|
||
boolean newIndexHasSyntheticSourceUsage(Settings indexTemplateAndCreateRequestSettings) { | ||
// TODO: build tmp MapperService and check whether SourceFieldMapper#isSynthetic() to determine synthetic source usage. | ||
// Not using IndexSettings.MODE.get() to avoid validation that may fail at this point. | ||
var rawIndexMode = indexTemplateAndCreateRequestSettings.get(IndexSettings.MODE.getKey()); | ||
IndexMode indexMode = rawIndexMode != null ? Enum.valueOf(IndexMode.class, rawIndexMode.toUpperCase(Locale.ROOT)) : null; | ||
return indexMode != null && indexMode.isSyntheticSourceEnabled(); | ||
boolean newIndexHasSyntheticSourceUsage( | ||
String indexName, | ||
boolean isTimeSeries, | ||
Settings indexTemplateAndCreateRequestSettings, | ||
List<CompressedXContent> combinedTemplateMappings | ||
) { | ||
if ("validate-index-name".equals(indexName)) { | ||
// This index name is used when validating component and index templates, we should skip this check in that case. | ||
// (See MetadataIndexTemplateService#validateIndexTemplateV2(...) method) | ||
return false; | ||
} | ||
|
||
var tmpIndexMetadata = buildIndexMetadataForMapperService(indexName, isTimeSeries, indexTemplateAndCreateRequestSettings); | ||
try (var mapperService = mapperServiceFactory.apply(tmpIndexMetadata)) { | ||
// combinedTemplateMappings can be null when creating system indices | ||
// combinedTemplateMappings can be empty when creating a normal index that doesn't match any template and without mapping. | ||
if (combinedTemplateMappings == null || combinedTemplateMappings.isEmpty()) { | ||
combinedTemplateMappings = List.of(new CompressedXContent("{}")); | ||
} | ||
mapperService.merge(MapperService.SINGLE_MAPPING_NAME, combinedTemplateMappings, MapperService.MergeReason.INDEX_TEMPLATE); | ||
return mapperService.documentMapper().sourceMapper().isSynthetic(); | ||
} catch (IOException e) { | ||
throw new UncheckedIOException(e); | ||
} | ||
} | ||
|
||
// Create a dummy IndexMetadata instance that can be used to create a MapperService in order to check whether synthetic source is used: | ||
private IndexMetadata buildIndexMetadataForMapperService( | ||
String indexName, | ||
boolean isTimeSeries, | ||
Settings indexTemplateAndCreateRequestSettings | ||
) { | ||
var tmpIndexMetadata = IndexMetadata.builder(indexName); | ||
|
||
int dummyPartitionSize = IndexMetadata.INDEX_ROUTING_PARTITION_SIZE_SETTING.get(indexTemplateAndCreateRequestSettings); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would probably create a method like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 makes sense |
||
int dummyShards = indexTemplateAndCreateRequestSettings.getAsInt( | ||
IndexMetadata.SETTING_NUMBER_OF_SHARDS, | ||
dummyPartitionSize == 1 ? 1 : dummyPartitionSize + 1 | ||
); | ||
int shardReplicas = indexTemplateAndCreateRequestSettings.getAsInt(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0); | ||
var finalResolvedSettings = Settings.builder() | ||
.put(IndexMetadata.SETTING_VERSION_CREATED, IndexVersion.current()) | ||
.put(indexTemplateAndCreateRequestSettings) | ||
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, dummyShards) | ||
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, shardReplicas) | ||
.put(IndexMetadata.SETTING_INDEX_UUID, UUIDs.randomBase64UUID()); | ||
|
||
if (isTimeSeries) { | ||
finalResolvedSettings.put(IndexSettings.MODE.getKey(), IndexMode.TIME_SERIES); | ||
// Avoid failing because index.routing_path is missing (in case fields are marked as dimension) | ||
finalResolvedSettings.putList(INDEX_ROUTING_PATH.getKey(), List.of("path")); | ||
} | ||
|
||
tmpIndexMetadata.settings(finalResolvedSettings); | ||
return tmpIndexMetadata.build(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the core of the change: instead of checking the index.mode setting, this now uses
SourceFieldMapper#isSynthetic()
to determine synthetic source usage..