Skip to content

Commit 636c35c

Browse files
authored
Introduce remote store path type in customData in IndexMetadata (#12607) (#13390)
Signed-off-by: Ashish Singh <ssashish@amazon.com>
1 parent 1b8cba3 commit 636c35c

File tree

7 files changed

+207
-15
lines changed

7 files changed

+207
-15
lines changed

server/src/main/java/org/opensearch/cluster/metadata/IndexMetadata.java

+1
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ public static APIBlock readFrom(StreamInput input) throws IOException {
635635
static final String KEY_ROLLOVER_INFOS = "rollover_info";
636636
static final String KEY_SYSTEM = "system";
637637
public static final String KEY_PRIMARY_TERMS = "primary_terms";
638+
public static final String REMOTE_STORE_CUSTOM_KEY = "remote_store";
638639

639640
public static final String INDEX_STATE_FILE_PREFIX = "state-";
640641

server/src/main/java/org/opensearch/cluster/metadata/MetadataCreateIndexService.java

+28-8
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@
9090
import org.opensearch.index.mapper.MapperService;
9191
import org.opensearch.index.mapper.MapperService.MergeReason;
9292
import org.opensearch.index.query.QueryShardContext;
93+
import org.opensearch.index.remote.RemoteStorePathResolver;
94+
import org.opensearch.index.remote.RemoteStorePathType;
9395
import org.opensearch.index.shard.IndexSettingProvider;
9496
import org.opensearch.index.translog.Translog;
9597
import org.opensearch.indices.IndexCreationException;
@@ -171,6 +173,9 @@ public class MetadataCreateIndexService {
171173
private final ClusterManagerTaskThrottler.ThrottlingKey createIndexTaskKey;
172174
private AwarenessReplicaBalance awarenessReplicaBalance;
173175

176+
@Nullable
177+
private final RemoteStorePathResolver remoteStorePathResolver;
178+
174179
public MetadataCreateIndexService(
175180
final Settings settings,
176181
final ClusterService clusterService,
@@ -202,6 +207,9 @@ public MetadataCreateIndexService(
202207

203208
// Task is onboarded for throttling, it will get retried from associated TransportClusterManagerNodeAction.
204209
createIndexTaskKey = clusterService.registerClusterManagerTask(ClusterManagerTaskKeys.CREATE_INDEX_KEY, true);
210+
remoteStorePathResolver = isRemoteDataAttributePresent(settings)
211+
? new RemoteStorePathResolver(clusterService.getClusterSettings())
212+
: null;
205213
}
206214

207215
/**
@@ -502,7 +510,8 @@ private ClusterState applyCreateIndexWithTemporaryService(
502510
temporaryIndexMeta.getSettings(),
503511
temporaryIndexMeta.getRoutingNumShards(),
504512
sourceMetadata,
505-
temporaryIndexMeta.isSystem()
513+
temporaryIndexMeta.isSystem(),
514+
temporaryIndexMeta.getCustomData()
506515
);
507516
} catch (Exception e) {
508517
logger.info("failed to build index metadata [{}]", request.index());
@@ -526,10 +535,11 @@ private ClusterState applyCreateIndexWithTemporaryService(
526535

527536
/**
528537
* Given a state and index settings calculated after applying templates, validate metadata for
529-
* the new index, returning an {@link IndexMetadata} for the new index
538+
* the new index, returning an {@link IndexMetadata} for the new index.
539+
* <p>
540+
* The access level of the method changed to default level for visibility to test.
530541
*/
531-
private IndexMetadata buildAndValidateTemporaryIndexMetadata(
532-
final ClusterState currentState,
542+
IndexMetadata buildAndValidateTemporaryIndexMetadata(
533543
final Settings aggregatedIndexSettings,
534544
final CreateIndexClusterStateUpdateRequest request,
535545
final int routingNumShards
@@ -548,6 +558,11 @@ private IndexMetadata buildAndValidateTemporaryIndexMetadata(
548558
tmpImdBuilder.settings(indexSettings);
549559
tmpImdBuilder.system(isSystem);
550560

561+
if (remoteStorePathResolver != null) {
562+
String pathType = remoteStorePathResolver.resolveType().toString();
563+
tmpImdBuilder.putCustom(IndexMetadata.REMOTE_STORE_CUSTOM_KEY, Map.of(RemoteStorePathType.NAME, pathType));
564+
}
565+
551566
// Set up everything, now locally create the index to see that things are ok, and apply
552567
IndexMetadata tempMetadata = tmpImdBuilder.build();
553568
validateActiveShardCount(request.waitForActiveShards(), tempMetadata);
@@ -586,7 +601,7 @@ private ClusterState applyCreateIndexRequestWithV1Templates(
586601
clusterService.getClusterSettings()
587602
);
588603
int routingNumShards = getIndexNumberOfRoutingShards(aggregatedIndexSettings, null);
589-
IndexMetadata tmpImd = buildAndValidateTemporaryIndexMetadata(currentState, aggregatedIndexSettings, request, routingNumShards);
604+
IndexMetadata tmpImd = buildAndValidateTemporaryIndexMetadata(aggregatedIndexSettings, request, routingNumShards);
590605

591606
return applyCreateIndexWithTemporaryService(
592607
currentState,
@@ -651,7 +666,7 @@ private ClusterState applyCreateIndexRequestWithV2Template(
651666
clusterService.getClusterSettings()
652667
);
653668
int routingNumShards = getIndexNumberOfRoutingShards(aggregatedIndexSettings, null);
654-
IndexMetadata tmpImd = buildAndValidateTemporaryIndexMetadata(currentState, aggregatedIndexSettings, request, routingNumShards);
669+
IndexMetadata tmpImd = buildAndValidateTemporaryIndexMetadata(aggregatedIndexSettings, request, routingNumShards);
655670

656671
return applyCreateIndexWithTemporaryService(
657672
currentState,
@@ -732,7 +747,7 @@ private ClusterState applyCreateIndexRequestWithExistingMetadata(
732747
clusterService.getClusterSettings()
733748
);
734749
final int routingNumShards = getIndexNumberOfRoutingShards(aggregatedIndexSettings, sourceMetadata);
735-
IndexMetadata tmpImd = buildAndValidateTemporaryIndexMetadata(currentState, aggregatedIndexSettings, request, routingNumShards);
750+
IndexMetadata tmpImd = buildAndValidateTemporaryIndexMetadata(aggregatedIndexSettings, request, routingNumShards);
736751

737752
return applyCreateIndexWithTemporaryService(
738753
currentState,
@@ -1203,7 +1218,8 @@ static IndexMetadata buildIndexMetadata(
12031218
Settings indexSettings,
12041219
int routingNumShards,
12051220
@Nullable IndexMetadata sourceMetadata,
1206-
boolean isSystem
1221+
boolean isSystem,
1222+
Map<String, DiffableStringMap> customData
12071223
) {
12081224
IndexMetadata.Builder indexMetadataBuilder = createIndexMetadataBuilder(indexName, sourceMetadata, indexSettings, routingNumShards);
12091225
indexMetadataBuilder.system(isSystem);
@@ -1224,6 +1240,10 @@ static IndexMetadata buildIndexMetadata(
12241240
indexMetadataBuilder.putAlias(aliases.get(i));
12251241
}
12261242

1243+
for (Map.Entry<String, DiffableStringMap> entry : customData.entrySet()) {
1244+
indexMetadataBuilder.putCustom(entry.getKey(), entry.getValue());
1245+
}
1246+
12271247
indexMetadataBuilder.state(IndexMetadata.State.OPEN);
12281248
return indexMetadataBuilder.build();
12291249
}

server/src/main/java/org/opensearch/common/settings/ClusterSettings.java

+8-6
Original file line numberDiff line numberDiff line change
@@ -714,12 +714,8 @@ public void apply(Settings value, Settings current, Settings previous) {
714714
RemoteStoreNodeService.REMOTE_STORE_COMPATIBILITY_MODE_SETTING,
715715
RemoteStoreNodeService.MIGRATION_DIRECTION_SETTING,
716716

717-
IndicesService.CLUSTER_INDEX_RESTRICT_REPLICATION_TYPE_SETTING,
718717
IndicesService.CLUSTER_REMOTE_INDEX_RESTRICT_ASYNC_DURABILITY_SETTING,
719-
720-
// Concurrent segment search settings
721-
SearchService.CLUSTER_CONCURRENT_SEGMENT_SEARCH_SETTING,
722-
SearchService.CONCURRENT_SEGMENT_SEARCH_TARGET_MAX_SLICE_COUNT_SETTING,
718+
IndicesService.CLUSTER_INDEX_RESTRICT_REPLICATION_TYPE_SETTING,
723719

724720
AdmissionControlSettings.ADMISSION_CONTROL_TRANSPORT_LAYER_MODE,
725721
CpuBasedAdmissionControllerSettings.CPU_BASED_ADMISSION_CONTROLLER_TRANSPORT_LAYER_MODE,
@@ -730,8 +726,14 @@ public void apply(Settings value, Settings current, Settings previous) {
730726
IoBasedAdmissionControllerSettings.SEARCH_IO_USAGE_LIMIT,
731727
IoBasedAdmissionControllerSettings.INDEXING_IO_USAGE_LIMIT,
732728

729+
// Concurrent segment search settings
730+
SearchService.CLUSTER_CONCURRENT_SEGMENT_SEARCH_SETTING,
731+
SearchService.CONCURRENT_SEGMENT_SEARCH_TARGET_MAX_SLICE_COUNT_SETTING,
732+
733733
RemoteStoreSettings.CLUSTER_REMOTE_INDEX_SEGMENT_METADATA_RETENTION_MAX_COUNT_SETTING,
734-
RemoteStoreSettings.CLUSTER_REMOTE_TRANSLOG_BUFFER_INTERVAL_SETTING
734+
RemoteStoreSettings.CLUSTER_REMOTE_TRANSLOG_BUFFER_INTERVAL_SETTING,
735+
IndicesService.CLUSTER_REMOTE_STORE_PATH_PREFIX_TYPE_SETTING
736+
735737
)
736738
)
737739
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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.remote;
10+
11+
import org.opensearch.common.settings.ClusterSettings;
12+
import org.opensearch.indices.IndicesService;
13+
14+
/**
15+
* Determines the {@link RemoteStorePathType} at the time of index metadata creation.
16+
*
17+
* @opensearch.internal
18+
*/
19+
public class RemoteStorePathResolver {
20+
21+
private final ClusterSettings clusterSettings;
22+
23+
public RemoteStorePathResolver(ClusterSettings clusterSettings) {
24+
this.clusterSettings = clusterSettings;
25+
}
26+
27+
public RemoteStorePathType resolveType() {
28+
return clusterSettings.get(IndicesService.CLUSTER_REMOTE_STORE_PATH_PREFIX_TYPE_SETTING);
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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.remote;
10+
11+
import java.util.Locale;
12+
13+
/**
14+
* Enumerates the types of remote store paths resolution techniques supported by OpenSearch.
15+
* For more information, see <a href="https://github.com/opensearch-project/OpenSearch/issues/12567">Github issue #12567</a>.
16+
*
17+
* @opensearch.internal
18+
*/
19+
public enum RemoteStorePathType {
20+
21+
FIXED,
22+
HASHED_PREFIX;
23+
24+
public static RemoteStorePathType parseString(String remoteStoreBlobPathType) {
25+
try {
26+
return RemoteStorePathType.valueOf(remoteStoreBlobPathType.toUpperCase(Locale.ROOT));
27+
} catch (IllegalArgumentException e) {
28+
throw new IllegalArgumentException("Could not parse RemoteStorePathType for [" + remoteStoreBlobPathType + "]");
29+
}
30+
}
31+
32+
/**
33+
* This string is used as key for storing information in the custom data in index settings.
34+
*/
35+
public static final String NAME = "path_type";
36+
}

server/src/main/java/org/opensearch/indices/IndicesService.java

+13
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@
126126
import org.opensearch.index.query.QueryRewriteContext;
127127
import org.opensearch.index.recovery.RecoveryStats;
128128
import org.opensearch.index.refresh.RefreshStats;
129+
import org.opensearch.index.remote.RemoteStorePathType;
129130
import org.opensearch.index.remote.RemoteStoreStatsTrackerFactory;
130131
import org.opensearch.index.search.stats.SearchStats;
131132
import org.opensearch.index.seqno.RetentionLeaseStats;
@@ -307,6 +308,18 @@ public class IndicesService extends AbstractLifecycleComponent
307308
Property.Final
308309
);
309310

311+
/**
312+
* This setting is used to set the remote store blob store path prefix strategy. This setting is effective only for
313+
* remote store enabled cluster.
314+
*/
315+
public static final Setting<RemoteStorePathType> CLUSTER_REMOTE_STORE_PATH_PREFIX_TYPE_SETTING = new Setting<>(
316+
"cluster.remote_store.index.path.prefix.type",
317+
RemoteStorePathType.FIXED.toString(),
318+
RemoteStorePathType::parseString,
319+
Property.NodeScope,
320+
Property.Dynamic
321+
);
322+
310323
/**
311324
* The node's settings.
312325
*/

server/src/test/java/org/opensearch/cluster/metadata/MetadataCreateIndexServiceTests.java

+91-1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
import org.opensearch.index.IndexSettings;
7575
import org.opensearch.index.mapper.MapperService;
7676
import org.opensearch.index.query.QueryShardContext;
77+
import org.opensearch.index.remote.RemoteStorePathType;
7778
import org.opensearch.index.translog.Translog;
7879
import org.opensearch.indices.IndexCreationException;
7980
import org.opensearch.indices.IndicesService;
@@ -1676,13 +1677,102 @@ public void testBuildIndexMetadata() {
16761677
.put(SETTING_NUMBER_OF_SHARDS, 1)
16771678
.build();
16781679
List<AliasMetadata> aliases = singletonList(AliasMetadata.builder("alias1").build());
1679-
IndexMetadata indexMetadata = buildIndexMetadata("test", aliases, () -> null, indexSettings, 4, sourceIndexMetadata, false);
1680+
IndexMetadata indexMetadata = buildIndexMetadata(
1681+
"test",
1682+
aliases,
1683+
() -> null,
1684+
indexSettings,
1685+
4,
1686+
sourceIndexMetadata,
1687+
false,
1688+
new HashMap<>()
1689+
);
16801690

16811691
assertThat(indexMetadata.getAliases().size(), is(1));
16821692
assertThat(indexMetadata.getAliases().keySet().iterator().next(), is("alias1"));
16831693
assertThat("The source index primary term must be used", indexMetadata.primaryTerm(0), is(3L));
16841694
}
16851695

1696+
/**
1697+
* This test checks if the cluster is a remote store cluster then we populate custom data for remote settings in
1698+
* index metadata of the underlying index. This captures information around the resolution pattern of the path for
1699+
* remote segments and translog.
1700+
*/
1701+
public void testRemoteCustomData() {
1702+
// Case 1 - Remote store is not enabled
1703+
IndexMetadata indexMetadata = testRemoteCustomData(false, randomFrom(RemoteStorePathType.values()));
1704+
assertNull(indexMetadata.getCustomData(IndexMetadata.REMOTE_STORE_CUSTOM_KEY));
1705+
1706+
// Case 2 - cluster.remote_store.index.path.prefix.optimised=fixed (default value)
1707+
indexMetadata = testRemoteCustomData(true, RemoteStorePathType.FIXED);
1708+
validateRemoteCustomData(
1709+
indexMetadata.getCustomData(IndexMetadata.REMOTE_STORE_CUSTOM_KEY),
1710+
RemoteStorePathType.NAME,
1711+
RemoteStorePathType.FIXED.toString()
1712+
);
1713+
1714+
// Case 3 - cluster.remote_store.index.path.prefix.optimised=hashed_prefix
1715+
indexMetadata = testRemoteCustomData(true, RemoteStorePathType.HASHED_PREFIX);
1716+
validateRemoteCustomData(
1717+
indexMetadata.getCustomData(IndexMetadata.REMOTE_STORE_CUSTOM_KEY),
1718+
RemoteStorePathType.NAME,
1719+
RemoteStorePathType.HASHED_PREFIX.toString()
1720+
);
1721+
}
1722+
1723+
private IndexMetadata testRemoteCustomData(boolean remoteStoreEnabled, RemoteStorePathType remoteStorePathType) {
1724+
Settings.Builder settingsBuilder = Settings.builder();
1725+
if (remoteStoreEnabled) {
1726+
settingsBuilder.put(NODE_ATTRIBUTES.getKey() + REMOTE_STORE_SEGMENT_REPOSITORY_NAME_ATTRIBUTE_KEY, "test");
1727+
}
1728+
settingsBuilder.put(IndicesService.CLUSTER_REMOTE_STORE_PATH_PREFIX_TYPE_SETTING.getKey(), remoteStorePathType.toString());
1729+
Settings settings = settingsBuilder.build();
1730+
1731+
ClusterService clusterService = mock(ClusterService.class);
1732+
Metadata metadata = Metadata.builder()
1733+
.transientSettings(Settings.builder().put(Metadata.DEFAULT_REPLICA_COUNT_SETTING.getKey(), 1).build())
1734+
.build();
1735+
ClusterState clusterState = ClusterState.builder(org.opensearch.cluster.ClusterName.CLUSTER_NAME_SETTING.getDefault(Settings.EMPTY))
1736+
.metadata(metadata)
1737+
.build();
1738+
ClusterSettings clusterSettings = new ClusterSettings(settings, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
1739+
when(clusterService.getSettings()).thenReturn(settings);
1740+
when(clusterService.getClusterSettings()).thenReturn(clusterSettings);
1741+
when(clusterService.state()).thenReturn(clusterState);
1742+
1743+
ThreadPool threadPool = new TestThreadPool(getTestName());
1744+
MetadataCreateIndexService metadataCreateIndexService = new MetadataCreateIndexService(
1745+
settings,
1746+
clusterService,
1747+
null,
1748+
null,
1749+
null,
1750+
createTestShardLimitService(randomIntBetween(1, 1000), false, clusterService),
1751+
new Environment(Settings.builder().put("path.home", "dummy").build(), null),
1752+
IndexScopedSettings.DEFAULT_SCOPED_SETTINGS,
1753+
threadPool,
1754+
null,
1755+
new SystemIndices(Collections.emptyMap()),
1756+
true,
1757+
new AwarenessReplicaBalance(settings, clusterService.getClusterSettings())
1758+
);
1759+
CreateIndexClusterStateUpdateRequest request = new CreateIndexClusterStateUpdateRequest("create index", "test", "test");
1760+
Settings indexSettings = Settings.builder()
1761+
.put("index.version.created", Version.CURRENT)
1762+
.put(INDEX_NUMBER_OF_SHARDS_SETTING.getKey(), 3)
1763+
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 1)
1764+
.build();
1765+
1766+
IndexMetadata indexMetadata = metadataCreateIndexService.buildAndValidateTemporaryIndexMetadata(indexSettings, request, 0);
1767+
threadPool.shutdown();
1768+
return indexMetadata;
1769+
}
1770+
1771+
private void validateRemoteCustomData(Map<String, String> customData, String expectedKey, String expectedValue) {
1772+
assertTrue(customData.containsKey(expectedKey));
1773+
assertEquals(expectedValue, customData.get(expectedKey));
1774+
}
1775+
16861776
public void testGetIndexNumberOfRoutingShardsWithNullSourceIndex() {
16871777
Settings indexSettings = Settings.builder()
16881778
.put("index.version.created", Version.CURRENT)

0 commit comments

Comments
 (0)