Skip to content

Commit d77cc2f

Browse files
committed
Addressing comments
Signed-off-by: Shourya Dutta Biswas <[email protected]>
1 parent f637670 commit d77cc2f

File tree

4 files changed

+275
-291
lines changed

4 files changed

+275
-291
lines changed

server/src/main/java/org/opensearch/action/admin/cluster/settings/TransportClusterUpdateSettingsAction.java

Lines changed: 13 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,10 @@
4242
import org.opensearch.cluster.ClusterState;
4343
import org.opensearch.cluster.block.ClusterBlockException;
4444
import org.opensearch.cluster.block.ClusterBlockLevel;
45-
import org.opensearch.cluster.metadata.IndexMetadata;
4645
import org.opensearch.cluster.metadata.IndexNameExpressionResolver;
4746
import org.opensearch.cluster.metadata.Metadata;
4847
import org.opensearch.cluster.node.DiscoveryNode;
4948
import org.opensearch.cluster.node.DiscoveryNodes;
50-
import org.opensearch.cluster.routing.RoutingTable;
5149
import org.opensearch.cluster.routing.allocation.AllocationService;
5250
import org.opensearch.cluster.service.ClusterManagerTaskKeys;
5351
import org.opensearch.cluster.service.ClusterManagerTaskThrottler;
@@ -60,20 +58,13 @@
6058
import org.opensearch.common.settings.SettingsException;
6159
import org.opensearch.core.action.ActionListener;
6260
import org.opensearch.core.common.io.stream.StreamInput;
63-
import org.opensearch.index.remote.RemoteMigrationIndexMetadataUpdater;
6461
import org.opensearch.node.remotestore.RemoteStoreNodeService;
6562
import org.opensearch.threadpool.ThreadPool;
6663
import org.opensearch.transport.TransportService;
6764

6865
import java.io.IOException;
69-
import java.util.Collection;
70-
import java.util.Collections;
71-
import java.util.List;
72-
import java.util.Map;
73-
import java.util.Set;
74-
import java.util.stream.Collectors;
7566

76-
import static org.opensearch.index.remote.RemoteMigrationIndexMetadataUpdater.indexHasRemoteStoreSettings;
67+
import static org.opensearch.index.remote.RemoteStoreUtils.checkAndFinalizeRemoteStoreMigration;
7768

7869
/**
7970
* Transport action for updating cluster settings
@@ -159,8 +150,6 @@ protected void clusterManagerOperation(
159150

160151
private volatile boolean changed = false;
161152

162-
private volatile boolean isSwitchingToStrictMode = false;
163-
164153
@Override
165154
public ClusterManagerTaskThrottler.ThrottlingKey getClusterManagerThrottlingKey() {
166155
return clusterUpdateSettingTaskKey;
@@ -269,27 +258,13 @@ public void onFailure(String source, Exception e) {
269258
@Override
270259
public ClusterState execute(final ClusterState currentState) {
271260
boolean isCompatibilityModeChanging = validateCompatibilityModeSettingRequest(request, state);
272-
final ClusterState clusterState = updater.updateSettings(
261+
ClusterState clusterState = updater.updateSettings(
273262
currentState,
274263
clusterSettings.upgradeSettings(request.transientSettings()),
275264
clusterSettings.upgradeSettings(request.persistentSettings()),
276265
logger
277266
);
278-
/*
279-
Remote Store migration: Checks if the applied cluster settings
280-
has switched the cluster to STRICT mode. If so, checks and applies
281-
appropriate index settings depending on the current set of node types
282-
in the cluster
283-
284-
This has been intentionally done after the cluster settings update
285-
flow. That way we are not interfering with the usual settings update
286-
and the cluster state mutation that comes along with it
287-
*/
288-
if (isCompatibilityModeChanging && isSwitchToStrictCompatibilityMode(request)) {
289-
ClusterState newStateAfterIndexMdChanges = finalizeMigration(clusterState);
290-
changed = newStateAfterIndexMdChanges != currentState;
291-
return newStateAfterIndexMdChanges;
292-
}
267+
clusterState = checkAndFinalizeRemoteStoreMigration(isCompatibilityModeChanging, request, clusterState, logger);
293268
changed = clusterState != currentState;
294269
return clusterState;
295270
}
@@ -307,9 +282,10 @@ public ClusterState execute(final ClusterState currentState) {
307282
public boolean validateCompatibilityModeSettingRequest(ClusterUpdateSettingsRequest request, ClusterState clusterState) {
308283
Settings settings = Settings.builder().put(request.persistentSettings()).put(request.transientSettings()).build();
309284
if (RemoteStoreNodeService.REMOTE_STORE_COMPATIBILITY_MODE_SETTING.exists(settings)) {
310-
String value = RemoteStoreNodeService.REMOTE_STORE_COMPATIBILITY_MODE_SETTING.get(settings).mode;
311285
validateAllNodesOfSameVersion(clusterState.nodes());
312-
if (RemoteStoreNodeService.CompatibilityMode.STRICT.mode.equals(value)) {
286+
if (RemoteStoreNodeService.REMOTE_STORE_COMPATIBILITY_MODE_SETTING.get(
287+
settings
288+
) == RemoteStoreNodeService.CompatibilityMode.STRICT) {
313289
validateAllNodesOfSameType(clusterState.nodes());
314290
}
315291
return true;
@@ -334,99 +310,18 @@ private void validateAllNodesOfSameVersion(DiscoveryNodes discoveryNodes) {
334310
* @param discoveryNodes current discovery nodes in the cluster
335311
*/
336312
private void validateAllNodesOfSameType(DiscoveryNodes discoveryNodes) {
337-
Set<Boolean> nodeTypes = discoveryNodes.getNodes()
313+
boolean allNodesDocrepEnabled = discoveryNodes.getNodes()
314+
.values()
315+
.stream()
316+
.allMatch(discoveryNode -> discoveryNode.isRemoteStoreNode() == false);
317+
boolean allNodesRemoteStoreEnabled = discoveryNodes.getNodes()
338318
.values()
339319
.stream()
340-
.map(DiscoveryNode::isRemoteStoreNode)
341-
.collect(Collectors.toSet());
342-
if (nodeTypes.size() != 1) {
320+
.allMatch(discoveryNode -> discoveryNode.isRemoteStoreNode());
321+
if (allNodesDocrepEnabled == false && allNodesRemoteStoreEnabled == false) {
343322
throw new SettingsException(
344323
"can not switch to STRICT compatibility mode when the cluster contains both remote and non-remote nodes"
345324
);
346325
}
347326
}
348-
349-
/**
350-
* Finalizes the docrep to remote-store migration process by applying remote store based index settings
351-
* on indices that are missing them. No-Op if all indices already have the settings applied through
352-
* IndexMetadataUpdater
353-
*
354-
* @param incomingState mutated cluster state after cluster settings were applied
355-
* @return new cluster state with index settings updated
356-
*/
357-
public ClusterState finalizeMigration(ClusterState incomingState) {
358-
Map<String, DiscoveryNode> discoveryNodeMap = incomingState.nodes().getNodes();
359-
if (discoveryNodeMap.isEmpty() == false) {
360-
// At this point, we have already validated that all nodes in the cluster are of uniform type.
361-
// Either all of them are remote store enabled, or all of them are docrep enabled
362-
boolean remoteStoreEnabledNodePresent = discoveryNodeMap.values().stream().findFirst().get().isRemoteStoreNode();
363-
if (remoteStoreEnabledNodePresent == true) {
364-
List<IndexMetadata> indicesWithoutRemoteStoreSettings = getIndicesWithoutRemoteStoreSettings(incomingState);
365-
if (indicesWithoutRemoteStoreSettings.isEmpty() == true) {
366-
logger.info("All indices in the cluster has remote store based index settings");
367-
} else {
368-
Metadata mutatedMetadata = applyRemoteStoreSettings(incomingState, indicesWithoutRemoteStoreSettings);
369-
return ClusterState.builder(incomingState).metadata(mutatedMetadata).build();
370-
}
371-
} else {
372-
logger.debug("All nodes in the cluster are not remote nodes. Skipping.");
373-
}
374-
}
375-
return incomingState;
376-
}
377-
378-
/**
379-
* Filters out indices which does not have remote store based
380-
* index settings applied even after all shard copies have
381-
* migrated to remote store enabled nodes
382-
*/
383-
private List<IndexMetadata> getIndicesWithoutRemoteStoreSettings(ClusterState clusterState) {
384-
Collection<IndexMetadata> allIndicesMetadata = clusterState.metadata().indices().values();
385-
if (allIndicesMetadata.isEmpty() == false) {
386-
List<IndexMetadata> indicesWithoutRemoteSettings = allIndicesMetadata.stream()
387-
.filter(idxMd -> indexHasRemoteStoreSettings(idxMd.getSettings()) == false)
388-
.collect(Collectors.toList());
389-
logger.debug(
390-
"Attempting to switch to strict mode. Count of indices without remote store settings {}",
391-
indicesWithoutRemoteSettings.size()
392-
);
393-
return indicesWithoutRemoteSettings;
394-
}
395-
return Collections.emptyList();
396-
}
397-
398-
/**
399-
* Applies remote store index settings through {@link RemoteMigrationIndexMetadataUpdater}
400-
*/
401-
private Metadata applyRemoteStoreSettings(ClusterState clusterState, List<IndexMetadata> indicesWithRemoteStoreSettings) {
402-
Metadata.Builder metadataBuilder = Metadata.builder(clusterState.getMetadata());
403-
RoutingTable currentRoutingTable = clusterState.getRoutingTable();
404-
DiscoveryNodes currentDiscoveryNodes = clusterState.getNodes();
405-
Settings currentClusterSettings = clusterState.metadata().settings();
406-
for (IndexMetadata indexMetadata : indicesWithRemoteStoreSettings) {
407-
IndexMetadata.Builder indexMetadataBuilder = IndexMetadata.builder(indexMetadata);
408-
RemoteMigrationIndexMetadataUpdater indexMetadataUpdater = new RemoteMigrationIndexMetadataUpdater(
409-
currentDiscoveryNodes,
410-
currentRoutingTable,
411-
indexMetadata,
412-
currentClusterSettings,
413-
logger
414-
);
415-
indexMetadataUpdater.maybeAddRemoteIndexSettings(indexMetadataBuilder, indexMetadata.getIndex().getName());
416-
metadataBuilder.put(indexMetadataBuilder);
417-
}
418-
return metadataBuilder.build();
419-
}
420-
421-
/**
422-
* Checks if the incoming cluster settings payload is attempting to switch
423-
* the cluster to `STRICT` compatibility mode
424-
* Visible only for tests
425-
*/
426-
public boolean isSwitchToStrictCompatibilityMode(ClusterUpdateSettingsRequest request) {
427-
Settings incomingSettings = Settings.builder().put(request.persistentSettings()).put(request.transientSettings()).build();
428-
return RemoteStoreNodeService.CompatibilityMode.STRICT.mode.equals(
429-
RemoteStoreNodeService.REMOTE_STORE_COMPATIBILITY_MODE_SETTING.get(incomingSettings).mode
430-
);
431-
}
432327
}

server/src/main/java/org/opensearch/index/remote/RemoteStoreUtils.java

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,33 @@
1111
import org.apache.logging.log4j.LogManager;
1212
import org.apache.logging.log4j.Logger;
1313
import org.opensearch.Version;
14+
import org.opensearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
1415
import org.opensearch.cluster.ClusterState;
1516
import org.opensearch.cluster.metadata.IndexMetadata;
17+
import org.opensearch.cluster.metadata.Metadata;
1618
import org.opensearch.cluster.node.DiscoveryNode;
1719
import org.opensearch.cluster.node.DiscoveryNodes;
20+
import org.opensearch.cluster.routing.RoutingTable;
1821
import org.opensearch.common.collect.Tuple;
1922
import org.opensearch.common.settings.Settings;
2023
import org.opensearch.node.remotestore.RemoteStoreNodeAttribute;
24+
import org.opensearch.node.remotestore.RemoteStoreNodeService;
2125

2226
import java.nio.ByteBuffer;
2327
import java.util.Arrays;
2428
import java.util.Base64;
29+
import java.util.Collection;
30+
import java.util.Collections;
2531
import java.util.HashMap;
2632
import java.util.List;
2733
import java.util.Locale;
2834
import java.util.Map;
2935
import java.util.Objects;
3036
import java.util.Optional;
3137
import java.util.function.Function;
38+
import java.util.stream.Collectors;
3239

40+
import static org.opensearch.index.remote.RemoteMigrationIndexMetadataUpdater.indexHasRemoteStoreSettings;
3341
import static org.opensearch.indices.RemoteStoreSettings.CLUSTER_REMOTE_STORE_PATH_HASH_ALGORITHM_SETTING;
3442
import static org.opensearch.indices.RemoteStoreSettings.CLUSTER_REMOTE_STORE_PATH_TYPE_SETTING;
3543
import static org.opensearch.indices.RemoteStoreSettings.CLUSTER_REMOTE_STORE_TRANSLOG_METADATA;
@@ -250,4 +258,119 @@ public static Map<String, String> getRemoteStoreRepoName(DiscoveryNodes discover
250258
.findFirst();
251259
return remoteNode.map(RemoteStoreNodeAttribute::getDataRepoNames).orElseGet(HashMap::new);
252260
}
261+
262+
/**
263+
* Invoked after a cluster settings update.
264+
* Checks if the applied cluster settings has switched the cluster to STRICT mode.
265+
* If so, checks and applies appropriate index settings depending on the current set
266+
* of node types in the cluster
267+
* This has been intentionally done after the cluster settings update
268+
* flow. That way we are not interfering with the usual settings update
269+
* and the cluster state mutation that comes along with it
270+
*
271+
* @param isCompatibilityModeChanging flag passed from cluster settings update call to denote if a compatibility mode change has been done
272+
* @param request request payload passed from cluster settings update
273+
* @param currentState cluster state generated after changing cluster settings were applied
274+
* @param logger Logger reference
275+
* @return Mutated cluster state with remote store index settings applied, no-op if the cluster is not switching to `STRICT` compatibility mode
276+
*/
277+
public static ClusterState checkAndFinalizeRemoteStoreMigration(
278+
boolean isCompatibilityModeChanging,
279+
ClusterUpdateSettingsRequest request,
280+
ClusterState currentState,
281+
Logger logger
282+
) {
283+
if (isCompatibilityModeChanging && isSwitchToStrictCompatibilityMode(request)) {
284+
return finalizeMigration(currentState, logger);
285+
}
286+
return currentState;
287+
}
288+
289+
/**
290+
* Finalizes the docrep to remote-store migration process by applying remote store based index settings
291+
* on indices that are missing them. No-Op if all indices already have the settings applied through
292+
* IndexMetadataUpdater
293+
*
294+
* @param incomingState mutated cluster state after cluster settings were applied
295+
* @return new cluster state with index settings updated
296+
*/
297+
public static ClusterState finalizeMigration(ClusterState incomingState, Logger logger) {
298+
Map<String, DiscoveryNode> discoveryNodeMap = incomingState.nodes().getNodes();
299+
if (discoveryNodeMap.isEmpty() == false) {
300+
// At this point, we have already validated that all nodes in the cluster are of uniform type.
301+
// Either all of them are remote store enabled, or all of them are docrep enabled
302+
boolean remoteStoreEnabledNodePresent = discoveryNodeMap.values().stream().findFirst().get().isRemoteStoreNode();
303+
if (remoteStoreEnabledNodePresent == true) {
304+
List<IndexMetadata> indicesWithoutRemoteStoreSettings = getIndicesWithoutRemoteStoreSettings(incomingState, logger);
305+
if (indicesWithoutRemoteStoreSettings.isEmpty() == true) {
306+
logger.info("All indices in the cluster has remote store based index settings");
307+
} else {
308+
Metadata mutatedMetadata = applyRemoteStoreSettings(incomingState, indicesWithoutRemoteStoreSettings, logger);
309+
return ClusterState.builder(incomingState).metadata(mutatedMetadata).build();
310+
}
311+
} else {
312+
logger.debug("All nodes in the cluster are not remote nodes. Skipping.");
313+
}
314+
}
315+
return incomingState;
316+
}
317+
318+
/**
319+
* Filters out indices which does not have remote store based
320+
* index settings applied even after all shard copies have
321+
* migrated to remote store enabled nodes
322+
*/
323+
private static List<IndexMetadata> getIndicesWithoutRemoteStoreSettings(ClusterState clusterState, Logger logger) {
324+
Collection<IndexMetadata> allIndicesMetadata = clusterState.metadata().indices().values();
325+
if (allIndicesMetadata.isEmpty() == false) {
326+
List<IndexMetadata> indicesWithoutRemoteSettings = allIndicesMetadata.stream()
327+
.filter(idxMd -> indexHasRemoteStoreSettings(idxMd.getSettings()) == false)
328+
.collect(Collectors.toList());
329+
logger.debug(
330+
"Attempting to switch to strict mode. Count of indices without remote store settings {}",
331+
indicesWithoutRemoteSettings.size()
332+
);
333+
return indicesWithoutRemoteSettings;
334+
}
335+
return Collections.emptyList();
336+
}
337+
338+
/**
339+
* Applies remote store index settings through {@link RemoteMigrationIndexMetadataUpdater}
340+
*/
341+
private static Metadata applyRemoteStoreSettings(
342+
ClusterState clusterState,
343+
List<IndexMetadata> indicesWithoutRemoteStoreSettings,
344+
Logger logger
345+
) {
346+
Metadata.Builder metadataBuilder = Metadata.builder(clusterState.getMetadata());
347+
RoutingTable currentRoutingTable = clusterState.getRoutingTable();
348+
DiscoveryNodes currentDiscoveryNodes = clusterState.getNodes();
349+
Settings currentClusterSettings = clusterState.metadata().settings();
350+
for (IndexMetadata indexMetadata : indicesWithoutRemoteStoreSettings) {
351+
IndexMetadata.Builder indexMetadataBuilder = IndexMetadata.builder(indexMetadata);
352+
RemoteMigrationIndexMetadataUpdater indexMetadataUpdater = new RemoteMigrationIndexMetadataUpdater(
353+
currentDiscoveryNodes,
354+
currentRoutingTable,
355+
indexMetadata,
356+
currentClusterSettings,
357+
logger
358+
);
359+
indexMetadataUpdater.maybeAddRemoteIndexSettings(indexMetadataBuilder, indexMetadata.getIndex().getName());
360+
metadataBuilder.put(indexMetadataBuilder);
361+
}
362+
return metadataBuilder.build();
363+
}
364+
365+
/**
366+
* Checks if the incoming cluster settings payload is attempting to switch
367+
* the cluster to `STRICT` compatibility mode
368+
* Visible only for tests
369+
*/
370+
public static boolean isSwitchToStrictCompatibilityMode(ClusterUpdateSettingsRequest request) {
371+
Settings incomingSettings = Settings.builder().put(request.persistentSettings()).put(request.transientSettings()).build();
372+
return RemoteStoreNodeService.REMOTE_STORE_COMPATIBILITY_MODE_SETTING.get(
373+
incomingSettings
374+
) == RemoteStoreNodeService.CompatibilityMode.STRICT;
375+
}
253376
}

0 commit comments

Comments
 (0)