Skip to content

Commit 91582e7

Browse files
authored
Introduce remote store path type in customData in IndexMetadata (opensearch-project#12607)
Signed-off-by: Ashish Singh <ssashish@amazon.com>
1 parent dda3e3d commit 91582e7

File tree

7 files changed

+201
-9
lines changed

7 files changed

+201
-9
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
@@ -88,6 +88,8 @@
8888
import org.opensearch.index.mapper.MapperService;
8989
import org.opensearch.index.mapper.MapperService.MergeReason;
9090
import org.opensearch.index.query.QueryShardContext;
91+
import org.opensearch.index.remote.RemoteStorePathResolver;
92+
import org.opensearch.index.remote.RemoteStorePathType;
9193
import org.opensearch.index.shard.IndexSettingProvider;
9294
import org.opensearch.index.translog.Translog;
9395
import org.opensearch.indices.IndexCreationException;
@@ -167,6 +169,9 @@ public class MetadataCreateIndexService {
167169
private final ClusterManagerTaskThrottler.ThrottlingKey createIndexTaskKey;
168170
private AwarenessReplicaBalance awarenessReplicaBalance;
169171

172+
@Nullable
173+
private final RemoteStorePathResolver remoteStorePathResolver;
174+
170175
public MetadataCreateIndexService(
171176
final Settings settings,
172177
final ClusterService clusterService,
@@ -198,6 +203,9 @@ public MetadataCreateIndexService(
198203

199204
// Task is onboarded for throttling, it will get retried from associated TransportClusterManagerNodeAction.
200205
createIndexTaskKey = clusterService.registerClusterManagerTask(ClusterManagerTaskKeys.CREATE_INDEX_KEY, true);
206+
remoteStorePathResolver = isRemoteDataAttributePresent(settings)
207+
? new RemoteStorePathResolver(clusterService.getClusterSettings())
208+
: null;
201209
}
202210

203211
/**
@@ -498,7 +506,8 @@ private ClusterState applyCreateIndexWithTemporaryService(
498506
temporaryIndexMeta.getSettings(),
499507
temporaryIndexMeta.getRoutingNumShards(),
500508
sourceMetadata,
501-
temporaryIndexMeta.isSystem()
509+
temporaryIndexMeta.isSystem(),
510+
temporaryIndexMeta.getCustomData()
502511
);
503512
} catch (Exception e) {
504513
logger.info("failed to build index metadata [{}]", request.index());
@@ -522,10 +531,11 @@ private ClusterState applyCreateIndexWithTemporaryService(
522531

523532
/**
524533
* Given a state and index settings calculated after applying templates, validate metadata for
525-
* the new index, returning an {@link IndexMetadata} for the new index
534+
* the new index, returning an {@link IndexMetadata} for the new index.
535+
* <p>
536+
* The access level of the method changed to default level for visibility to test.
526537
*/
527-
private IndexMetadata buildAndValidateTemporaryIndexMetadata(
528-
final ClusterState currentState,
538+
IndexMetadata buildAndValidateTemporaryIndexMetadata(
529539
final Settings aggregatedIndexSettings,
530540
final CreateIndexClusterStateUpdateRequest request,
531541
final int routingNumShards
@@ -544,6 +554,11 @@ private IndexMetadata buildAndValidateTemporaryIndexMetadata(
544554
tmpImdBuilder.settings(indexSettings);
545555
tmpImdBuilder.system(isSystem);
546556

557+
if (remoteStorePathResolver != null) {
558+
String pathType = remoteStorePathResolver.resolveType().toString();
559+
tmpImdBuilder.putCustom(IndexMetadata.REMOTE_STORE_CUSTOM_KEY, Map.of(RemoteStorePathType.NAME, pathType));
560+
}
561+
547562
// Set up everything, now locally create the index to see that things are ok, and apply
548563
IndexMetadata tempMetadata = tmpImdBuilder.build();
549564
validateActiveShardCount(request.waitForActiveShards(), tempMetadata);
@@ -582,7 +597,7 @@ private ClusterState applyCreateIndexRequestWithV1Templates(
582597
clusterService.getClusterSettings()
583598
);
584599
int routingNumShards = getIndexNumberOfRoutingShards(aggregatedIndexSettings, null);
585-
IndexMetadata tmpImd = buildAndValidateTemporaryIndexMetadata(currentState, aggregatedIndexSettings, request, routingNumShards);
600+
IndexMetadata tmpImd = buildAndValidateTemporaryIndexMetadata(aggregatedIndexSettings, request, routingNumShards);
586601

587602
return applyCreateIndexWithTemporaryService(
588603
currentState,
@@ -647,7 +662,7 @@ private ClusterState applyCreateIndexRequestWithV2Template(
647662
clusterService.getClusterSettings()
648663
);
649664
int routingNumShards = getIndexNumberOfRoutingShards(aggregatedIndexSettings, null);
650-
IndexMetadata tmpImd = buildAndValidateTemporaryIndexMetadata(currentState, aggregatedIndexSettings, request, routingNumShards);
665+
IndexMetadata tmpImd = buildAndValidateTemporaryIndexMetadata(aggregatedIndexSettings, request, routingNumShards);
651666

652667
return applyCreateIndexWithTemporaryService(
653668
currentState,
@@ -728,7 +743,7 @@ private ClusterState applyCreateIndexRequestWithExistingMetadata(
728743
clusterService.getClusterSettings()
729744
);
730745
final int routingNumShards = getIndexNumberOfRoutingShards(aggregatedIndexSettings, sourceMetadata);
731-
IndexMetadata tmpImd = buildAndValidateTemporaryIndexMetadata(currentState, aggregatedIndexSettings, request, routingNumShards);
746+
IndexMetadata tmpImd = buildAndValidateTemporaryIndexMetadata(aggregatedIndexSettings, request, routingNumShards);
732747

733748
return applyCreateIndexWithTemporaryService(
734749
currentState,
@@ -1147,7 +1162,8 @@ static IndexMetadata buildIndexMetadata(
11471162
Settings indexSettings,
11481163
int routingNumShards,
11491164
@Nullable IndexMetadata sourceMetadata,
1150-
boolean isSystem
1165+
boolean isSystem,
1166+
Map<String, DiffableStringMap> customData
11511167
) {
11521168
IndexMetadata.Builder indexMetadataBuilder = createIndexMetadataBuilder(indexName, sourceMetadata, indexSettings, routingNumShards);
11531169
indexMetadataBuilder.system(isSystem);
@@ -1168,6 +1184,10 @@ static IndexMetadata buildIndexMetadata(
11681184
indexMetadataBuilder.putAlias(aliases.get(i));
11691185
}
11701186

1187+
for (Map.Entry<String, DiffableStringMap> entry : customData.entrySet()) {
1188+
indexMetadataBuilder.putCustom(entry.getKey(), entry.getValue());
1189+
}
1190+
11711191
indexMetadataBuilder.state(IndexMetadata.State.OPEN);
11721192
return indexMetadataBuilder.build();
11731193
}

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

+2
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,8 @@ public void apply(Settings value, Settings current, Settings previous) {
713713
IoBasedAdmissionControllerSettings.SEARCH_IO_USAGE_LIMIT,
714714
IoBasedAdmissionControllerSettings.INDEXING_IO_USAGE_LIMIT,
715715
IndicesService.CLUSTER_INDEX_RESTRICT_REPLICATION_TYPE_SETTING,
716+
IndicesService.CLUSTER_REMOTE_STORE_PATH_PREFIX_TYPE_SETTING,
717+
716718
// Concurrent segment search settings
717719
SearchService.CLUSTER_CONCURRENT_SEGMENT_SEARCH_SETTING,
718720
SearchService.CONCURRENT_SEGMENT_SEARCH_TARGET_MAX_SLICE_COUNT_SETTING
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
@@ -123,6 +123,7 @@
123123
import org.opensearch.index.query.QueryRewriteContext;
124124
import org.opensearch.index.recovery.RecoveryStats;
125125
import org.opensearch.index.refresh.RefreshStats;
126+
import org.opensearch.index.remote.RemoteStorePathType;
126127
import org.opensearch.index.remote.RemoteStoreStatsTrackerFactory;
127128
import org.opensearch.index.search.stats.SearchStats;
128129
import org.opensearch.index.seqno.RetentionLeaseStats;
@@ -313,6 +314,18 @@ public class IndicesService extends AbstractLifecycleComponent
313314
Property.Final
314315
);
315316

317+
/**
318+
* This setting is used to set the remote store blob store path prefix strategy. This setting is effective only for
319+
* remote store enabled cluster.
320+
*/
321+
public static final Setting<RemoteStorePathType> CLUSTER_REMOTE_STORE_PATH_PREFIX_TYPE_SETTING = new Setting<>(
322+
"cluster.remote_store.index.path.prefix.type",
323+
RemoteStorePathType.FIXED.toString(),
324+
RemoteStorePathType::parseString,
325+
Property.NodeScope,
326+
Property.Dynamic
327+
);
328+
316329
/**
317330
* The node's settings.
318331
*/

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

+91-1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import org.opensearch.index.IndexSettings;
7272
import org.opensearch.index.mapper.MapperService;
7373
import org.opensearch.index.query.QueryShardContext;
74+
import org.opensearch.index.remote.RemoteStorePathType;
7475
import org.opensearch.index.translog.Translog;
7576
import org.opensearch.indices.IndexCreationException;
7677
import org.opensearch.indices.IndicesService;
@@ -1563,13 +1564,102 @@ public void testBuildIndexMetadata() {
15631564
.put(SETTING_NUMBER_OF_SHARDS, 1)
15641565
.build();
15651566
List<AliasMetadata> aliases = singletonList(AliasMetadata.builder("alias1").build());
1566-
IndexMetadata indexMetadata = buildIndexMetadata("test", aliases, () -> null, indexSettings, 4, sourceIndexMetadata, false);
1567+
IndexMetadata indexMetadata = buildIndexMetadata(
1568+
"test",
1569+
aliases,
1570+
() -> null,
1571+
indexSettings,
1572+
4,
1573+
sourceIndexMetadata,
1574+
false,
1575+
new HashMap<>()
1576+
);
15671577

15681578
assertThat(indexMetadata.getAliases().size(), is(1));
15691579
assertThat(indexMetadata.getAliases().keySet().iterator().next(), is("alias1"));
15701580
assertThat("The source index primary term must be used", indexMetadata.primaryTerm(0), is(3L));
15711581
}
15721582

1583+
/**
1584+
* This test checks if the cluster is a remote store cluster then we populate custom data for remote settings in
1585+
* index metadata of the underlying index. This captures information around the resolution pattern of the path for
1586+
* remote segments and translog.
1587+
*/
1588+
public void testRemoteCustomData() {
1589+
// Case 1 - Remote store is not enabled
1590+
IndexMetadata indexMetadata = testRemoteCustomData(false, randomFrom(RemoteStorePathType.values()));
1591+
assertNull(indexMetadata.getCustomData(IndexMetadata.REMOTE_STORE_CUSTOM_KEY));
1592+
1593+
// Case 2 - cluster.remote_store.index.path.prefix.optimised=fixed (default value)
1594+
indexMetadata = testRemoteCustomData(true, RemoteStorePathType.FIXED);
1595+
validateRemoteCustomData(
1596+
indexMetadata.getCustomData(IndexMetadata.REMOTE_STORE_CUSTOM_KEY),
1597+
RemoteStorePathType.NAME,
1598+
RemoteStorePathType.FIXED.toString()
1599+
);
1600+
1601+
// Case 3 - cluster.remote_store.index.path.prefix.optimised=hashed_prefix
1602+
indexMetadata = testRemoteCustomData(true, RemoteStorePathType.HASHED_PREFIX);
1603+
validateRemoteCustomData(
1604+
indexMetadata.getCustomData(IndexMetadata.REMOTE_STORE_CUSTOM_KEY),
1605+
RemoteStorePathType.NAME,
1606+
RemoteStorePathType.HASHED_PREFIX.toString()
1607+
);
1608+
}
1609+
1610+
private IndexMetadata testRemoteCustomData(boolean remoteStoreEnabled, RemoteStorePathType remoteStorePathType) {
1611+
Settings.Builder settingsBuilder = Settings.builder();
1612+
if (remoteStoreEnabled) {
1613+
settingsBuilder.put(NODE_ATTRIBUTES.getKey() + REMOTE_STORE_SEGMENT_REPOSITORY_NAME_ATTRIBUTE_KEY, "test");
1614+
}
1615+
settingsBuilder.put(IndicesService.CLUSTER_REMOTE_STORE_PATH_PREFIX_TYPE_SETTING.getKey(), remoteStorePathType.toString());
1616+
Settings settings = settingsBuilder.build();
1617+
1618+
ClusterService clusterService = mock(ClusterService.class);
1619+
Metadata metadata = Metadata.builder()
1620+
.transientSettings(Settings.builder().put(Metadata.DEFAULT_REPLICA_COUNT_SETTING.getKey(), 1).build())
1621+
.build();
1622+
ClusterState clusterState = ClusterState.builder(org.opensearch.cluster.ClusterName.CLUSTER_NAME_SETTING.getDefault(Settings.EMPTY))
1623+
.metadata(metadata)
1624+
.build();
1625+
ClusterSettings clusterSettings = new ClusterSettings(settings, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
1626+
when(clusterService.getSettings()).thenReturn(settings);
1627+
when(clusterService.getClusterSettings()).thenReturn(clusterSettings);
1628+
when(clusterService.state()).thenReturn(clusterState);
1629+
1630+
ThreadPool threadPool = new TestThreadPool(getTestName());
1631+
MetadataCreateIndexService metadataCreateIndexService = new MetadataCreateIndexService(
1632+
settings,
1633+
clusterService,
1634+
null,
1635+
null,
1636+
null,
1637+
createTestShardLimitService(randomIntBetween(1, 1000), false, clusterService),
1638+
new Environment(Settings.builder().put("path.home", "dummy").build(), null),
1639+
IndexScopedSettings.DEFAULT_SCOPED_SETTINGS,
1640+
threadPool,
1641+
null,
1642+
new SystemIndices(Collections.emptyMap()),
1643+
true,
1644+
new AwarenessReplicaBalance(settings, clusterService.getClusterSettings())
1645+
);
1646+
CreateIndexClusterStateUpdateRequest request = new CreateIndexClusterStateUpdateRequest("create index", "test", "test");
1647+
Settings indexSettings = Settings.builder()
1648+
.put("index.version.created", Version.CURRENT)
1649+
.put(INDEX_NUMBER_OF_SHARDS_SETTING.getKey(), 3)
1650+
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 1)
1651+
.build();
1652+
1653+
IndexMetadata indexMetadata = metadataCreateIndexService.buildAndValidateTemporaryIndexMetadata(indexSettings, request, 0);
1654+
threadPool.shutdown();
1655+
return indexMetadata;
1656+
}
1657+
1658+
private void validateRemoteCustomData(Map<String, String> customData, String expectedKey, String expectedValue) {
1659+
assertTrue(customData.containsKey(expectedKey));
1660+
assertEquals(expectedValue, customData.get(expectedKey));
1661+
}
1662+
15731663
public void testGetIndexNumberOfRoutingShardsWithNullSourceIndex() {
15741664
Settings indexSettings = Settings.builder()
15751665
.put("index.version.created", Version.CURRENT)

0 commit comments

Comments
 (0)