This is an automated email from the ASF dual-hosted git repository.
namelchev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new fc8a07e0f0e IGNITE-20418 Added the multiple nodes argument to the
'indexes_force_rebuild' command (#10941)
fc8a07e0f0e is described below
commit fc8a07e0f0ebe27d4ed17612da18f90707ae60a2
Author: Vladimir Steshin <[email protected]>
AuthorDate: Fri Sep 29 14:51:12 2023 +0300
IGNITE-20418 Added the multiple nodes argument to the
'indexes_force_rebuild' command (#10941)
---
docs/_docs/tools/control-script.adoc | 4 +-
.../internal/commandline/ArgumentParser.java | 11 +-
.../GridCommandHandlerIndexForceRebuildTest.java | 255 +++++++++++++++++++--
.../internal/management/api/ArgumentGroup.java | 3 +
...rgumentGroup.java => ArgumentGroupsHolder.java} | 21 +-
.../internal/management/api/CommandUtils.java | 126 +++++++---
.../cache/CacheIndexesForceRebuildCommand.java | 179 +++++++++++++--
.../cache/CacheIndexesForceRebuildCommandArg.java | 38 ++-
.../management/cache/IndexForceRebuildTask.java | 26 ++-
...mandHandlerClusterByClassTest_cache_help.output | 6 +-
...dlerClusterByClassWithSSLTest_cache_help.output | 6 +-
11 files changed, 584 insertions(+), 91 deletions(-)
diff --git a/docs/_docs/tools/control-script.adoc
b/docs/_docs/tools/control-script.adoc
index 490c55e7f37..843878b6a5f 100644
--- a/docs/_docs/tools/control-script.adoc
+++ b/docs/_docs/tools/control-script.adoc
@@ -1071,12 +1071,12 @@ To trigger the rebuild process of all indexes for the
specified caches or the ca
tab:Unix[]
[source,shell]
----
-control.sh --cache indexes_force_rebuild --node-id nodeId --cache-names
cacheName1,...cacheNameN|--group-names groupName1,...groupNameN
+control.sh --cache indexes_force_rebuild --node-ids
nodeId1,...nodeIdN|--all-nodes --cache-names
cacheName1,...cacheNameN|--group-names groupName1,...groupNameN
----
tab:Window[]
[source,shell]
----
-control.bat --cache indexes_force_rebuild --node-id nodeId --cache-names
cacheName1,...cacheNameN|--group-names groupName1,...groupNameN
+control.bat --cache indexes_force_rebuild --node-ids
nodeId1,...nodeIdN|--all-nodes --cache-names
cacheName1,...cacheNameN|--group-names groupName1,...groupNameN
----
--
diff --git
a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/ArgumentParser.java
b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/ArgumentParser.java
index 604f3a47d24..1a6e1d19cb9 100644
---
a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/ArgumentParser.java
+++
b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/ArgumentParser.java
@@ -21,8 +21,6 @@ package org.apache.ignite.internal.commandline;
import java.lang.reflect.Field;
import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
import java.util.Deque;
import java.util.HashSet;
import java.util.Iterator;
@@ -42,6 +40,7 @@ import org.apache.ignite.internal.management.api.Argument;
import org.apache.ignite.internal.management.api.ArgumentGroup;
import org.apache.ignite.internal.management.api.CliSubcommandsWithPrefix;
import org.apache.ignite.internal.management.api.Command;
+import org.apache.ignite.internal.management.api.CommandUtils;
import org.apache.ignite.internal.management.api.CommandsRegistry;
import org.apache.ignite.internal.management.api.Positional;
import org.apache.ignite.internal.util.typedef.internal.U;
@@ -350,13 +349,11 @@ public class ArgumentParser {
(name, val) -> {}
);
- ArgumentGroup argGrp =
cmdPath.peek().argClass().getAnnotation(ArgumentGroup.class);
- Set<String> grpdFlds = argGrp == null
- ? Collections.emptySet()
- : new HashSet<>(Arrays.asList(argGrp.value()));
+ List<Set<String>> grpdFlds =
CommandUtils.argumentGroupsValues(cmdPath.peek().argClass());
Consumer<Field> namedArgCb = fld -> namedArgs.add(
- toArg.apply(fld, grpdFlds.contains(fld.getName()) ||
fld.getAnnotation(Argument.class).optional())
+ toArg.apply(fld, CommandUtils.argumentGroupIdx(grpdFlds,
fld.getName()) >= 0
+ || fld.getAnnotation(Argument.class).optional())
);
Consumer<Field> positionalArgCb = fld -> positionalArgs.add(new
CLIArgument<>(
diff --git
a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerIndexForceRebuildTest.java
b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerIndexForceRebuildTest.java
index 3486d746826..34aa9b51239 100644
---
a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerIndexForceRebuildTest.java
+++
b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerIndexForceRebuildTest.java
@@ -26,12 +26,17 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheWriteSynchronizationMode;
import org.apache.ignite.cluster.ClusterState;
+import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.IgniteEx;
import org.apache.ignite.internal.IgniteInternalFuture;
import org.apache.ignite.internal.IgniteInterruptedCheckedException;
import org.apache.ignite.internal.cache.query.index.IndexProcessor;
+import
org.apache.ignite.internal.management.cache.CacheIndexesForceRebuildCommand;
import org.apache.ignite.internal.managers.indexing.IndexesRebuildTask;
import org.apache.ignite.internal.processors.cache.GridCacheContext;
import org.apache.ignite.internal.processors.cache.IgniteCacheProxy;
@@ -40,6 +45,7 @@ import
org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheFuture
import
org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitorClosure;
import org.apache.ignite.internal.util.future.GridFutureAdapter;
import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.G;
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.internal.SB;
import org.apache.ignite.internal.util.typedef.internal.U;
@@ -55,6 +61,7 @@ import static java.lang.String.valueOf;
import static
org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_INVALID_ARGUMENTS;
import static
org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK;
import static org.apache.ignite.internal.management.api.CommandUtils.INDENT;
+import static
org.apache.ignite.internal.processors.cache.persistence.file.FilePageStoreManager.DFLT_STORE_DIR;
import static org.apache.ignite.internal.util.IgniteUtils.max;
import static org.apache.ignite.testframework.GridTestUtils.assertContains;
import static org.apache.ignite.testframework.GridTestUtils.getFieldValue;
@@ -64,6 +71,7 @@ import static
org.apache.ignite.util.GridCommandHandlerIndexingUtils.breakSqlInd
import static
org.apache.ignite.util.GridCommandHandlerIndexingUtils.complexIndexEntity;
import static
org.apache.ignite.util.GridCommandHandlerIndexingUtils.createAndFillCache;
import static
org.apache.ignite.util.GridCommandHandlerIndexingUtils.createAndFillThreeFieldsEntryCache;
+import static
org.apache.ignite.util.GridCommandHandlerIndexingUtils.personEntity;
/**
* Test for --cache indexes_force_rebuild command. Uses single cluster per
suite.
@@ -176,7 +184,7 @@ public class GridCommandHandlerIndexForceRebuildTest
extends GridCommandHandlerA
String cacheNamesOutputStr = testOut.toString();
- assertTrue(cacheNamesOutputStr.contains("WARNING: Indexes rebuild was
not started for any cache. Check command input."));
+
assertTrue(cacheNamesOutputStr.contains(CacheIndexesForceRebuildCommand.PREF_REBUILD_NOT_STARTED_SINGLE));
testOut.reset();
@@ -186,7 +194,83 @@ public class GridCommandHandlerIndexForceRebuildTest
extends GridCommandHandlerA
String grpNamesOutputStr = testOut.toString();
- assertTrue(grpNamesOutputStr.contains("WARNING: Indexes rebuild was
not started for any cache. Check command input."));
+
assertTrue(grpNamesOutputStr.contains(CacheIndexesForceRebuildCommand.PREF_REBUILD_NOT_STARTED_SINGLE));
+ }
+
+ /**
+ * Test the command output on a cache with node filter.
+ */
+ @Test
+ public void testWithNodeFilter() throws Exception {
+ injectTestSystemOut();
+
+ try {
+ grid(1).createCache(new CacheConfiguration<>("cacheWithNodeFilter")
+ .setNodeFilter(n -> n.consistentId().toString().endsWith("1"))
+
.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC)
+ .setBackups(1)
+ .setAtomicityMode(CacheAtomicityMode.ATOMIC)
+ .setQueryEntities(Collections.singletonList(personEntity())));
+
+ for (int i = 0; i < 100; ++i)
+ grid(1).cache("cacheWithNodeFilter").put(i, new Person(i * 10,
"Name_" + 1));
+
+ assertEquals(EXIT_CODE_OK, execute("--cache",
"indexes_force_rebuild", "--all-nodes", "--cache-names",
+ "cacheWithNodeFilter"));
+
+ String cacheNamesOutputStr = testOut.toString();
+
+ validateMultiNodeOutput(cacheNamesOutputStr,
CacheIndexesForceRebuildCommand.PREF_REBUILD_STARTED,
+ grid(1).localNode().id().toString());
+
+ validateMultiNodeOutput(cacheNamesOutputStr,
CacheIndexesForceRebuildCommand.PREF_CACHES_NOT_FOUND,
+ grid(LAST_NODE_NUM).localNode().id().toString());
+ validateMultiNodeOutput(cacheNamesOutputStr,
CacheIndexesForceRebuildCommand.PREF_CACHES_NOT_FOUND,
+ grid(0).localNode().id().toString());
+
+ validateMultiNodeOutput(cacheNamesOutputStr,
CacheIndexesForceRebuildCommand.PREF_REBUILD_NOT_STARTED,
+ grid(0).localNode().id().toString());
+ validateMultiNodeOutput(cacheNamesOutputStr,
CacheIndexesForceRebuildCommand.PREF_REBUILD_NOT_STARTED,
+ grid(LAST_NODE_NUM).localNode().id().toString());
+
+ waitForIndexesRebuild(grid(1));
+ }
+ finally {
+ grid(LAST_NODE_NUM).destroyCache("cacheWithNodeFilter");
+
+ awaitPartitionMapExchange();
+
+ // TODO Remove after IGNITE-20507.
+ // Cleaning cache meta being kept.
+ for (Ignite ig : G.allGrids()) {
+ U.delete(U.resolveWorkDirectory(U.defaultWorkDirectory(),
DFLT_STORE_DIR + '/' + ig.name()
+ + "/cache-cacheWithNodeFilter", false));
+ }
+ }
+ }
+
+ /**
+ * Checks error messages when trying to rebuild indexes for non-existent
cache of group on several nodes
+ * using '--node-ids'.
+ */
+ @Test
+ public void testEmptyResultTwoNodes() {
+ injectTestSystemOut();
+
+ String nids = grid(LAST_NODE_NUM).localNode().id().toString() + ',' +
grid(0).localNode().id().toString();
+
+ assertEquals(EXIT_CODE_OK, execute("--cache", "indexes_force_rebuild",
"--node-ids", nids,
+ "--cache-names", CACHE_NAME_NON_EXISTING));
+
+ String cacheNamesOutputStr = testOut.toString();
+
+
assertFalse(cacheNamesOutputStr.contains(CacheIndexesForceRebuildCommand.PREF_REBUILD_STARTED));
+
assertFalse(cacheNamesOutputStr.contains(CacheIndexesForceRebuildCommand.PREF_REBUILD_NOT_STARTED_SINGLE));
+
+ validateMultiNodeOutput(cacheNamesOutputStr,
CacheIndexesForceRebuildCommand.PREF_REBUILD_NOT_STARTED,
+ grid(LAST_NODE_NUM).localNode().id().toString());
+ validateMultiNodeOutput(cacheNamesOutputStr,
CacheIndexesForceRebuildCommand.PREF_REBUILD_NOT_STARTED,
+ grid(0).localNode().id().toString());
}
/**
@@ -209,6 +293,37 @@ public class GridCommandHandlerIndexForceRebuildTest
extends GridCommandHandlerA
removeLogListener(grid(LAST_NODE_NUM), lsnr);
}
+ /**
+ * Checks two arguments in the group are not allowed.
+ */
+ @Test
+ public void testInvalidArgumentGroups() {
+ injectTestSystemOut();
+
+ assertContains(log, executeCommand(EXIT_CODE_INVALID_ARGUMENTS,
"--cache", "indexes_force_rebuild",
+ "--node-ids", grid(LAST_NODE_NUM).localNode().id().toString()
+ ',' + grid(0).localNode().id().toString(),
+ "--node-id", grid(LAST_NODE_NUM).localNode().id().toString(),
+ "--cache-names", CACHE_NAME_NO_GRP),
+ "Only one of [--node-ids, --all-nodes, --node-id] allowed");
+
+ assertContains(log, executeCommand(EXIT_CODE_INVALID_ARGUMENTS,
"--cache", "indexes_force_rebuild",
+ "--node-ids", grid(LAST_NODE_NUM).localNode().id().toString()
+ ',' + grid(0).localNode().id().toString(),
+ "--all-nodes",
+ "--cache-names", CACHE_NAME_NO_GRP),
+ "Only one of [--node-ids, --all-nodes, --node-id] allowed");
+
+ assertContains(log, executeCommand(EXIT_CODE_INVALID_ARGUMENTS,
"--cache", "indexes_force_rebuild",
+ "--all-nodes",
+ "--node-id", grid(LAST_NODE_NUM).localNode().id().toString(),
+ "--cache-names", CACHE_NAME_NO_GRP),
+ "Only one of [--node-ids, --all-nodes, --node-id] allowed");
+
+ assertContains(log, executeCommand(EXIT_CODE_INVALID_ARGUMENTS,
"--cache", "indexes_force_rebuild",
+ "--node-id", grid(LAST_NODE_NUM).localNode().id().toString(),
+ "--cache-names", CACHE_NAME_NO_GRP, "--group-names",
CACHE_NAME_NO_GRP),
+ "Only one of [--group-names, --cache-names] allowed");
+ }
+
/**
* Checks --node-id and --cache-names options,
* correctness of utility output and the fact that indexes were actually
rebuilt.
@@ -268,6 +383,84 @@ public class GridCommandHandlerIndexForceRebuildTest
extends GridCommandHandlerA
}
}
+ /**
+ * Checks output of index rebuilding launched on several nodes using
'--nodes-ids'.
+ */
+ @Test
+ public void testIndexRebuildOutputTwoNodes() throws Exception {
+ blockRebuildIdx.put(CACHE_NAME_2_1, new GridFutureAdapter<>());
+
+ injectTestSystemOut();
+
+ try {
+ triggerIndexRebuild(LAST_NODE_NUM,
Collections.singletonList(CACHE_NAME_2_1));
+
+ assertEquals(EXIT_CODE_OK, execute("--cache",
"indexes_force_rebuild",
+ "--node-ids", grid(LAST_NODE_NUM).localNode().id().toString()
+ ',' + grid(0).localNode().id().toString(),
+ "--cache-names", CACHE_NAME_1_1 + ',' + CACHE_NAME_2_1 + ',' +
CACHE_NAME_NON_EXISTING));
+
+ String outputStr = testOut.toString();
+
+ validateMultiNodeOutput(outputStr,
CacheIndexesForceRebuildCommand.PREF_CACHES_NOT_FOUND, CACHE_NAME_NON_EXISTING);
+ validateMultiNodeOutput(outputStr,
CacheIndexesForceRebuildCommand.PREF_CACHES_NOT_FOUND,
+ grid(LAST_NODE_NUM).localNode().id().toString());
+ validateMultiNodeOutput(outputStr,
CacheIndexesForceRebuildCommand.PREF_CACHES_NOT_FOUND,
+ grid(0).localNode().id().toString());
+
+ validateMultiNodeOutput(outputStr,
CacheIndexesForceRebuildCommand.PREF_REBUILDING, CACHE_NAME_2_1);
+ validateMultiNodeOutput(outputStr,
CacheIndexesForceRebuildCommand.PREF_REBUILDING,
+ grid(LAST_NODE_NUM).localNode().id().toString());
+
+ validateMultiNodeOutput(outputStr,
CacheIndexesForceRebuildCommand.PREF_REBUILD_STARTED, CACHE_NAME_1_1);
+ validateMultiNodeOutput(outputStr,
CacheIndexesForceRebuildCommand.PREF_REBUILD_STARTED,
+ grid(LAST_NODE_NUM).localNode().id().toString());
+ validateMultiNodeOutput(outputStr,
CacheIndexesForceRebuildCommand.PREF_REBUILD_STARTED,
+ grid(0).localNode().id().toString());
+ }
+ finally {
+ blockRebuildIdx.remove(CACHE_NAME_2_1);
+
+ assertTrue(waitForIndexesRebuild(grid(LAST_NODE_NUM)));
+ }
+ }
+
+ /**
+ * Checks output of index rebuilding launched on all nodes using
'--all-nodes'.
+ */
+ @Test
+ public void testIndexRebuildAllNodes() throws
IgniteInterruptedCheckedException {
+ injectTestSystemOut();
+
+ LogListener[] cacheLsnrs = new LogListener[GRIDS_NUM];
+
+ try {
+ for (int i = 0; i < GRIDS_NUM; i++)
+ cacheLsnrs[i] = installRebuildCheckListener(grid(i),
CACHE_NAME_1_1);
+
+ assertEquals(EXIT_CODE_OK, execute("--cache",
"indexes_force_rebuild", "--all-nodes",
+ "--cache-names", CACHE_NAME_1_1));
+
+ String outputStr = testOut.toString();
+
+ validateMultiNodeOutput(outputStr,
CacheIndexesForceRebuildCommand.PREF_REBUILD_STARTED, CACHE_NAME_1_1);
+
+ for (int i = 0; i < GRIDS_NUM; i++) {
+ validateMultiNodeOutput(outputStr,
CacheIndexesForceRebuildCommand.PREF_REBUILD_STARTED,
+ grid(i).localNode().id().toString());
+ }
+
+ for (Ignite ig : G.allGrids())
+ waitForIndexesRebuild((IgniteEx)ig);
+
+ for (LogListener lsnr : cacheLsnrs)
+ assertTrue(lsnr.check());
+ }
+ finally {
+ for (int i = 0; i < GRIDS_NUM; i++)
+ removeLogListener(grid(i), cacheLsnrs[i]);
+ }
+ }
+
/**
* Checks --node-id and --group-names options,
* correctness of utility output and the fact that indexes were actually
rebuilt.
@@ -514,25 +707,25 @@ public class GridCommandHandlerIndexForceRebuildTest
extends GridCommandHandlerA
*/
@Test
public void testSequentialForceRebuildIndexes() throws Exception {
- IgniteEx grid = grid(0);
+ Collection<IgniteEx> grids = Collections.singletonList(grid(0));
injectTestSystemOut();
String outputStr;
- forceRebuildIndices(F.asList(CACHE_NAME_1_1), grid);
+ forceRebuildIndices(F.asList(CACHE_NAME_1_1), grids);
outputStr = testOut.toString();
validateOutputIndicesRebuildWasStarted(outputStr, F.asMap(GRP_NAME_1,
F.asList(CACHE_NAME_1_1)));
- assertFalse(outputStr.contains("WARNING: These caches have indexes
rebuilding in progress:"));
+
assertFalse(outputStr.contains(CacheIndexesForceRebuildCommand.PREF_REBUILDING));
- forceRebuildIndices(F.asList(CACHE_NAME_1_1), grid);
+ forceRebuildIndices(F.asList(CACHE_NAME_1_1), grids);
validateOutputIndicesRebuildWasStarted(outputStr, F.asMap(GRP_NAME_1,
F.asList(CACHE_NAME_1_1)));
- assertFalse(outputStr.contains("WARNING: These caches have indexes
rebuilding in progress:"));
+
assertFalse(outputStr.contains(CacheIndexesForceRebuildCommand.PREF_REBUILDING));
}
/**
@@ -541,7 +734,7 @@ public class GridCommandHandlerIndexForceRebuildTest
extends GridCommandHandlerA
* @param outputStr CLI {@code control.sh} utility output.
* @param cacheNames Cache names to print.
*/
- private void validateOutputCacheNamesNotFound(String outputStr, String...
cacheNames) {
+ private static void validateOutputCacheNamesNotFound(String outputStr,
String... cacheNames) {
assertContains(
log,
outputStr,
@@ -568,7 +761,7 @@ public class GridCommandHandlerIndexForceRebuildTest
extends GridCommandHandlerA
* @param strings List of strings.
* @return Formated text.
*/
- private String makeStringListWithIndent(String... strings) {
+ private static String makeStringListWithIndent(String... strings) {
return INDENT + String.join(U.nl() + INDENT, strings);
}
@@ -578,7 +771,7 @@ public class GridCommandHandlerIndexForceRebuildTest
extends GridCommandHandlerA
* @param cacheGroputToNames Cache groups mapping to non-existing cache
names.
* @return Text for CLI print output for given caches.
*/
- private String makeStringListForCacheGroupsAndNames(Map<String,
List<String>> cacheGroputToNames) {
+ private static String makeStringListForCacheGroupsAndNames(Map<String,
List<String>> cacheGroputToNames) {
SB sb = new SB();
for (Map.Entry<String, List<String>> entry :
cacheGroputToNames.entrySet()) {
@@ -597,7 +790,7 @@ public class GridCommandHandlerIndexForceRebuildTest
extends GridCommandHandlerA
* @param outputStr CLI {@code control.sh} utility output.
* @param cacheGroputToNames Cache groups mapping to non-existing cache
names.
*/
- private void validateOutputIndicesRebuildingInProgress(String outputStr,
Map<String, List<String>> cacheGroputToNames) {
+ private static void validateOutputIndicesRebuildingInProgress(String
outputStr, Map<String, List<String>> cacheGroputToNames) {
String caches =
makeStringListForCacheGroupsAndNames(cacheGroputToNames);
assertContains(
@@ -623,6 +816,35 @@ public class GridCommandHandlerIndexForceRebuildTest
extends GridCommandHandlerA
);
}
+ /**
+ * Validates the multi-node command output. Searches for the passed
prefix/header and the target strings below it.
+ *
+ * @param outputStr The output.
+ * @param prefix Prefix or header to search.
+ * @param targetStr Target string to search after {@code prefix}.
+ */
+ private static void validateMultiNodeOutput(String outputStr, String
prefix, String targetStr) {
+ String[] lines = outputStr.split(U.nl());
+
+ for (int i = 0, heraderIdx = -1; i < lines.length; ++i) {
+ String line = lines[i];
+
+ if (heraderIdx < 0) {
+ if (line.contains(prefix))
+ heraderIdx = i;
+
+ continue;
+ }
+
+ // Search next line after the header.
+ if (i == heraderIdx + 1 && line.contains(targetStr))
+ return;
+ }
+
+ throw new IllegalStateException("Target string '" + targetStr + "' not
found after header '" + prefix
+ + "' in the command output.");
+ }
+
/**
* Triggers indexes rebuild for ALL caches on grid node with index {@code
igniteIdx}.
*
@@ -772,21 +994,24 @@ public class GridCommandHandlerIndexForceRebuildTest
extends GridCommandHandlerA
* Force rebuilds indices for chosen caches, and waits until rebuild
process is complete.
*
* @param cacheNames Cache names need indices to rebuild.
- * @param grid Ignite node.
+ * @param grids Ignite nodes.
* @throws Exception If failed.
*/
- private void forceRebuildIndices(Iterable<String> cacheNames, IgniteEx
grid) throws Exception {
+ private void forceRebuildIndices(Iterable<String> cacheNames,
Collection<IgniteEx> grids) throws Exception {
String cacheNamesArg = String.join(",", cacheNames);
assertEquals(
EXIT_CODE_OK,
execute(
"--cache", "indexes_force_rebuild",
- "--node-id", grid.localNode().id().toString(),
+ grids.size() == 1 ? "--node-id" : "--node-ids",
+ grids.size() == 1 ?
grids.iterator().next().localNode().id().toString()
+ : grids.stream().map(g ->
g.localNode().id().toString()).collect(Collectors.joining(",")),
"--cache-names", cacheNamesArg
)
);
- waitForIndexesRebuild(grid, getTestTimeout(), Collections.emptyList());
+ for (IgniteEx g : grids)
+ waitForIndexesRebuild(g, getTestTimeout(),
Collections.emptyList());
}
}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/api/ArgumentGroup.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/api/ArgumentGroup.java
index f55c684892a..8f48a04a4e2 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/management/api/ArgumentGroup.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/api/ArgumentGroup.java
@@ -18,6 +18,7 @@
package org.apache.ignite.internal.management.api;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -28,9 +29,11 @@ import java.lang.annotation.Target;
* If values from {@link #value()} not conform restrictions then error will be
thrown.
*
* @see org.apache.ignite.internal.management.SystemViewCommandArg
+ * @see ArgumentGroupsHolder
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
+@Repeatable(ArgumentGroupsHolder.class)
public @interface ArgumentGroup {
/** @return Names of argument class fields to forms "group" restriction. */
public String[] value();
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/api/ArgumentGroup.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/api/ArgumentGroupsHolder.java
similarity index 61%
copy from
modules/core/src/main/java/org/apache/ignite/internal/management/api/ArgumentGroup.java
copy to
modules/core/src/main/java/org/apache/ignite/internal/management/api/ArgumentGroupsHolder.java
index f55c684892a..d39a740200d 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/management/api/ArgumentGroup.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/api/ArgumentGroupsHolder.java
@@ -18,26 +18,17 @@
package org.apache.ignite.internal.management.api;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- * Defines commands arguments restriction.
- * Group of {@link #value()} fields must be presented in Arguments.
- * If values from {@link #value()} not conform restrictions then error will be
thrown.
- *
- * @see org.apache.ignite.internal.management.SystemViewCommandArg
+ * {@link Repeatable} container for {@link ArgumentGroup}.
*/
@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface ArgumentGroup {
- /** @return Names of argument class fields to forms "group" restriction. */
- public String[] value();
-
- /** @return {@code True} if arguments is optional, {@code false} if
required. */
- public boolean optional();
-
- /** @return {@code True} if only one of argument from group allowed. */
- public boolean onlyOneOf() default false;
+@Target({ElementType.TYPE})
+public @interface ArgumentGroupsHolder {
+ /** Array of {@link ArgumentGroup} annotations. */
+ ArgumentGroup[] value();
}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/api/CommandUtils.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/api/CommandUtils.java
index ad6d5ac724b..76e37070e52 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/management/api/CommandUtils.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/api/CommandUtils.java
@@ -369,21 +369,27 @@ public class CommandUtils {
List<Field> positionalParams = new ArrayList<>();
List<Field> namedParams = new ArrayList<>();
- ArgumentGroup argGrp = argCls.getAnnotation(ArgumentGroup.class);
+ List<ArgumentGroup> argGprs = argumentGroups(argCls);
- Set<String> grpNames = argGrp != null
- ? new HashSet<>(Arrays.asList(argGrp.value()))
- : Collections.emptySet();
+ List<Set<String>> grpNames = argumentGroupsValues(argGprs);
- List<Field> grpFlds = new ArrayList<>();
+ List<List<Field>> grpFlds = grpNames.isEmpty() ?
Collections.emptyList() : new ArrayList<>(grpNames.size());
+
+ grpNames.forEach(gf -> grpFlds.add(grpFlds.size(), null));
// Iterates classes from the roots.
for (int i = classes.size() - 1; i >= 0; i--) {
Field[] flds = classes.get(i).getDeclaredFields();
for (Field fld : flds) {
- if (grpNames.contains(fld.getName()))
- grpFlds.add(fld);
+ int argGrpIdx = argumentGroupIdx(grpNames, fld.getName());
+
+ if (argGrpIdx >= 0) {
+ if (grpFlds.get(argGrpIdx) == null)
+ grpFlds.set(argGrpIdx, new ArrayList<>());
+
+ grpFlds.get(argGrpIdx).add(fld);
+ }
else if (fld.isAnnotationPresent(Positional.class))
positionalParams.add(fld);
else if (fld.isAnnotationPresent(Argument.class))
@@ -395,8 +401,61 @@ public class CommandUtils {
namedParams.forEach(namedParamVisitor);
- if (argGrp != null)
- argumentGroupVisitor.accept(argGrp, grpFlds);
+ for (int i = 0; i < grpFlds.size(); ++i)
+ argumentGroupVisitor.accept(argGprs.get(i), grpFlds.get(i));
+ }
+
+ /**
+ * @return List of declared {@link ArgumentGroup} at {@code cls}.
Singleton list if only one argument group is
+ * declared. Empty list if no argument group is declared.
+ */
+ private static List<ArgumentGroup> argumentGroups(Class<?> cls) {
+ ArgumentGroup singleGrp = cls.getAnnotation(ArgumentGroup.class);
+
+ if (singleGrp != null) {
+ assert cls.getAnnotation(ArgumentGroupsHolder.class) == null;
+
+ return Collections.singletonList(singleGrp);
+ }
+
+ ArgumentGroupsHolder grps =
cls.getAnnotation(ArgumentGroupsHolder.class);
+
+ return grps == null ? Collections.emptyList() :
Arrays.asList(grps.value());
+ }
+
+ /**
+ * @return Sets list of {@link ArgumentGroup#value()} declared at {@code
cls}.
+ */
+ public static List<Set<String>> argumentGroupsValues(Class<?> cls) {
+ return argumentGroupsValues(argumentGroups(cls));
+ }
+
+ /**
+ * @return Sets list of {@link ArgumentGroup#value()} holding in {@code
argGrps}.
+ * @see #argumentGroupsValues(Class)
+ */
+ public static List<Set<String>> argumentGroupsValues(List<ArgumentGroup>
argGrps) {
+ List<Set<String>> res = argGrps.stream().map(grp -> new
HashSet<>(Arrays.asList(grp.value())))
+ .collect(Collectors.toList());
+
+ // Checks that argument groups only unique values.
+ assert
F.flatCollections(res).stream().collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()))
+ .entrySet().stream().noneMatch(e -> e.getValue() > 1) : "Argument
groups " + argGrps + " have not unique arguments";
+
+ return res;
+ }
+
+ /**
+ * @return Index of first value set in {@code argGrpValues} containing
{@code name}. -1 if not found.
+ * @see #argumentGroupsValues(Class)
+ */
+ public static int argumentGroupIdx(List<Set<String>> argGrpValues, String
name) {
+ for (int i = 0; i < argGrpValues.size(); ++i) {
+ if (argGrpValues.get(i).contains(name))
+ return i;
+ }
+
+ return -1;
}
/**
@@ -690,8 +749,12 @@ public class CommandUtils {
})
);
- if (arg.argGrp != null && (!arg.grpOptional() &&
!arg.grpFldExists))
- throw new IllegalArgumentException("One of " +
toFormattedNames(argCls, arg.grpdFlds) + " required");
+ for (int grpIdx = 0; grpIdx < arg.argGrps.size(); ++grpIdx) {
+ if (!arg.argGrps.get(grpIdx).optional() &&
!arg.grpFldExists[grpIdx]) {
+ throw new IllegalArgumentException("One of " +
toFormattedNames(argCls, arg.grpdFlds.get(grpIdx))
+ + " required");
+ }
+ }
return arg.res;
}
@@ -737,32 +800,29 @@ public class CommandUtils {
/** */
private static class ArgumentState<A extends IgniteDataTransferObject>
implements BiConsumer<Field, Object> {
/** */
- final A res;
+ private final A res;
/** */
- final ArgumentGroup argGrp;
+ private final List<ArgumentGroup> argGrps;
/** */
- boolean grpFldExists;
+ private final @Nullable boolean[] grpFldExists;
/** */
- int idx;
+ private int idx;
/** */
- final Set<String> grpdFlds;
+ private final List<Set<String>> grpdFlds;
/** */
public ArgumentState(Class<A> argCls) throws InstantiationException,
IllegalAccessException {
res = argCls.newInstance();
- argGrp = argCls.getAnnotation(ArgumentGroup.class);
- grpdFlds = argGrp == null
- ? Collections.emptySet()
- : new HashSet<>(Arrays.asList(argGrp.value()));
- }
- /** */
- public boolean grpOptional() {
- return argGrp == null || argGrp.optional();
+ argGrps = argumentGroups(argCls);
+
+ grpdFlds = argumentGroupsValues(argGrps);
+
+ grpFldExists = argGrps.isEmpty() ? null : new
boolean[argGrps.size()];
}
/** */
@@ -776,10 +836,14 @@ public class CommandUtils {
/** {@inheritDoc} */
@Override public void accept(Field fld, Object val) {
- boolean grpdFld = grpdFlds.contains(fld.getName());
+ int argGrpIdx = argumentGroupIdx(grpdFlds, fld.getName());
+
+ assert argGrpIdx < argGrps.size();
+
+ ArgumentGroup argGrp = argGrpIdx < 0 ? null :
argGrps.get(argGrpIdx);
if (val == null) {
- if (grpdFld || fld.getAnnotation(Argument.class).optional())
+ if (argGrp != null ||
fld.getAnnotation(Argument.class).optional())
return;
String name = fld.isAnnotationPresent(Positional.class)
@@ -792,14 +856,16 @@ public class CommandUtils {
if (Objects.equals(val, get(fld)))
return;
- if (grpdFld) {
- if (grpFldExists && (argGrp != null && argGrp.onlyOneOf())) {
+ if (argGrp != null) {
+ assert grpFldExists != null;
+
+ if (grpFldExists[argGrpIdx] && argGrp.onlyOneOf()) {
throw new IllegalArgumentException(
- "Only one of " + toFormattedNames(res.getClass(),
grpdFlds) + " allowed"
+ "Only one of " + toFormattedNames(res.getClass(),
grpdFlds.get(argGrpIdx)) + " allowed"
);
}
- grpFldExists = true;
+ grpFldExists[argGrpIdx] = true;
}
set(fld, val);
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheIndexesForceRebuildCommand.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheIndexesForceRebuildCommand.java
index 575e1e0d085..224c957159f 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheIndexesForceRebuildCommand.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheIndexesForceRebuildCommand.java
@@ -18,17 +18,45 @@
package org.apache.ignite.internal.management.cache;
import java.util.Collection;
-import java.util.List;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
import java.util.function.Consumer;
+import java.util.stream.Collectors;
import org.apache.ignite.internal.client.GridClientNode;
import org.apache.ignite.internal.management.api.CommandUtils;
import org.apache.ignite.internal.management.api.ComputeCommand;
import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.SB;
+import org.apache.ignite.internal.util.typedef.internal.U;
import static org.apache.ignite.internal.management.api.CommandUtils.INDENT;
/** Index force rebuild. */
-public class CacheIndexesForceRebuildCommand implements
ComputeCommand<CacheIndexesForceRebuildCommandArg, IndexForceRebuildTaskRes> {
+public class CacheIndexesForceRebuildCommand
+ implements ComputeCommand<CacheIndexesForceRebuildCommandArg, Map<UUID,
IndexForceRebuildTaskRes>> {
+ /** */
+ public static final String PREF_REBUILDING = "WARNING: These caches have
indexes rebuilding in progress:";
+
+ /** */
+ public static final String PREF_CACHES_NOT_FOUND = "WARNING: These caches
were not found:";
+
+ /** */
+ private static final String PREF_GROUPS_NOT_FOUND = "WARNING: These cache
groups were not found:";
+
+ /** */
+ public static final String PREF_REBUILD_STARTED = "Indexes rebuild was
started for these caches:";
+
+ /** */
+ public static final String PREF_REBUILD_NOT_STARTED_SINGLE = "WARNING:
Indexes rebuild was not started for " +
+ "any cache. Check command input";
+
+ /** */
+ public static final String PREF_REBUILD_NOT_STARTED = "WARNING: Indexes
rebuild was not started for " +
+ "any cache on the following nodes. Check the command input:";
+
/** {@inheritDoc} */
@Override public String description() {
return "Triggers rebuild of all indexes for specified caches or cache
groups";
@@ -46,27 +74,89 @@ public class CacheIndexesForceRebuildCommand implements
ComputeCommand<CacheInde
/** {@inheritDoc} */
@Override public Collection<GridClientNode>
nodes(Collection<GridClientNode> nodes, CacheIndexesForceRebuildCommandArg arg)
{
+ Collection<GridClientNode> res;
+
+ if (arg.allNodes())
+ res = nodes.stream().filter(n ->
!n.isClient()).collect(Collectors.toList());
+ else {
+ res = arg.nodeIds() != null
+ ? CommandUtils.nodes(arg.nodeIds(), nodes)
+ : CommandUtils.node(arg.nodeId(), nodes);
+
+ if (!F.isEmpty(res)) {
+ for (GridClientNode n : res) {
+ if (n != null && n.isClient())
+ throw new IllegalArgumentException("Please, specify
only server node ids");
+ }
+ }
+ }
+
+ if (F.isEmpty(res))
+ throw new IllegalArgumentException("Please, specify oat least one
server node");
+
+ return res;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void printResult(
+ CacheIndexesForceRebuildCommandArg arg,
+ Map<UUID, IndexForceRebuildTaskRes> results,
+ Consumer<String> printer
+ ) {
if (arg.nodeId() != null) {
- List<GridClientNode> node = CommandUtils.node(arg.nodeId(), nodes);
+ printSingleResult(arg, results.values().iterator().next(),
printer);
+
+ return;
+ }
- if (node.get(0) != null && node.get(0).isClient())
- throw new IllegalArgumentException("Please, specify server
node id");
+ Map<String, Set<UUID>> notFound = new HashMap<>();
+ Map<IndexRebuildStatusInfoContainer, Set<UUID>> rebuilding = new
HashMap<>();
+ Map<IndexRebuildStatusInfoContainer, Set<UUID>> started = new
HashMap<>();
+ Set<UUID> notStarted = new HashSet<>();
- return node;
+ results.forEach((nodeId, res) -> {
+ storeCacheResults(notFound, res.notFoundCacheNames(), nodeId);
+
+ storeCacheResults(rebuilding, res.cachesWithRebuildInProgress(),
nodeId);
+
+ if (!F.isEmpty(res.cachesWithStartedRebuild()))
+ storeCacheResults(started, res.cachesWithStartedRebuild(),
nodeId);
+ else
+ notStarted.add(nodeId);
+ });
+
+ SB b = new SB();
+
+ if (!F.isEmpty(notFound))
+ printBlock(b, arg.groupNames() == null ? PREF_CACHES_NOT_FOUND :
PREF_GROUPS_NOT_FOUND, notFound);
+
+ if (!F.isEmpty(notStarted)) {
+ printHeader(b, PREF_REBUILD_NOT_STARTED);
+
+ printEntryNewLine(b);
+
+ b.a(nodeIdsString(notStarted));
}
- return null;
+ if (!F.isEmpty(rebuilding))
+ printBlock(b, PREF_REBUILDING, rebuilding);
+
+ if (!F.isEmpty(started))
+ printBlock(b, PREF_REBUILD_STARTED, started);
+
+ printer.accept(b.toString().trim());
}
- /** {@inheritDoc} */
- @Override public void printResult(
+ /**
+ * Prints result if only single node was requested with '--node-id'
instead of '--node-ids'.
+ */
+ private static void printSingleResult(
CacheIndexesForceRebuildCommandArg arg,
IndexForceRebuildTaskRes res,
Consumer<String> printer
) {
if (!F.isEmpty(res.notFoundCacheNames())) {
- String warning = arg.groupNames() == null ?
- "WARNING: These caches were not found:" : "WARNING: These
cache groups were not found:";
+ String warning = arg.groupNames() == null ? PREF_CACHES_NOT_FOUND
: PREF_GROUPS_NOT_FOUND;
printer.accept(warning);
@@ -79,7 +169,7 @@ public class CacheIndexesForceRebuildCommand implements
ComputeCommand<CacheInde
}
if (!F.isEmpty(res.cachesWithRebuildInProgress())) {
- printer.accept("WARNING: These caches have indexes rebuilding in
progress:");
+ printer.accept(PREF_REBUILDING);
printInfos(res.cachesWithRebuildInProgress(), printer);
@@ -87,20 +177,79 @@ public class CacheIndexesForceRebuildCommand implements
ComputeCommand<CacheInde
}
if (!F.isEmpty(res.cachesWithStartedRebuild())) {
- printer.accept("Indexes rebuild was started for these caches:");
+ printer.accept(PREF_REBUILD_STARTED);
printInfos(res.cachesWithStartedRebuild(), printer);
}
else
- printer.accept("WARNING: Indexes rebuild was not started for any
cache. Check command input.");
+ printer.accept(PREF_REBUILD_NOT_STARTED_SINGLE);
printer.accept("");
}
/** */
- private void printInfos(Collection<IndexRebuildStatusInfoContainer> infos,
Consumer<String> printer) {
+ private static <T> void storeCacheResults(Map<T, Set<UUID>> to,
Collection<T> keys, UUID nodeId) {
+ if (F.isEmpty(keys))
+ return;
+
+ for (T kv : keys) {
+ to.compute(kv, (kv0, nodeIds0) -> {
+ if (nodeIds0 == null)
+ nodeIds0 = new HashSet<>();
+
+ nodeIds0.add(nodeId);
+
+ return nodeIds0;
+ });
+ }
+ }
+
+ /** */
+ private static void printInfos(Collection<IndexRebuildStatusInfoContainer>
infos, Consumer<String> printer) {
infos.stream()
.sorted(IndexRebuildStatusInfoContainer.comparator())
.forEach(rebuildStatusInfo -> printer.accept(INDENT +
rebuildStatusInfo.toString()));
}
+
+ /** */
+ private static void printBlock(SB b, String header, Map<?, ? extends
Collection<UUID>> data) {
+ printHeader(b, header);
+
+ data.forEach((cacheInfo, nodes) -> {
+ printEntryNewLine(b);
+
+ printCacheInfo(b, cacheInfo);
+
+ b.a(" on nodes ").a(nodeIdsString(nodes)).a('.');
+ });
+ }
+
+ /** */
+ private static void printEntryNewLine(SB b) {
+ b.a(U.nl()).a(INDENT);
+ }
+
+ /** */
+ private static String nodeIdsString(Collection<UUID> nodes) {
+ return nodes.stream().map(uuid -> '\'' + uuid.toString() +
'\'').collect(Collectors.joining(", "));
+ }
+
+ /** */
+ private static void printHeader(SB b, String header) {
+ b.a(U.nl()).a(U.nl()).a(header);
+ }
+
+ /** */
+ private static void printCacheInfo(SB b, Object info) {
+ if (info.getClass() == String.class)
+ b.a('\'').a(info).a('\'');
+ else if (info instanceof IndexRebuildStatusInfoContainer) {
+ IndexRebuildStatusInfoContainer status =
(IndexRebuildStatusInfoContainer)info;
+
+ b.a('\'').a(status.cacheName()).a('\'');
+
+ if (!F.isEmpty(status.groupName()))
+ b.a(" (groupName='").a(status.groupName()).a("')");
+ }
+ }
}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheIndexesForceRebuildCommandArg.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheIndexesForceRebuildCommandArg.java
index 7531b157871..111e9f24d22 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheIndexesForceRebuildCommandArg.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheIndexesForceRebuildCommandArg.java
@@ -27,15 +27,27 @@ import
org.apache.ignite.internal.management.api.ArgumentGroup;
import org.apache.ignite.internal.util.typedef.internal.U;
/** */
+@ArgumentGroup(value = {"nodeIds", "allNodes", "nodeId"}, onlyOneOf = true,
optional = false)
@ArgumentGroup(value = {"cacheNames", "groupNames"}, onlyOneOf = true,
optional = false)
public class CacheIndexesForceRebuildCommandArg extends
IgniteDataTransferObject {
/** */
private static final long serialVersionUID = 0;
/** */
- @Argument(description = "Specify node for indexes rebuild", example =
"nodeId")
+ @Argument(description = "Specify node for indexes rebuild (deprecated. Use
--node-ids instead)", example = "nodeId")
private UUID nodeId;
+ /** */
+ @Argument(
+ description = "Comma-separated list of nodes ids to run index rebuild
on",
+ example = "nodeId1,...nodeIdN"
+ )
+ private UUID[] nodeIds;
+
+ /** Flag to launch index rebuild on all nodes. */
+ @Argument(description = "Rebuild index on all nodes")
+ private boolean allNodes;
+
/** */
@Argument(description = "Comma-separated list of cache names for which
indexes should be rebuilt",
example = "cacheName1,...cacheNameN")
@@ -51,6 +63,8 @@ public class CacheIndexesForceRebuildCommandArg extends
IgniteDataTransferObject
U.writeUuid(out, nodeId);
U.writeArray(out, cacheNames);
U.writeArray(out, groupNames);
+ U.writeArray(out, nodeIds);
+ out.writeBoolean(allNodes);
}
/** {@inheritDoc} */
@@ -58,6 +72,8 @@ public class CacheIndexesForceRebuildCommandArg extends
IgniteDataTransferObject
nodeId = U.readUuid(in);
cacheNames = U.readArray(in, String.class);
groupNames = U.readArray(in, String.class);
+ nodeIds = U.readArray(in, UUID.class);
+ allNodes = in.readBoolean();
}
/** */
@@ -70,6 +86,26 @@ public class CacheIndexesForceRebuildCommandArg extends
IgniteDataTransferObject
this.nodeId = nodeId;
}
+ /** */
+ public UUID[] nodeIds() {
+ return nodeIds;
+ }
+
+ /** */
+ public void allNodes(boolean allNodes) {
+ this.allNodes = allNodes;
+ }
+
+ /** */
+ public boolean allNodes() {
+ return allNodes;
+ }
+
+ /** */
+ public void nodeIds(UUID[] nodeIds) {
+ this.nodeIds = nodeIds;
+ }
+
/** */
public String[] cacheNames() {
return cacheNames;
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/IndexForceRebuildTask.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/IndexForceRebuildTask.java
index f02afe358d8..74ce6c787d5 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/IndexForceRebuildTask.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/IndexForceRebuildTask.java
@@ -18,10 +18,15 @@
package org.apache.ignite.internal.management.cache;
import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import java.util.stream.Collectors;
import org.apache.ignite.IgniteException;
+import org.apache.ignite.compute.ComputeJobResult;
import org.apache.ignite.internal.processors.cache.CacheGroupContext;
import org.apache.ignite.internal.processors.cache.GridCacheContext;
import org.apache.ignite.internal.processors.cache.GridCacheProcessor;
@@ -29,13 +34,14 @@ import
org.apache.ignite.internal.processors.cache.IgniteInternalCache;
import org.apache.ignite.internal.processors.task.GridInternal;
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.visor.VisorJob;
-import org.apache.ignite.internal.visor.VisorOneNodeTask;
+import org.apache.ignite.internal.visor.VisorMultiNodeTask;
/**
* Task that triggers indexes force rebuild for specified caches or cache
groups.
*/
@GridInternal
-public class IndexForceRebuildTask extends
VisorOneNodeTask<CacheIndexesForceRebuildCommandArg, IndexForceRebuildTaskRes> {
+public class IndexForceRebuildTask extends
VisorMultiNodeTask<CacheIndexesForceRebuildCommandArg,
+ Map<UUID, IndexForceRebuildTaskRes>, IndexForceRebuildTaskRes> {
/** */
private static final long serialVersionUID = 0L;
@@ -111,4 +117,20 @@ public class IndexForceRebuildTask extends
VisorOneNodeTask<CacheIndexesForceReb
);
}
}
+
+ /** {@inheritDoc} */
+ @Override protected Map<UUID, IndexForceRebuildTaskRes>
reduce0(List<ComputeJobResult> results)
+ throws IgniteException {
+
+ Map<UUID, IndexForceRebuildTaskRes> res = new HashMap<>();
+
+ for (ComputeJobResult jobRes : results) {
+ if (jobRes.getException() != null)
+ throw jobRes.getException();
+
+ res.put(jobRes.getNode().id(), jobRes.getData());
+ }
+
+ return res;
+ }
}
diff --git
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_cache_help.output
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_cache_help.output
index ab64a2ff145..3b7b9111815 100644
---
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_cache_help.output
+++
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_cache_help.output
@@ -97,10 +97,12 @@ Arguments: --cache help --yes
--node-id nodeId - Specify node for job execution. If not specified
explicitly, info will be gathered from all nodes.
Triggers rebuild of all indexes for specified caches or cache groups:
- control.(sh|bat) --cache indexes_force_rebuild --node-id nodeId
--cache-names cacheName1,...cacheNameN|--group-names groupName1,...groupNameN
+ control.(sh|bat) --cache indexes_force_rebuild --node-id nodeId|--node-ids
nodeId1,...nodeIdN|--all-nodes --cache-names
cacheName1,...cacheNameN|--group-names groupName1,...groupNameN
Parameters:
- --node-id nodeId - Specify node for indexes
rebuild.
+ --node-id nodeId - Specify node for indexes
rebuild (deprecated. Use --node-ids instead).
+ --node-ids nodeId1,...nodeIdN - Comma-separated list of nodes
ids to run index rebuild on.
+ --all-nodes - Rebuild index on all nodes.
--cache-names cacheName1,...cacheNameN - Comma-separated list of cache
names for which indexes should be rebuilt.
--group-names groupName1,...groupNameN - Comma-separated list of cache
group names for which indexes should be rebuilt.
diff --git
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_cache_help.output
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_cache_help.output
index ab64a2ff145..3b7b9111815 100644
---
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_cache_help.output
+++
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_cache_help.output
@@ -97,10 +97,12 @@ Arguments: --cache help --yes
--node-id nodeId - Specify node for job execution. If not specified
explicitly, info will be gathered from all nodes.
Triggers rebuild of all indexes for specified caches or cache groups:
- control.(sh|bat) --cache indexes_force_rebuild --node-id nodeId
--cache-names cacheName1,...cacheNameN|--group-names groupName1,...groupNameN
+ control.(sh|bat) --cache indexes_force_rebuild --node-id nodeId|--node-ids
nodeId1,...nodeIdN|--all-nodes --cache-names
cacheName1,...cacheNameN|--group-names groupName1,...groupNameN
Parameters:
- --node-id nodeId - Specify node for indexes
rebuild.
+ --node-id nodeId - Specify node for indexes
rebuild (deprecated. Use --node-ids instead).
+ --node-ids nodeId1,...nodeIdN - Comma-separated list of nodes
ids to run index rebuild on.
+ --all-nodes - Rebuild index on all nodes.
--cache-names cacheName1,...cacheNameN - Comma-separated list of cache
names for which indexes should be rebuilt.
--group-names groupName1,...groupNameN - Comma-separated list of cache
group names for which indexes should be rebuilt.