Skip to content

Commit 4163aa1

Browse files

File tree

12 files changed

+508
-131
lines changed

12 files changed

+508
-131
lines changed
 

‎server/src/internalClusterTest/java/org/opensearch/remotestore/RemoteRestoreSnapshotIT.java

+41-5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.opensearch.client.Requests;
1919
import org.opensearch.cluster.ClusterState;
2020
import org.opensearch.cluster.metadata.IndexMetadata;
21+
import org.opensearch.common.Nullable;
2122
import org.opensearch.common.io.PathUtils;
2223
import org.opensearch.common.settings.Settings;
2324
import org.opensearch.common.util.io.IOUtils;
@@ -46,6 +47,7 @@
4647
import java.util.Arrays;
4748
import java.util.List;
4849
import java.util.Map;
50+
import java.util.Objects;
4951
import java.util.Optional;
5052
import java.util.concurrent.ExecutionException;
5153
import java.util.stream.Collectors;
@@ -226,7 +228,7 @@ public void testRemoteStoreCustomDataOnIndexCreationAndRestore() {
226228

227229
indexDocuments(client, indexName1, randomIntBetween(5, 10));
228230
ensureGreen(indexName1);
229-
validatePathType(indexName1, PathType.FIXED, PathHashAlgorithm.FNV_1A);
231+
validatePathType(indexName1, PathType.FIXED);
230232

231233
logger.info("--> snapshot");
232234
SnapshotInfo snapshotInfo = createSnapshot(snapshotRepoName, snapshotName1, new ArrayList<>(Arrays.asList(indexName1)));
@@ -243,7 +245,7 @@ public void testRemoteStoreCustomDataOnIndexCreationAndRestore() {
243245
.get();
244246
assertEquals(RestStatus.ACCEPTED, restoreSnapshotResponse.status());
245247
ensureGreen(restoredIndexName1version1);
246-
validatePathType(restoredIndexName1version1, PathType.FIXED, PathHashAlgorithm.FNV_1A);
248+
validatePathType(restoredIndexName1version1, PathType.FIXED);
247249

248250
client(clusterManagerNode).admin()
249251
.cluster()
@@ -269,16 +271,50 @@ public void testRemoteStoreCustomDataOnIndexCreationAndRestore() {
269271
validatePathType(indexName2, PathType.HASHED_PREFIX, PathHashAlgorithm.FNV_1A);
270272

271273
// Validating that custom data has not changed for indexes which were created before the cluster setting got updated
272-
validatePathType(indexName1, PathType.FIXED, PathHashAlgorithm.FNV_1A);
274+
validatePathType(indexName1, PathType.FIXED);
275+
276+
// Create Snapshot of index 2
277+
String snapshotName2 = "test-restore-snapshot2";
278+
snapshotInfo = createSnapshot(snapshotRepoName, snapshotName2, new ArrayList<>(List.of(indexName2)));
279+
assertEquals(SnapshotState.SUCCESS, snapshotInfo.state());
280+
assertTrue(snapshotInfo.successfulShards() > 0);
281+
assertEquals(snapshotInfo.totalShards(), snapshotInfo.successfulShards());
282+
283+
// Update cluster settings to FIXED
284+
client(clusterManagerNode).admin()
285+
.cluster()
286+
.prepareUpdateSettings()
287+
.setTransientSettings(Settings.builder().put(CLUSTER_REMOTE_STORE_PATH_PREFIX_TYPE_SETTING.getKey(), PathType.FIXED))
288+
.get();
289+
290+
// Close index 2
291+
assertAcked(client().admin().indices().prepareClose(indexName2));
292+
restoreSnapshotResponse = client.admin()
293+
.cluster()
294+
.prepareRestoreSnapshot(snapshotRepoName, snapshotName2)
295+
.setWaitForCompletion(false)
296+
.setIndices(indexName2)
297+
.get();
298+
assertEquals(RestStatus.ACCEPTED, restoreSnapshotResponse.status());
299+
ensureGreen(indexName2);
300+
301+
// Validating that custom data has not changed for testindex2 which was created before the cluster setting got updated
302+
validatePathType(indexName2, PathType.HASHED_PREFIX, PathHashAlgorithm.FNV_1A);
273303
}
274304

275-
private void validatePathType(String index, PathType pathType, PathHashAlgorithm pathHashAlgorithm) {
305+
private void validatePathType(String index, PathType pathType) {
306+
validatePathType(index, pathType, null);
307+
}
308+
309+
private void validatePathType(String index, PathType pathType, @Nullable PathHashAlgorithm pathHashAlgorithm) {
276310
ClusterState state = client().admin().cluster().prepareState().execute().actionGet().getState();
277311
// Validate that the remote_store custom data is present in index metadata for the created index.
278312
Map<String, String> remoteCustomData = state.metadata().index(index).getCustomData(IndexMetadata.REMOTE_STORE_CUSTOM_KEY);
279313
assertNotNull(remoteCustomData);
280314
assertEquals(pathType.name(), remoteCustomData.get(PathType.NAME));
281-
assertEquals(pathHashAlgorithm.name(), remoteCustomData.get(PathHashAlgorithm.NAME));
315+
if (Objects.nonNull(pathHashAlgorithm)) {
316+
assertEquals(pathHashAlgorithm.name(), remoteCustomData.get(PathHashAlgorithm.NAME));
317+
}
282318
}
283319

284320
public void testRestoreInSameRemoteStoreEnabledIndex() throws IOException {

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

+18-22
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,9 @@ public MetadataCreateIndexService(
210210

211211
// Task is onboarded for throttling, it will get retried from associated TransportClusterManagerNodeAction.
212212
createIndexTaskKey = clusterService.registerClusterManagerTask(ClusterManagerTaskKeys.CREATE_INDEX_KEY, true);
213+
Supplier<Version> minNodeVersionSupplier = () -> clusterService.state().nodes().getMinNodeVersion();
213214
remoteStorePathStrategyResolver = isRemoteDataAttributePresent(settings)
214-
? new RemoteStorePathStrategyResolver(clusterService.getClusterSettings())
215+
? new RemoteStorePathStrategyResolver(clusterService.getClusterSettings(), minNodeVersionSupplier)
215216
: null;
216217
}
217218

@@ -576,28 +577,23 @@ IndexMetadata buildAndValidateTemporaryIndexMetadata(
576577
* @param assertNullOldType flag to verify that the old remote store path type is null
577578
*/
578579
public void addRemoteStorePathStrategyInCustomData(IndexMetadata.Builder tmpImdBuilder, boolean assertNullOldType) {
579-
if (remoteStorePathStrategyResolver != null) {
580-
// It is possible that remote custom data exists already. In such cases, we need to only update the path type
581-
// in the remote store custom data map.
582-
Map<String, String> existingRemoteCustomData = tmpImdBuilder.removeCustom(IndexMetadata.REMOTE_STORE_CUSTOM_KEY);
583-
Map<String, String> remoteCustomData = existingRemoteCustomData == null
584-
? new HashMap<>()
585-
: new HashMap<>(existingRemoteCustomData);
586-
// Determine the path type for use using the remoteStorePathResolver.
587-
RemoteStorePathStrategy newPathStrategy = remoteStorePathStrategyResolver.get();
588-
String oldPathType = remoteCustomData.put(PathType.NAME, newPathStrategy.getType().name());
589-
String oldHashAlgorithm = remoteCustomData.put(PathHashAlgorithm.NAME, newPathStrategy.getHashAlgorithm().name());
590-
assert !assertNullOldType || (Objects.isNull(oldPathType) && Objects.isNull(oldHashAlgorithm));
591-
logger.trace(
592-
() -> new ParameterizedMessage(
593-
"Added newPathStrategy={}, replaced oldPathType={} oldHashAlgorithm={}",
594-
newPathStrategy,
595-
oldPathType,
596-
oldHashAlgorithm
597-
)
598-
);
599-
tmpImdBuilder.putCustom(IndexMetadata.REMOTE_STORE_CUSTOM_KEY, remoteCustomData);
580+
if (remoteStorePathStrategyResolver == null) {
581+
return;
582+
}
583+
// It is possible that remote custom data exists already. In such cases, we need to only update the path type
584+
// in the remote store custom data map.
585+
Map<String, String> existingCustomData = tmpImdBuilder.removeCustom(IndexMetadata.REMOTE_STORE_CUSTOM_KEY);
586+
assert assertNullOldType == false || Objects.isNull(existingCustomData);
587+
588+
// Determine the path type for use using the remoteStorePathResolver.
589+
RemoteStorePathStrategy newPathStrategy = remoteStorePathStrategyResolver.get();
590+
Map<String, String> remoteCustomData = new HashMap<>();
591+
remoteCustomData.put(PathType.NAME, newPathStrategy.getType().name());
592+
if (Objects.nonNull(newPathStrategy.getHashAlgorithm())) {
593+
remoteCustomData.put(PathHashAlgorithm.NAME, newPathStrategy.getHashAlgorithm().name());
600594
}
595+
logger.trace(() -> new ParameterizedMessage("Added newStrategy={}, replaced oldStrategy={}", remoteCustomData, existingCustomData));
596+
tmpImdBuilder.putCustom(IndexMetadata.REMOTE_STORE_CUSTOM_KEY, remoteCustomData);
601597
}
602598

603599
private ClusterState applyCreateIndexRequestWithV1Templates(

‎server/src/main/java/org/opensearch/index/IndexSettings.java

+13-6
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
import java.util.List;
6565
import java.util.Locale;
6666
import java.util.Map;
67+
import java.util.Objects;
6768
import java.util.Optional;
6869
import java.util.concurrent.TimeUnit;
6970
import java.util.function.Consumer;
@@ -764,6 +765,7 @@ public static IndexMergePolicy fromString(String text) {
764765
private volatile String defaultSearchPipeline;
765766
private final boolean widenIndexSortType;
766767
private final boolean assignedOnRemoteNode;
768+
private final RemoteStorePathStrategy remoteStorePathStrategy;
767769

768770
/**
769771
* The maximum age of a retention lease before it is considered expired.
@@ -987,6 +989,7 @@ public IndexSettings(final IndexMetadata indexMetadata, final Settings nodeSetti
987989
*/
988990
widenIndexSortType = IndexMetadata.SETTING_INDEX_VERSION_CREATED.get(settings).before(V_2_7_0);
989991
assignedOnRemoteNode = RemoteStoreNodeAttribute.isRemoteDataAttributePresent(this.getNodeSettings());
992+
remoteStorePathStrategy = determineRemoteStorePathStrategy();
990993

991994
setEnableFuzzySetForDocId(scopedSettings.get(INDEX_DOC_ID_FUZZY_SET_ENABLED_SETTING));
992995
setDocIdFuzzySetFalsePositiveProbability(scopedSettings.get(INDEX_DOC_ID_FUZZY_SET_FALSE_POSITIVE_PROBABILITY_SETTING));
@@ -1908,15 +1911,19 @@ public void setDocIdFuzzySetFalsePositiveProbability(double docIdFuzzySetFalsePo
19081911
this.docIdFuzzySetFalsePositiveProbability = docIdFuzzySetFalsePositiveProbability;
19091912
}
19101913

1911-
public RemoteStorePathStrategy getRemoteStorePathStrategy() {
1914+
private RemoteStorePathStrategy determineRemoteStorePathStrategy() {
19121915
Map<String, String> remoteCustomData = indexMetadata.getCustomData(IndexMetadata.REMOTE_STORE_CUSTOM_KEY);
1913-
if (remoteCustomData != null
1914-
&& remoteCustomData.containsKey(PathType.NAME)
1915-
&& remoteCustomData.containsKey(PathHashAlgorithm.NAME)) {
1916+
assert remoteCustomData == null || remoteCustomData.containsKey(PathType.NAME);
1917+
if (remoteCustomData != null && remoteCustomData.containsKey(PathType.NAME)) {
19161918
PathType pathType = PathType.parseString(remoteCustomData.get(PathType.NAME));
1917-
PathHashAlgorithm pathHashAlgorithm = PathHashAlgorithm.parseString(remoteCustomData.get(PathHashAlgorithm.NAME));
1918-
return new RemoteStorePathStrategy(pathType, pathHashAlgorithm);
1919+
String hashAlgoStr = remoteCustomData.get(PathHashAlgorithm.NAME);
1920+
PathHashAlgorithm hashAlgorithm = Objects.nonNull(hashAlgoStr) ? PathHashAlgorithm.parseString(hashAlgoStr) : null;
1921+
return new RemoteStorePathStrategy(pathType, hashAlgorithm);
19191922
}
19201923
return new RemoteStorePathStrategy(PathType.FIXED);
19211924
}
1925+
1926+
public RemoteStorePathStrategy getRemoteStorePathStrategy() {
1927+
return remoteStorePathStrategy;
1928+
}
19221929
}

‎server/src/main/java/org/opensearch/index/remote/RemoteStoreEnums.java

+77-4
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,19 @@
88

99
package org.opensearch.index.remote;
1010

11+
import org.apache.logging.log4j.message.ParameterizedMessage;
1112
import org.opensearch.common.annotation.PublicApi;
1213
import org.opensearch.common.blobstore.BlobPath;
1314
import org.opensearch.common.hash.FNV1a;
1415
import org.opensearch.index.remote.RemoteStorePathStrategy.PathInput;
1516

17+
import java.util.HashMap;
1618
import java.util.Locale;
19+
import java.util.Map;
20+
import java.util.Objects;
1721
import java.util.Set;
1822

23+
import static java.util.Collections.unmodifiableMap;
1924
import static org.opensearch.index.remote.RemoteStoreEnums.DataType.DATA;
2025
import static org.opensearch.index.remote.RemoteStoreEnums.DataType.METADATA;
2126

@@ -78,9 +83,10 @@ public String getName() {
7883
*/
7984
@PublicApi(since = "2.14.0")
8085
public enum PathType {
81-
FIXED {
86+
FIXED(0) {
8287
@Override
8388
public BlobPath generatePath(PathInput pathInput, PathHashAlgorithm hashAlgorithm) {
89+
assert Objects.isNull(hashAlgorithm) : "hashAlgorithm is expected to be null with fixed remote store path type";
8490
// Hash algorithm is not used in FIXED path type
8591
return pathInput.basePath()
8692
.add(pathInput.indexUUID())
@@ -94,7 +100,7 @@ boolean requiresHashAlgorithm() {
94100
return false;
95101
}
96102
},
97-
HASHED_PREFIX {
103+
HASHED_PREFIX(1) {
98104
@Override
99105
public BlobPath generatePath(PathInput pathInput, PathHashAlgorithm hashAlgorithm) {
100106
// TODO - We need to implement this, keeping the same path as Fixed for sake of multiple tests that can fail otherwise.
@@ -112,6 +118,40 @@ boolean requiresHashAlgorithm() {
112118
}
113119
};
114120

121+
private final int code;
122+
123+
PathType(int code) {
124+
this.code = code;
125+
}
126+
127+
public int getCode() {
128+
return code;
129+
}
130+
131+
private static final Map<Integer, PathType> CODE_TO_ENUM;
132+
133+
static {
134+
PathType[] values = values();
135+
Map<Integer, PathType> codeToStatus = new HashMap<>(values.length);
136+
for (PathType value : values) {
137+
int code = value.code;
138+
if (codeToStatus.containsKey(code)) {
139+
throw new IllegalStateException(
140+
new ParameterizedMessage("{} has same code as {}", codeToStatus.get(code), value).getFormattedMessage()
141+
);
142+
}
143+
codeToStatus.put(code, value);
144+
}
145+
CODE_TO_ENUM = unmodifiableMap(codeToStatus);
146+
}
147+
148+
/**
149+
* Turn a status code into a {@link PathType}.
150+
*/
151+
public static PathType fromCode(int code) {
152+
return CODE_TO_ENUM.get(code);
153+
}
154+
115155
/**
116156
* This method generates the path for the given path input which constitutes multiple fields and characteristics
117157
* of the data.
@@ -131,7 +171,7 @@ public BlobPath path(PathInput pathInput, PathHashAlgorithm hashAlgorithm) {
131171
return generatePath(pathInput, hashAlgorithm);
132172
}
133173

134-
abstract BlobPath generatePath(PathInput pathInput, PathHashAlgorithm hashAlgorithm);
174+
protected abstract BlobPath generatePath(PathInput pathInput, PathHashAlgorithm hashAlgorithm);
135175

136176
abstract boolean requiresHashAlgorithm();
137177

@@ -158,7 +198,7 @@ public static PathType parseString(String pathType) {
158198
@PublicApi(since = "2.14.0")
159199
public enum PathHashAlgorithm {
160200

161-
FNV_1A {
201+
FNV_1A(0) {
162202
@Override
163203
long hash(PathInput pathInput) {
164204
String input = pathInput.indexUUID() + pathInput.shardId() + pathInput.dataCategory().getName() + pathInput.dataType()
@@ -167,6 +207,39 @@ long hash(PathInput pathInput) {
167207
}
168208
};
169209

210+
private final int code;
211+
212+
PathHashAlgorithm(int code) {
213+
this.code = code;
214+
}
215+
216+
public int getCode() {
217+
return code;
218+
}
219+
220+
private static final Map<Integer, PathHashAlgorithm> CODE_TO_ENUM;
221+
static {
222+
PathHashAlgorithm[] values = values();
223+
Map<Integer, PathHashAlgorithm> codeToStatus = new HashMap<>(values.length);
224+
for (PathHashAlgorithm value : values) {
225+
int code = value.code;
226+
if (codeToStatus.containsKey(code)) {
227+
throw new IllegalStateException(
228+
new ParameterizedMessage("{} has same code as {}", codeToStatus.get(code), value).getFormattedMessage()
229+
);
230+
}
231+
codeToStatus.put(code, value);
232+
}
233+
CODE_TO_ENUM = unmodifiableMap(codeToStatus);
234+
}
235+
236+
/**
237+
* Turn a status code into a {@link PathHashAlgorithm}.
238+
*/
239+
public static PathHashAlgorithm fromCode(int code) {
240+
return CODE_TO_ENUM.get(code);
241+
}
242+
170243
abstract long hash(PathInput pathInput);
171244

172245
public static PathHashAlgorithm parseString(String pathHashAlgorithm) {

‎server/src/main/java/org/opensearch/index/remote/RemoteStorePathStrategy.java

+14-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
package org.opensearch.index.remote;
1010

11+
import org.apache.logging.log4j.message.ParameterizedMessage;
1112
import org.opensearch.common.Nullable;
1213
import org.opensearch.common.annotation.PublicApi;
1314
import org.opensearch.common.blobstore.BlobPath;
@@ -36,11 +37,21 @@ public RemoteStorePathStrategy(PathType type) {
3637
}
3738

3839
public RemoteStorePathStrategy(PathType type, PathHashAlgorithm hashAlgorithm) {
39-
assert type.requiresHashAlgorithm() == false || Objects.nonNull(hashAlgorithm);
40-
this.type = Objects.requireNonNull(type);
40+
Objects.requireNonNull(type, "pathType can not be null");
41+
if (isCompatible(type, hashAlgorithm) == false) {
42+
throw new IllegalArgumentException(
43+
new ParameterizedMessage("pathType={} pathHashAlgorithm={} are incompatible", type, hashAlgorithm).getFormattedMessage()
44+
);
45+
}
46+
this.type = type;
4147
this.hashAlgorithm = hashAlgorithm;
4248
}
4349

50+
public static boolean isCompatible(PathType type, PathHashAlgorithm hashAlgorithm) {
51+
return (type.requiresHashAlgorithm() == false && Objects.isNull(hashAlgorithm))
52+
|| (type.requiresHashAlgorithm() && Objects.nonNull(hashAlgorithm));
53+
}
54+
4455
public PathType getType() {
4556
return type;
4657
}
@@ -55,7 +66,7 @@ public String toString() {
5566
}
5667

5768
public BlobPath generatePath(PathInput pathInput) {
58-
return type.generatePath(pathInput, hashAlgorithm);
69+
return type.path(pathInput, hashAlgorithm);
5970
}
6071

6172
/**

‎server/src/main/java/org/opensearch/index/remote/RemoteStorePathStrategyResolver.java

+14-2
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88

99
package org.opensearch.index.remote;
1010

11+
import org.opensearch.Version;
1112
import org.opensearch.common.settings.ClusterSettings;
1213
import org.opensearch.index.remote.RemoteStoreEnums.PathHashAlgorithm;
1314
import org.opensearch.index.remote.RemoteStoreEnums.PathType;
1415
import org.opensearch.indices.IndicesService;
1516

17+
import java.util.function.Supplier;
18+
1619
/**
1720
* Determines the {@link RemoteStorePathStrategy} at the time of index metadata creation.
1821
*
@@ -22,13 +25,22 @@ public class RemoteStorePathStrategyResolver {
2225

2326
private volatile PathType type;
2427

25-
public RemoteStorePathStrategyResolver(ClusterSettings clusterSettings) {
28+
private final Supplier<Version> minNodeVersionSupplier;
29+
30+
public RemoteStorePathStrategyResolver(ClusterSettings clusterSettings, Supplier<Version> minNodeVersionSupplier) {
31+
this.minNodeVersionSupplier = minNodeVersionSupplier;
2632
type = clusterSettings.get(IndicesService.CLUSTER_REMOTE_STORE_PATH_PREFIX_TYPE_SETTING);
2733
clusterSettings.addSettingsUpdateConsumer(IndicesService.CLUSTER_REMOTE_STORE_PATH_PREFIX_TYPE_SETTING, this::setType);
2834
}
2935

3036
public RemoteStorePathStrategy get() {
31-
return new RemoteStorePathStrategy(type, PathHashAlgorithm.FNV_1A);
37+
PathType pathType;
38+
PathHashAlgorithm pathHashAlgorithm;
39+
// Min node version check ensures that we are enabling the new prefix type only when all the nodes understand it.
40+
pathType = Version.CURRENT.compareTo(minNodeVersionSupplier.get()) <= 0 ? type : PathType.FIXED;
41+
// If the path type is fixed, hash algorithm is not applicable.
42+
pathHashAlgorithm = pathType == PathType.FIXED ? null : PathHashAlgorithm.FNV_1A;
43+
return new RemoteStorePathStrategy(pathType, pathHashAlgorithm);
3244
}
3345

3446
private void setType(PathType type) {

‎server/src/main/java/org/opensearch/index/shard/StoreRecovery.java

+1-4
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@
5858
import org.opensearch.index.engine.Engine;
5959
import org.opensearch.index.engine.EngineException;
6060
import org.opensearch.index.mapper.MapperService;
61-
import org.opensearch.index.remote.RemoteStoreEnums.PathType;
62-
import org.opensearch.index.remote.RemoteStorePathStrategy;
6361
import org.opensearch.index.seqno.SequenceNumbers;
6462
import org.opensearch.index.snapshots.IndexShardRestoreFailedException;
6563
import org.opensearch.index.snapshots.blobstore.RemoteStoreShardShallowCopySnapshot;
@@ -405,8 +403,7 @@ void recoverFromSnapshotAndRemoteStore(
405403
remoteStoreRepository,
406404
indexUUID,
407405
shardId,
408-
new RemoteStorePathStrategy(PathType.FIXED)
409-
// TODO - The path type needs to be obtained from RemoteStoreShardShallowCopySnapshot
406+
shallowCopyShardMetadata.getRemoteStorePathStrategy()
410407
);
411408
sourceRemoteDirectory.initializeToSpecificCommit(
412409
primaryTerm,

‎server/src/main/java/org/opensearch/index/snapshots/blobstore/RemoteStoreShardShallowCopySnapshot.java

+149-50
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,22 @@
88

99
package org.opensearch.index.snapshots.blobstore;
1010

11+
import org.apache.logging.log4j.message.ParameterizedMessage;
1112
import org.opensearch.OpenSearchParseException;
1213
import org.opensearch.common.annotation.PublicApi;
1314
import org.opensearch.core.ParseField;
1415
import org.opensearch.core.xcontent.ToXContentFragment;
1516
import org.opensearch.core.xcontent.XContentBuilder;
1617
import org.opensearch.core.xcontent.XContentParser;
18+
import org.opensearch.index.remote.RemoteStoreEnums.PathHashAlgorithm;
19+
import org.opensearch.index.remote.RemoteStoreEnums.PathType;
20+
import org.opensearch.index.remote.RemoteStorePathStrategy;
1721
import org.opensearch.index.snapshots.IndexShardSnapshotStatus;
1822

1923
import java.io.IOException;
2024
import java.util.ArrayList;
2125
import java.util.List;
26+
import java.util.Objects;
2227

2328
/**
2429
* Remote Store based Shard snapshot metadata
@@ -41,8 +46,10 @@ public class RemoteStoreShardShallowCopySnapshot implements ToXContentFragment,
4146
private final String repositoryBasePath;
4247
private final String indexUUID;
4348
private final List<String> fileNames;
49+
private final PathType pathType;
50+
private final PathHashAlgorithm pathHashAlgorithm;
4451

45-
static final String DEFAULT_VERSION = "1";
52+
static final String DEFAULT_VERSION = "2";
4653
static final String NAME = "name";
4754
static final String VERSION = "version";
4855
static final String INDEX_VERSION = "index_version";
@@ -61,6 +68,8 @@ public class RemoteStoreShardShallowCopySnapshot implements ToXContentFragment,
6168

6269
static final String TOTAL_FILE_COUNT = "number_of_files";
6370
static final String TOTAL_SIZE = "total_size";
71+
static final String PATH_TYPE = "path_type";
72+
static final String PATH_HASH_ALGORITHM = "path_hash_algorithm";
6473

6574
private static final ParseField PARSE_NAME = new ParseField(NAME);
6675
private static final ParseField PARSE_VERSION = new ParseField(VERSION);
@@ -75,6 +84,8 @@ public class RemoteStoreShardShallowCopySnapshot implements ToXContentFragment,
7584
private static final ParseField PARSE_REMOTE_STORE_REPOSITORY = new ParseField(REMOTE_STORE_REPOSITORY);
7685
private static final ParseField PARSE_REPOSITORY_BASE_PATH = new ParseField(REPOSITORY_BASE_PATH);
7786
private static final ParseField PARSE_FILE_NAMES = new ParseField(FILE_NAMES);
87+
private static final ParseField PARSE_PATH_TYPE = new ParseField(PATH_TYPE);
88+
private static final ParseField PARSE_PATH_HASH_ALGORITHM = new ParseField(PATH_HASH_ALGORITHM);
7889

7990
/**
8091
* Serializes shard snapshot metadata info into JSON
@@ -101,6 +112,14 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
101112
builder.value(fileName);
102113
}
103114
builder.endArray();
115+
// We are handling NP check since a cluster can have indexes created earlier which do not have remote store
116+
// path type and path hash algorithm in its custom data in index metadata.
117+
if (Objects.nonNull(pathType)) {
118+
builder.field(PATH_TYPE, pathType.getCode());
119+
}
120+
if (Objects.nonNull(pathHashAlgorithm)) {
121+
builder.field(PATH_HASH_ALGORITHM, pathHashAlgorithm.getCode());
122+
}
104123
return builder;
105124
}
106125

@@ -116,34 +135,30 @@ public RemoteStoreShardShallowCopySnapshot(
116135
String indexUUID,
117136
String remoteStoreRepository,
118137
String repositoryBasePath,
119-
List<String> fileNames
138+
List<String> fileNames,
139+
PathType pathType,
140+
PathHashAlgorithm pathHashAlgorithm
120141
) {
121-
this.version = DEFAULT_VERSION;
122-
verifyParameters(
123-
version,
142+
this(
143+
DEFAULT_VERSION,
124144
snapshot,
125145
indexVersion,
126146
primaryTerm,
127147
commitGeneration,
148+
startTime,
149+
time,
150+
totalFileCount,
151+
totalSize,
128152
indexUUID,
129153
remoteStoreRepository,
130-
repositoryBasePath
154+
repositoryBasePath,
155+
fileNames,
156+
pathType,
157+
pathHashAlgorithm
131158
);
132-
this.snapshot = snapshot;
133-
this.indexVersion = indexVersion;
134-
this.primaryTerm = primaryTerm;
135-
this.commitGeneration = commitGeneration;
136-
this.startTime = startTime;
137-
this.time = time;
138-
this.totalFileCount = totalFileCount;
139-
this.totalSize = totalSize;
140-
this.indexUUID = indexUUID;
141-
this.remoteStoreRepository = remoteStoreRepository;
142-
this.repositoryBasePath = repositoryBasePath;
143-
this.fileNames = fileNames;
144159
}
145160

146-
private RemoteStoreShardShallowCopySnapshot(
161+
RemoteStoreShardShallowCopySnapshot(
147162
String version,
148163
String snapshot,
149164
long indexVersion,
@@ -156,7 +171,9 @@ private RemoteStoreShardShallowCopySnapshot(
156171
String indexUUID,
157172
String remoteStoreRepository,
158173
String repositoryBasePath,
159-
List<String> fileNames
174+
List<String> fileNames,
175+
PathType pathType,
176+
PathHashAlgorithm pathHashAlgorithm
160177
) {
161178
verifyParameters(
162179
version,
@@ -166,7 +183,9 @@ private RemoteStoreShardShallowCopySnapshot(
166183
commitGeneration,
167184
indexUUID,
168185
remoteStoreRepository,
169-
repositoryBasePath
186+
repositoryBasePath,
187+
pathType,
188+
pathHashAlgorithm
170189
);
171190
this.version = version;
172191
this.snapshot = snapshot;
@@ -181,6 +200,8 @@ private RemoteStoreShardShallowCopySnapshot(
181200
this.remoteStoreRepository = remoteStoreRepository;
182201
this.repositoryBasePath = repositoryBasePath;
183202
this.fileNames = fileNames;
203+
this.pathType = pathType;
204+
this.pathHashAlgorithm = pathHashAlgorithm;
184205
}
185206

186207
/**
@@ -203,6 +224,8 @@ public static RemoteStoreShardShallowCopySnapshot fromXContent(XContentParser pa
203224
long primaryTerm = -1;
204225
long commitGeneration = -1;
205226
List<String> fileNames = new ArrayList<>();
227+
PathType pathType = null;
228+
PathHashAlgorithm pathHashAlgorithm = null;
206229

207230
if (parser.currentToken() == null) { // fresh parser? move to the first token
208231
parser.nextToken();
@@ -237,6 +260,10 @@ public static RemoteStoreShardShallowCopySnapshot fromXContent(XContentParser pa
237260
remoteStoreRepository = parser.text();
238261
} else if (PARSE_REPOSITORY_BASE_PATH.match(currentFieldName, parser.getDeprecationHandler())) {
239262
repositoryBasePath = parser.text();
263+
} else if (PARSE_PATH_TYPE.match(currentFieldName, parser.getDeprecationHandler())) {
264+
pathType = PathType.fromCode(parser.intValue());
265+
} else if (PARSE_PATH_HASH_ALGORITHM.match(currentFieldName, parser.getDeprecationHandler())) {
266+
pathHashAlgorithm = PathHashAlgorithm.fromCode(parser.intValue());
240267
} else {
241268
throw new OpenSearchParseException("unknown parameter [{}]", currentFieldName);
242269
}
@@ -266,7 +293,9 @@ public static RemoteStoreShardShallowCopySnapshot fromXContent(XContentParser pa
266293
indexUUID,
267294
remoteStoreRepository,
268295
repositoryBasePath,
269-
fileNames
296+
fileNames,
297+
pathType,
298+
pathHashAlgorithm
270299
);
271300
}
272301

@@ -380,38 +409,47 @@ private void verifyParameters(
380409
long commitGeneration,
381410
String indexUUID,
382411
String remoteStoreRepository,
383-
String repositoryBasePath
412+
String repositoryBasePath,
413+
PathType pathType,
414+
PathHashAlgorithm pathHashAlgorithm
384415
) {
385-
String exceptionStr = null;
386-
if (version == null) {
387-
exceptionStr = "Invalid Version Provided";
388-
}
389-
if (snapshot == null) {
390-
exceptionStr = "Invalid/Missing Snapshot Name";
391-
}
392-
if (indexVersion < 0) {
393-
exceptionStr = "Invalid Index Version";
394-
}
395-
if (primaryTerm < 0) {
396-
exceptionStr = "Invalid Primary Term";
397-
}
398-
if (commitGeneration < 0) {
399-
exceptionStr = "Invalid Commit Generation";
400-
}
401-
if (indexUUID == null) {
402-
exceptionStr = "Invalid/Missing Index UUID";
403-
}
404-
if (remoteStoreRepository == null) {
405-
exceptionStr = "Invalid/Missing Remote Store Repository";
406-
}
407-
if (repositoryBasePath == null) {
408-
exceptionStr = "Invalid/Missing Repository Base Path";
409-
}
410-
if (exceptionStr != null) {
416+
417+
throwExceptionIfInvalid(Objects.isNull(version), "Invalid Version Provided");
418+
throwExceptionIfInvalid(Objects.isNull(snapshot), "Invalid/Missing Snapshot Name");
419+
throwExceptionIfInvalid(indexVersion < 0, "Invalid Index Version");
420+
throwExceptionIfInvalid(primaryTerm < 0, "Invalid Primary Term");
421+
throwExceptionIfInvalid(commitGeneration < 0, "Invalid Commit Generation");
422+
throwExceptionIfInvalid(Objects.isNull(indexUUID), "Invalid/Missing Index UUID");
423+
throwExceptionIfInvalid(Objects.isNull(remoteStoreRepository), "Invalid/Missing Remote Store Repository");
424+
throwExceptionIfInvalid(Objects.isNull(repositoryBasePath), "Invalid/Missing Repository Base Path");
425+
throwExceptionIfInvalid(
426+
isValidRemotePathConfiguration(version, pathType, pathHashAlgorithm) == false,
427+
new ParameterizedMessage(
428+
"Invalid combination of pathType={} pathHashAlgorithm={} for version={}",
429+
pathType,
430+
pathHashAlgorithm,
431+
version
432+
).getFormattedMessage()
433+
);
434+
}
435+
436+
private void throwExceptionIfInvalid(boolean isInvalid, String exceptionStr) {
437+
if (isInvalid) {
411438
throw new IllegalArgumentException(exceptionStr);
412439
}
413440
}
414441

442+
private boolean isValidRemotePathConfiguration(String version, PathType pathType, PathHashAlgorithm pathHashAlgorithm) {
443+
switch (version) {
444+
case "1":
445+
return Objects.isNull(pathType) && Objects.isNull(pathHashAlgorithm);
446+
case "2":
447+
return Objects.nonNull(pathType) && RemoteStorePathStrategy.isCompatible(pathType, pathHashAlgorithm);
448+
default:
449+
return false;
450+
}
451+
}
452+
415453
/**
416454
* Creates a new instance which has a different name and zero incremental file counts but is identical to this instance in terms of the files
417455
* it references.
@@ -433,7 +471,9 @@ public RemoteStoreShardShallowCopySnapshot asClone(String targetSnapshotName, lo
433471
indexUUID,
434472
remoteStoreRepository,
435473
repositoryBasePath,
436-
fileNames
474+
fileNames,
475+
pathType,
476+
pathHashAlgorithm
437477
);
438478
}
439479

@@ -449,4 +489,63 @@ public IndexShardSnapshotStatus getIndexShardSnapshotStatus() {
449489
null
450490
); // Not adding a real generation here as it doesn't matter to callers
451491
}
492+
493+
public PathType getPathType() {
494+
return pathType;
495+
}
496+
497+
public PathHashAlgorithm getPathHashAlgorithm() {
498+
return pathHashAlgorithm;
499+
}
500+
501+
public RemoteStorePathStrategy getRemoteStorePathStrategy() {
502+
if (Objects.nonNull(pathType)) {
503+
return new RemoteStorePathStrategy(pathType, pathHashAlgorithm);
504+
}
505+
return new RemoteStorePathStrategy(PathType.FIXED);
506+
}
507+
508+
@Override
509+
public boolean equals(Object obj) {
510+
if (this == obj) return true;
511+
if (obj == null || getClass() != obj.getClass()) return false;
512+
RemoteStoreShardShallowCopySnapshot that = (RemoteStoreShardShallowCopySnapshot) obj;
513+
514+
return Objects.equals(this.snapshot, that.snapshot)
515+
&& Objects.equals(this.version, that.version)
516+
&& this.indexVersion == that.indexVersion
517+
&& this.startTime == that.startTime
518+
&& this.time == that.time
519+
&& this.totalFileCount == that.totalFileCount
520+
&& this.totalSize == that.totalSize
521+
&& this.primaryTerm == that.primaryTerm
522+
&& this.commitGeneration == that.commitGeneration
523+
&& Objects.equals(this.remoteStoreRepository, that.remoteStoreRepository)
524+
&& Objects.equals(this.repositoryBasePath, that.repositoryBasePath)
525+
&& Objects.equals(this.indexUUID, that.indexUUID)
526+
&& Objects.equals(this.fileNames, that.fileNames)
527+
&& Objects.equals(this.pathType, that.pathType)
528+
&& Objects.equals(this.pathHashAlgorithm, that.pathHashAlgorithm);
529+
}
530+
531+
@Override
532+
public int hashCode() {
533+
return Objects.hash(
534+
snapshot,
535+
version,
536+
indexVersion,
537+
startTime,
538+
time,
539+
totalFileCount,
540+
totalSize,
541+
primaryTerm,
542+
commitGeneration,
543+
remoteStoreRepository,
544+
repositoryBasePath,
545+
indexUUID,
546+
fileNames,
547+
pathType,
548+
pathHashAlgorithm
549+
);
550+
}
452551
}

‎server/src/main/java/org/opensearch/repositories/blobstore/BlobStoreRepository.java

+7-8
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@
108108
import org.opensearch.core.xcontent.NamedXContentRegistry;
109109
import org.opensearch.core.xcontent.XContentParser;
110110
import org.opensearch.index.mapper.MapperService;
111-
import org.opensearch.index.remote.RemoteStoreEnums.PathType;
112111
import org.opensearch.index.remote.RemoteStorePathStrategy;
113112
import org.opensearch.index.snapshots.IndexShardRestoreFailedException;
114113
import org.opensearch.index.snapshots.IndexShardSnapshotStatus;
@@ -676,8 +675,7 @@ public void cloneRemoteStoreIndexShardSnapshot(
676675
remoteStoreRepository,
677676
indexUUID,
678677
String.valueOf(shardId.shardId()),
679-
new RemoteStorePathStrategy(PathType.FIXED)
680-
// TODO - The path type needs to be obtained from RemoteStoreShardShallowCopySnapshot
678+
remStoreBasedShardMetadata.getRemoteStorePathStrategy()
681679
);
682680
remoteStoreMetadataLockManger.cloneLock(
683681
FileLockInfo.getLockInfoBuilder().withAcquirerId(source.getUUID()).build(),
@@ -1217,8 +1215,7 @@ protected void releaseRemoteStoreLockAndCleanup(
12171215
remoteStoreRepoForIndex,
12181216
indexUUID,
12191217
shardId,
1220-
new RemoteStorePathStrategy(PathType.FIXED)
1221-
// TODO - The path type needs to be obtained from RemoteStoreShardShallowCopySnapshot
1218+
remoteStoreShardShallowCopySnapshot.getRemoteStorePathStrategy()
12221219
);
12231220
remoteStoreMetadataLockManager.release(FileLockInfo.getLockInfoBuilder().withAcquirerId(shallowSnapshotUUID).build());
12241221
logger.debug("Successfully released lock for shard {} of index with uuid {}", shardId, indexUUID);
@@ -1241,8 +1238,7 @@ protected void releaseRemoteStoreLockAndCleanup(
12411238
indexUUID,
12421239
new ShardId(Index.UNKNOWN_INDEX_NAME, indexUUID, Integer.parseInt(shardId)),
12431240
ThreadPool.Names.REMOTE_PURGE,
1244-
new RemoteStorePathStrategy(PathType.FIXED)
1245-
// TODO - The path type needs to be obtained from RemoteStoreShardShallowCopySnapshot
1241+
remoteStoreShardShallowCopySnapshot.getRemoteStorePathStrategy()
12461242
);
12471243
}
12481244
}
@@ -2781,6 +2777,7 @@ public void snapshotRemoteStoreIndexShard(
27812777
// now create and write the commit point
27822778
logger.trace("[{}] [{}] writing shard snapshot file", shardId, snapshotId);
27832779
try {
2780+
RemoteStorePathStrategy pathStrategy = store.indexSettings().getRemoteStorePathStrategy();
27842781
REMOTE_STORE_SHARD_SHALLOW_COPY_SNAPSHOT_FORMAT.write(
27852782
new RemoteStoreShardShallowCopySnapshot(
27862783
snapshotId.getName(),
@@ -2794,7 +2791,9 @@ public void snapshotRemoteStoreIndexShard(
27942791
store.indexSettings().getUUID(),
27952792
store.indexSettings().getRemoteStoreRepository(),
27962793
this.basePath().toString(),
2797-
fileNames
2794+
fileNames,
2795+
pathStrategy.getType(),
2796+
pathStrategy.getHashAlgorithm()
27982797
),
27992798
shardContainer,
28002799
snapshotId.getUUID(),

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

+3-6
Original file line numberDiff line numberDiff line change
@@ -1706,12 +1706,9 @@ public void testRemoteCustomData() {
17061706

17071707
// Case 2 - cluster.remote_store.index.path.prefix.optimised=fixed (default value)
17081708
indexMetadata = testRemoteCustomData(true, PathType.FIXED);
1709-
validateRemoteCustomData(indexMetadata.getCustomData(IndexMetadata.REMOTE_STORE_CUSTOM_KEY), PathType.NAME, PathType.FIXED.name());
1710-
validateRemoteCustomData(
1711-
indexMetadata.getCustomData(IndexMetadata.REMOTE_STORE_CUSTOM_KEY),
1712-
PathHashAlgorithm.NAME,
1713-
PathHashAlgorithm.FNV_1A.name()
1714-
);
1709+
Map<String, String> remoteCustomData = indexMetadata.getCustomData(IndexMetadata.REMOTE_STORE_CUSTOM_KEY);
1710+
validateRemoteCustomData(remoteCustomData, PathType.NAME, PathType.FIXED.name());
1711+
assertNull(remoteCustomData.get(PathHashAlgorithm.NAME));
17151712

17161713
// Case 3 - cluster.remote_store.index.path.prefix.optimised=hashed_prefix
17171714
indexMetadata = testRemoteCustomData(true, PathType.HASHED_PREFIX);

‎server/src/test/java/org/opensearch/index/snapshots/blobstore/RemoteStoreShardShallowCopySnapshotTests.java

+168-18
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import org.opensearch.core.xcontent.ToXContent;
1515
import org.opensearch.core.xcontent.XContentBuilder;
1616
import org.opensearch.core.xcontent.XContentParser;
17+
import org.opensearch.index.remote.RemoteStoreEnums.PathHashAlgorithm;
18+
import org.opensearch.index.remote.RemoteStoreEnums.PathType;
1719
import org.opensearch.test.OpenSearchTestCase;
1820

1921
import java.io.IOException;
@@ -40,7 +42,10 @@ public void testToXContent() throws IOException {
4042
String repositoryBasePath = "test-repo-basepath";
4143
List<String> fileNames = new ArrayList<>(5);
4244
fileNames.addAll(Arrays.asList("file1", "file2", "file3", "file4", "file5"));
45+
46+
// Case 1 - Without remote path type fields
4347
RemoteStoreShardShallowCopySnapshot shardShallowCopySnapshot = new RemoteStoreShardShallowCopySnapshot(
48+
"1",
4449
snapshot,
4550
indexVersion,
4651
primaryTerm,
@@ -52,7 +57,9 @@ public void testToXContent() throws IOException {
5257
indexUUID,
5358
remoteStoreRepository,
5459
repositoryBasePath,
55-
fileNames
60+
fileNames,
61+
null,
62+
null
5663
);
5764
String actual;
5865
try (XContentBuilder builder = MediaTypeRegistry.JSON.contentBuilder()) {
@@ -66,6 +73,67 @@ public void testToXContent() throws IOException {
6673
+ "\"test-rs-repository\",\"commit_generation\":5,\"primary_term\":3,\"remote_store_repository_base_path\":"
6774
+ "\"test-repo-basepath\",\"file_names\":[\"file1\",\"file2\",\"file3\",\"file4\",\"file5\"]}";
6875
assert Objects.equals(actual, expectedXContent) : "xContent is " + actual;
76+
77+
// Case 2 - with just fixed type
78+
shardShallowCopySnapshot = new RemoteStoreShardShallowCopySnapshot(
79+
snapshot,
80+
indexVersion,
81+
primaryTerm,
82+
commitGeneration,
83+
startTime,
84+
time,
85+
totalFileCount,
86+
totalSize,
87+
indexUUID,
88+
remoteStoreRepository,
89+
repositoryBasePath,
90+
fileNames,
91+
PathType.FIXED,
92+
null
93+
);
94+
try (XContentBuilder builder = MediaTypeRegistry.JSON.contentBuilder()) {
95+
builder.startObject();
96+
shardShallowCopySnapshot.toXContent(builder, ToXContent.EMPTY_PARAMS);
97+
builder.endObject();
98+
actual = builder.toString();
99+
}
100+
101+
expectedXContent = "{\"version\":\"2\",\"name\":\"test-snapshot\",\"index_version\":1,\"start_time\":123,\"time\":123,"
102+
+ "\"number_of_files\":5,\"total_size\":5,\"index_uuid\":\"syzhajds-ashdlfj\",\"remote_store_repository\":"
103+
+ "\"test-rs-repository\",\"commit_generation\":5,\"primary_term\":3,\"remote_store_repository_base_path\":"
104+
+ "\"test-repo-basepath\",\"file_names\":[\"file1\",\"file2\",\"file3\",\"file4\",\"file5\"],\"path_type\":0}";
105+
assert Objects.equals(actual, expectedXContent) : "xContent is " + actual;
106+
107+
// Case 3 - with just hashed prefix type and hash algorithm
108+
shardShallowCopySnapshot = new RemoteStoreShardShallowCopySnapshot(
109+
snapshot,
110+
indexVersion,
111+
primaryTerm,
112+
commitGeneration,
113+
startTime,
114+
time,
115+
totalFileCount,
116+
totalSize,
117+
indexUUID,
118+
remoteStoreRepository,
119+
repositoryBasePath,
120+
fileNames,
121+
PathType.HASHED_PREFIX,
122+
PathHashAlgorithm.FNV_1A
123+
);
124+
try (XContentBuilder builder = MediaTypeRegistry.JSON.contentBuilder()) {
125+
builder.startObject();
126+
shardShallowCopySnapshot.toXContent(builder, ToXContent.EMPTY_PARAMS);
127+
builder.endObject();
128+
actual = builder.toString();
129+
}
130+
131+
expectedXContent = "{\"version\":\"2\",\"name\":\"test-snapshot\",\"index_version\":1,\"start_time\":123,\"time\":123,"
132+
+ "\"number_of_files\":5,\"total_size\":5,\"index_uuid\":\"syzhajds-ashdlfj\",\"remote_store_repository\":"
133+
+ "\"test-rs-repository\",\"commit_generation\":5,\"primary_term\":3,\"remote_store_repository_base_path\":"
134+
+ "\"test-repo-basepath\",\"file_names\":[\"file1\",\"file2\",\"file3\",\"file4\",\"file5\"],\"path_type\":1"
135+
+ ",\"path_hash_algorithm\":0}";
136+
assert Objects.equals(actual, expectedXContent) : "xContent is " + actual;
69137
}
70138

71139
public void testFromXContent() throws IOException {
@@ -83,6 +151,7 @@ public void testFromXContent() throws IOException {
83151
List<String> fileNames = new ArrayList<>(5);
84152
fileNames.addAll(Arrays.asList("file1", "file2", "file3", "file4", "file5"));
85153
RemoteStoreShardShallowCopySnapshot expectedShardShallowCopySnapshot = new RemoteStoreShardShallowCopySnapshot(
154+
"1",
86155
snapshot,
87156
indexVersion,
88157
primaryTerm,
@@ -94,30 +163,76 @@ public void testFromXContent() throws IOException {
94163
indexUUID,
95164
remoteStoreRepository,
96165
repositoryBasePath,
97-
fileNames
166+
fileNames,
167+
null,
168+
null
98169
);
99170
String xContent = "{\"version\":\"1\",\"name\":\"test-snapshot\",\"index_version\":1,\"start_time\":123,\"time\":123,"
100171
+ "\"number_of_files\":5,\"total_size\":5,\"index_uuid\":\"syzhajds-ashdlfj\",\"remote_store_repository\":"
101172
+ "\"test-rs-repository\",\"commit_generation\":5,\"primary_term\":3,\"remote_store_repository_base_path\":"
102173
+ "\"test-repo-basepath\",\"file_names\":[\"file1\",\"file2\",\"file3\",\"file4\",\"file5\"]}";
103174
try (XContentParser parser = createParser(JsonXContent.jsonXContent, xContent)) {
104175
RemoteStoreShardShallowCopySnapshot actualShardShallowCopySnapshot = RemoteStoreShardShallowCopySnapshot.fromXContent(parser);
105-
assertEquals(actualShardShallowCopySnapshot.snapshot(), expectedShardShallowCopySnapshot.snapshot());
106-
assertEquals(
107-
actualShardShallowCopySnapshot.getRemoteStoreRepository(),
108-
expectedShardShallowCopySnapshot.getRemoteStoreRepository()
109-
);
110-
assertEquals(actualShardShallowCopySnapshot.getCommitGeneration(), expectedShardShallowCopySnapshot.getCommitGeneration());
111-
assertEquals(actualShardShallowCopySnapshot.getPrimaryTerm(), expectedShardShallowCopySnapshot.getPrimaryTerm());
112-
assertEquals(actualShardShallowCopySnapshot.startTime(), expectedShardShallowCopySnapshot.startTime());
113-
assertEquals(actualShardShallowCopySnapshot.time(), expectedShardShallowCopySnapshot.time());
114-
assertEquals(actualShardShallowCopySnapshot.totalSize(), expectedShardShallowCopySnapshot.totalSize());
115-
assertEquals(actualShardShallowCopySnapshot.totalFileCount(), expectedShardShallowCopySnapshot.totalFileCount());
176+
assert Objects.equals(expectedShardShallowCopySnapshot, actualShardShallowCopySnapshot);
177+
}
178+
179+
// with pathType=PathType.FIXED
180+
xContent = "{\"version\":\"2\",\"name\":\"test-snapshot\",\"index_version\":1,\"start_time\":123,\"time\":123,"
181+
+ "\"number_of_files\":5,\"total_size\":5,\"index_uuid\":\"syzhajds-ashdlfj\",\"remote_store_repository\":"
182+
+ "\"test-rs-repository\",\"commit_generation\":5,\"primary_term\":3,\"remote_store_repository_base_path\":"
183+
+ "\"test-repo-basepath\",\"file_names\":[\"file1\",\"file2\",\"file3\",\"file4\",\"file5\"],\"path_type\":0}";
184+
expectedShardShallowCopySnapshot = new RemoteStoreShardShallowCopySnapshot(
185+
"2",
186+
snapshot,
187+
indexVersion,
188+
primaryTerm,
189+
commitGeneration,
190+
startTime,
191+
time,
192+
totalFileCount,
193+
totalSize,
194+
indexUUID,
195+
remoteStoreRepository,
196+
repositoryBasePath,
197+
fileNames,
198+
PathType.FIXED,
199+
null
200+
);
201+
try (XContentParser parser = createParser(JsonXContent.jsonXContent, xContent)) {
202+
RemoteStoreShardShallowCopySnapshot actualShardShallowCopySnapshot = RemoteStoreShardShallowCopySnapshot.fromXContent(parser);
203+
assert Objects.equals(expectedShardShallowCopySnapshot, actualShardShallowCopySnapshot);
204+
}
205+
206+
// with pathType=PathType.HASHED_PREFIX and pathHashAlgorithm=PathHashAlgorithm.FNV_1A
207+
xContent = "{\"version\":\"2\",\"name\":\"test-snapshot\",\"index_version\":1,\"start_time\":123,\"time\":123,"
208+
+ "\"number_of_files\":5,\"total_size\":5,\"index_uuid\":\"syzhajds-ashdlfj\",\"remote_store_repository\":"
209+
+ "\"test-rs-repository\",\"commit_generation\":5,\"primary_term\":3,\"remote_store_repository_base_path\":"
210+
+ "\"test-repo-basepath\",\"file_names\":[\"file1\",\"file2\",\"file3\",\"file4\",\"file5\"],\"path_type\":1,\"path_hash_algorithm\":0}";
211+
expectedShardShallowCopySnapshot = new RemoteStoreShardShallowCopySnapshot(
212+
"2",
213+
snapshot,
214+
indexVersion,
215+
primaryTerm,
216+
commitGeneration,
217+
startTime,
218+
time,
219+
totalFileCount,
220+
totalSize,
221+
indexUUID,
222+
remoteStoreRepository,
223+
repositoryBasePath,
224+
fileNames,
225+
PathType.HASHED_PREFIX,
226+
PathHashAlgorithm.FNV_1A
227+
);
228+
try (XContentParser parser = createParser(JsonXContent.jsonXContent, xContent)) {
229+
RemoteStoreShardShallowCopySnapshot actualShardShallowCopySnapshot = RemoteStoreShardShallowCopySnapshot.fromXContent(parser);
230+
assert Objects.equals(expectedShardShallowCopySnapshot, actualShardShallowCopySnapshot);
116231
}
117232
}
118233

119234
public void testFromXContentInvalid() throws IOException {
120-
final int iters = scaledRandomIntBetween(1, 10);
235+
final int iters = 14;
121236
for (int iter = 0; iter < iters; iter++) {
122237
String snapshot = "test-snapshot";
123238
long indexVersion = 1;
@@ -133,10 +248,11 @@ public void testFromXContentInvalid() throws IOException {
133248
List<String> fileNames = new ArrayList<>(5);
134249
fileNames.addAll(Arrays.asList("file1", "file2", "file3", "file4", "file5"));
135250
String failure = null;
136-
String version = RemoteStoreShardShallowCopySnapshot.DEFAULT_VERSION;
137-
long length = Math.max(0, Math.abs(randomLong()));
251+
String version = "1";
252+
PathType pathType = null;
253+
PathHashAlgorithm pathHashAlgorithm = null;
138254
// random corruption
139-
switch (randomIntBetween(0, 8)) {
255+
switch (iter) {
140256
case 0:
141257
snapshot = null;
142258
failure = "Invalid/Missing Snapshot Name";
@@ -170,6 +286,31 @@ public void testFromXContentInvalid() throws IOException {
170286
failure = "Invalid Version Provided";
171287
break;
172288
case 8:
289+
version = "2";
290+
failure = "Invalid combination of pathType=null pathHashAlgorithm=null for version=2";
291+
break;
292+
case 9:
293+
version = "1";
294+
pathType = PathType.FIXED;
295+
failure = "Invalid combination of pathType=FIXED pathHashAlgorithm=null for version=1";
296+
break;
297+
case 10:
298+
version = "1";
299+
pathHashAlgorithm = PathHashAlgorithm.FNV_1A;
300+
failure = "Invalid combination of pathType=null pathHashAlgorithm=FNV_1A for version=1";
301+
break;
302+
case 11:
303+
version = "2";
304+
pathType = PathType.FIXED;
305+
pathHashAlgorithm = PathHashAlgorithm.FNV_1A;
306+
failure = "Invalid combination of pathType=FIXED pathHashAlgorithm=FNV_1A for version=2";
307+
break;
308+
case 12:
309+
version = "2";
310+
pathType = PathType.HASHED_PREFIX;
311+
pathHashAlgorithm = PathHashAlgorithm.FNV_1A;
312+
break;
313+
case 13:
173314
break;
174315
default:
175316
fail("shouldn't be here");
@@ -194,6 +335,14 @@ public void testFromXContentInvalid() throws IOException {
194335
builder.value(fileName);
195336
}
196337
builder.endArray();
338+
// We are handling NP check since a cluster can have indexes created earlier which do not have remote store
339+
// path type and path hash algorithm in its custom data in index metadata.
340+
if (Objects.nonNull(pathType)) {
341+
builder.field(RemoteStoreShardShallowCopySnapshot.PATH_TYPE, pathType.getCode());
342+
}
343+
if (Objects.nonNull(pathHashAlgorithm)) {
344+
builder.field(RemoteStoreShardShallowCopySnapshot.PATH_HASH_ALGORITHM, pathHashAlgorithm.getCode());
345+
}
197346
builder.endObject();
198347
byte[] xContent = BytesReference.toBytes(BytesReference.bytes(builder));
199348

@@ -211,7 +360,8 @@ public void testFromXContentInvalid() throws IOException {
211360
assertEquals(remoteStoreShardShallowCopySnapshot.startTime(), startTime);
212361
assertEquals(remoteStoreShardShallowCopySnapshot.time(), time);
213362
assertEquals(remoteStoreShardShallowCopySnapshot.totalSize(), totalSize);
214-
assertEquals(remoteStoreShardShallowCopySnapshot.totalFileCount(), totalFileCount);
363+
assertEquals(remoteStoreShardShallowCopySnapshot.getPathType(), pathType);
364+
assertEquals(remoteStoreShardShallowCopySnapshot.getPathHashAlgorithm(), pathHashAlgorithm);
215365
} else {
216366
try (XContentParser parser = createParser(JsonXContent.jsonXContent, xContent)) {
217367
parser.nextToken();

‎server/src/test/java/org/opensearch/index/store/RemoteSegmentStoreDirectoryTests.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -704,9 +704,9 @@ public void testCleanupAsync() throws Exception {
704704
String repositoryName = "test-repository";
705705
String indexUUID = "test-idx-uuid";
706706
ShardId shardId = new ShardId(Index.UNKNOWN_INDEX_NAME, indexUUID, Integer.parseInt("0"));
707-
RemoteStorePathStrategy pathStrategy = new RemoteStorePathStrategy(
708-
randomFrom(PathType.values()),
709-
randomFrom(PathHashAlgorithm.values())
707+
RemoteStorePathStrategy pathStrategy = randomFrom(
708+
new RemoteStorePathStrategy(PathType.FIXED),
709+
new RemoteStorePathStrategy(PathType.HASHED_PREFIX, PathHashAlgorithm.FNV_1A)
710710
);
711711

712712
RemoteSegmentStoreDirectory.remoteDirectoryCleanup(

0 commit comments

Comments
 (0)
Please sign in to comment.