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 <vlads...@gmail.com> 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.