/* SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * compatible open source license. */ /* * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. * * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch B.V. licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using OpenSearch.Net.Utf8Json; using static OpenSearch.Client.Specification.IndicesApi.FixedIndexSettings; using static OpenSearch.Client.Specification.IndicesApi.IndexSortSettings; using static OpenSearch.Client.Specification.IndicesApi.UpdatableIndexSettings; namespace OpenSearch.Client.Specification.IndicesApi { internal class IndexSettingsFormatter : IJsonFormatter { private static readonly DynamicIndexSettingsFormatter DynamicIndexSettingsFormatter = new DynamicIndexSettingsFormatter(); public void Serialize(ref JsonWriter writer, IIndexSettings value, IJsonFormatterResolver formatterResolver) => DynamicIndexSettingsFormatter.Serialize(ref writer, value, formatterResolver); public IIndexSettings Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) => (IIndexSettings)DynamicIndexSettingsFormatter.Deserialize(ref reader, formatterResolver); } internal class DynamicIndexSettingsFormatter : IJsonFormatter { private static readonly IndexSettingsDictionaryFormatter Formatter = new IndexSettingsDictionaryFormatter(); public IDynamicIndexSettings Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { var indexSettings = new IndexSettings(); SetKnownIndexSettings(ref reader, formatterResolver, indexSettings); return indexSettings; } public void Serialize(ref JsonWriter writer, IDynamicIndexSettings value, IJsonFormatterResolver formatterResolver) { if (value == null) { writer.WriteNull(); return; } IDictionary d = value; void Set(string knownKey, object newValue) { if (newValue != null) d[knownKey] = newValue; } Set(NumberOfReplicas, value.NumberOfReplicas); Set(RefreshInterval, value.RefreshInterval); Set(DefaultPipeline, value.DefaultPipeline); Set(FinalPipeline, value.FinalPipeline); Set(BlocksReadOnly, value.BlocksReadOnly); Set(BlocksRead, value.BlocksRead); Set(BlocksWrite, value.BlocksWrite); Set(BlocksMetadata, value.BlocksMetadata); Set(BlocksReadOnlyAllowDelete, value.BlocksReadOnlyAllowDelete); Set(Priority, value.Priority); Set(UpdatableIndexSettings.AutoExpandReplicas, value.AutoExpandReplicas); Set(UpdatableIndexSettings.RecoveryInitialShards, value.RecoveryInitialShards); Set(RequestsCacheEnable, value.RequestsCacheEnabled); Set(RoutingAllocationTotalShardsPerNode, value.RoutingAllocationTotalShardsPerNode); Set(UnassignedNodeLeftDelayedTimeout, value.UnassignedNodeLeftDelayedTimeout); var translog = value.Translog; Set(TranslogSyncInterval, translog?.SyncInterval); Set(UpdatableIndexSettings.TranslogDurability, translog?.Durability); var flush = value.Translog?.Flush; Set(TranslogFlushThresholdSize, flush?.ThresholdSize); Set(TranslogFlushThresholdPeriod, flush?.ThresholdPeriod); Set(MergePolicyExpungeDeletesAllowed, value.Merge?.Policy?.ExpungeDeletesAllowed); Set(MergePolicyFloorSegment, value.Merge?.Policy?.FloorSegment); Set(MergePolicyMaxMergeAtOnce, value.Merge?.Policy?.MaxMergeAtOnce); Set(MergePolicyMaxMergeAtOnceExplicit, value.Merge?.Policy?.MaxMergeAtOnceExplicit); Set(MergePolicyMaxMergedSegment, value.Merge?.Policy?.MaxMergedSegment); Set(MergePolicySegmentsPerTier, value.Merge?.Policy?.SegmentsPerTier); Set(MergePolicyReclaimDeletesWeight, value.Merge?.Policy?.ReclaimDeletesWeight); Set(MergeSchedulerMaxThreadCount, value.Merge?.Scheduler?.MaxThreadCount); Set(MergeSchedulerAutoThrottle, value.Merge?.Scheduler?.AutoThrottle); var log = value.SlowLog; var search = log?.Search; var indexing = log?.Indexing; Set(SlowlogSearchThresholdQueryWarn, search?.Query?.ThresholdWarn); Set(SlowlogSearchThresholdQueryInfo, search?.Query?.ThresholdInfo); Set(SlowlogSearchThresholdQueryDebug, search?.Query?.ThresholdDebug); Set(SlowlogSearchThresholdQueryTrace, search?.Query?.ThresholdTrace); Set(SlowlogSearchThresholdFetchWarn, search?.Fetch?.ThresholdWarn); Set(SlowlogSearchThresholdFetchInfo, search?.Fetch?.ThresholdInfo); Set(SlowlogSearchThresholdFetchDebug, search?.Fetch?.ThresholdDebug); Set(SlowlogSearchThresholdFetchTrace, search?.Fetch?.ThresholdTrace); Set(SlowlogSearchLevel, search?.LogLevel); Set(SlowlogIndexingThresholdFetchWarn, indexing?.ThresholdWarn); Set(SlowlogIndexingThresholdFetchInfo, indexing?.ThresholdInfo); Set(SlowlogIndexingThresholdFetchDebug, indexing?.ThresholdDebug); Set(SlowlogIndexingThresholdFetchTrace, indexing?.ThresholdTrace); Set(SlowlogIndexingLevel, indexing?.LogLevel); Set(SlowlogIndexingSource, indexing?.Source); Set(UpdatableIndexSettings.Analysis, value.Analysis); Set(Similarity, value.Similarity); if (value is IIndexSettings indexSettings) { Set(StoreType, indexSettings.FileSystemStorageImplementation); Set(QueriesCacheEnabled, indexSettings.Queries?.Cache?.Enabled); Set(NumberOfShards, indexSettings.NumberOfShards); Set(NumberOfRoutingShards, indexSettings.NumberOfRoutingShards); Set(RoutingPartitionSize, indexSettings.RoutingPartitionSize); Set(StoreType, indexSettings.FileSystemStorageImplementation); Set(QueriesCacheEnabled, indexSettings.Queries?.Cache?.Enabled); Set(NumberOfShards, indexSettings.NumberOfShards); Set(NumberOfRoutingShards, indexSettings.NumberOfRoutingShards); Set(RoutingPartitionSize, indexSettings.RoutingPartitionSize); Set(Hidden, indexSettings.Hidden); if (indexSettings.SoftDeletes != null) { Set(SoftDeletesRetentionOperations, indexSettings.SoftDeletes.Retention?.Operations); } if (indexSettings?.Sorting != null) { Set(IndexSortSettings.Fields, AsArrayOrSingleItem(indexSettings.Sorting.Fields)); Set(Order, AsArrayOrSingleItem(indexSettings.Sorting.Order)); Set(Mode, AsArrayOrSingleItem(indexSettings.Sorting.Mode)); Set(IndexSortSettings.Missing, AsArrayOrSingleItem(indexSettings.Sorting.Missing)); } } Formatter.Serialize(ref writer, d, formatterResolver); } private static object AsArrayOrSingleItem(IEnumerable items) { if (items == null || !items.Any()) return null; if (items.Count() == 1) return items.First(); return items; } private static Dictionary Flatten(Dictionary original, string prefix = "", Dictionary current = null ) { current ??= new Dictionary(); foreach (var property in original) { if (property.Value is Dictionary objects && property.Key != UpdatableIndexSettings.Analysis && property.Key != Similarity) Flatten(objects, prefix + property.Key + ".", current); else current.Add(prefix + property.Key, property.Value); } return current; } private static void SetKnownIndexSettings(ref JsonReader reader, IJsonFormatterResolver formatterResolver, IIndexSettings s) { // TODO: Ugly. Could use dynamic dictionary here, and use get traversal logic var formatter = formatterResolver.GetFormatter>(); var settings = Flatten(formatter.Deserialize(ref reader, formatterResolver)); Set(s, settings, NumberOfReplicas, v => s.NumberOfReplicas = v, formatterResolver); Set(s, settings, UpdatableIndexSettings.AutoExpandReplicas, v => s.AutoExpandReplicas = v, formatterResolver); Set