diff --git a/docs/_docs/tools/control-script.adoc b/docs/_docs/tools/control-script.adoc index 490c55e7f3730..843878b6a5f7d 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 604f3a47d2420..1a6e1d19cb95a 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 @@ 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.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 @@ private CLIArgumentParser createArgumentParser() { (name, val) -> {} ); - ArgumentGroup argGrp = cmdPath.peek().argClass().getAnnotation(ArgumentGroup.class); - Set grpdFlds = argGrp == null - ? Collections.emptySet() - : new HashSet<>(Arrays.asList(argGrp.value())); + List> grpdFlds = CommandUtils.argumentGroupsValues(cmdPath.peek().argClass()); Consumer 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 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 3486d74682684..34aa9b5123917 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.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.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 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.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 void testEmptyResult() { 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 void testEmptyResult() { 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 void testComplexIndexRebuild() throws IgniteInterruptedCheckedException { 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 void testCacheNamesArg() throws Exception { } } + /** + * 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 void testCorruptedIndexRebuild() throws Exception { */ @Test public void testSequentialForceRebuildIndexes() throws Exception { - IgniteEx grid = grid(0); + Collection 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 void testSequentialForceRebuildIndexes() throws Exception { * @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 @@ private void validateOutputCacheGroupsNotFound(String outputStr, String... cache * @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 @@ private String makeStringListWithIndent(String... strings) { * @param cacheGroputToNames Cache groups mapping to non-existing cache names. * @return Text for CLI print output for given caches. */ - private String makeStringListForCacheGroupsAndNames(Map> cacheGroputToNames) { + private static String makeStringListForCacheGroupsAndNames(Map> cacheGroputToNames) { SB sb = new SB(); for (Map.Entry> entry : cacheGroputToNames.entrySet()) { @@ -597,7 +790,7 @@ private String makeStringListForCacheGroupsAndNames(Map> ca * @param outputStr CLI {@code control.sh} utility output. * @param cacheGroputToNames Cache groups mapping to non-existing cache names. */ - private void validateOutputIndicesRebuildingInProgress(String outputStr, Map> cacheGroputToNames) { + private static void validateOutputIndicesRebuildingInProgress(String outputStr, Map> cacheGroputToNames) { String caches = makeStringListForCacheGroupsAndNames(cacheGroputToNames); assertContains( @@ -623,6 +816,35 @@ private void validateOutputIndicesRebuildWasStarted(String outputStr, Map { * 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 cacheNames, IgniteEx grid) throws Exception { + private void forceRebuildIndices(Iterable cacheNames, Collection 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 f55c684892a64..8f48a04a4e2d7 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 @@ * 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/ArgumentGroupsHolder.java b/modules/core/src/main/java/org/apache/ignite/internal/management/api/ArgumentGroupsHolder.java new file mode 100644 index 0000000000000..d39a740200d83 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/api/ArgumentGroupsHolder.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +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; + +/** + * {@link Repeatable} container for {@link ArgumentGroup}. + */ +@Retention(RetentionPolicy.RUNTIME) +@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 ad6d5ac724b56..76e37070e52b6 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 static void visitCommandParams( List positionalParams = new ArrayList<>(); List namedParams = new ArrayList<>(); - ArgumentGroup argGrp = argCls.getAnnotation(ArgumentGroup.class); + List argGprs = argumentGroups(argCls); - Set grpNames = argGrp != null - ? new HashSet<>(Arrays.asList(argGrp.value())) - : Collections.emptySet(); + List> grpNames = argumentGroupsValues(argGprs); - List grpFlds = new ArrayList<>(); + List> 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 @@ else if (fld.isAnnotationPresent(Argument.class)) 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 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> argumentGroupsValues(Class cls) { + return argumentGroupsValues(argumentGroups(cls)); + } + + /** + * @return Sets list of {@link ArgumentGroup#value()} holding in {@code argGrps}. + * @see #argumentGroupsValues(Class) + */ + public static List> argumentGroupsValues(List argGrps) { + List> 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> 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 static A argument( }) ); - 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 static R execute( /** */ private static class ArgumentState implements BiConsumer { /** */ - final A res; + private final A res; /** */ - final ArgumentGroup argGrp; + private final List argGrps; /** */ - boolean grpFldExists; + private final @Nullable boolean[] grpFldExists; /** */ - int idx; + private int idx; /** */ - final Set grpdFlds; + private final List> grpdFlds; /** */ public ArgumentState(Class 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 @@ private int nextIdx() { /** {@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 @@ private int nextIdx() { 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 575e1e0d0859c..224c957159f90 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 { +public class CacheIndexesForceRebuildCommand + implements ComputeCommand> { + /** */ + 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 nodes(Collection nodes, CacheIndexesForceRebuildCommandArg arg) { + Collection 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 results, + Consumer printer + ) { if (arg.nodeId() != null) { - List 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> notFound = new HashMap<>(); + Map> rebuilding = new HashMap<>(); + Map> started = new HashMap<>(); + Set 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 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 infos, Consumer printer) { + private static void storeCacheResults(Map> to, Collection 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 infos, Consumer printer) { infos.stream() .sorted(IndexRebuildStatusInfoContainer.comparator()) .forEach(rebuildStatusInfo -> printer.accept(INDENT + rebuildStatusInfo.toString())); } + + /** */ + private static void printBlock(SB b, String header, Map> 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 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 7531b157871c0..111e9f24d2204 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.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 void nodeId(UUID nodeId) { 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 f02afe358d849..74ce6c787d5f3 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.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 { +public class IndexForceRebuildTask extends VisorMultiNodeTask, IndexForceRebuildTaskRes> { /** */ private static final long serialVersionUID = 0L; @@ -111,4 +117,20 @@ protected IndexForceRebuildJob(CacheIndexesForceRebuildCommandArg arg, boolean d ); } } + + /** {@inheritDoc} */ + @Override protected Map reduce0(List results) + throws IgniteException { + + Map 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/main/java/org/apache/ignite/internal/mem/file/MappedFile.java b/modules/core/src/main/java/org/apache/ignite/internal/mem/file/MappedFile.java index 4b7552491c61f..f264d87a31516 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/mem/file/MappedFile.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/mem/file/MappedFile.java @@ -19,26 +19,28 @@ import java.io.Closeable; import java.io.File; +import java.io.FileDescriptor; import java.io.IOException; import java.io.RandomAccessFile; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.mem.DirectMemoryRegion; import org.apache.ignite.internal.mem.UnsafeChunk; import org.apache.ignite.internal.util.typedef.internal.U; import sun.nio.ch.FileChannelImpl; +import static org.apache.ignite.internal.util.IgniteUtils.jdkVersion; +import static org.apache.ignite.internal.util.IgniteUtils.majorJavaVersion; + /** */ public class MappedFile implements Closeable, DirectMemoryRegion { - /** */ - private static final Method map0 = U.findNonPublicMethod(FileChannelImpl.class, "map0", int.class, long.class, long.class); - - /** */ - private static final Method unmap0 = U.findNonPublicMethod(FileChannelImpl.class, "unmap0", long.class, long.class); - /** */ public static final int MAP_RW = 1; + /** File memory mapper */ + private static final Mapper mapper = pickMapper(); + /** */ private final RandomAccessFile file; @@ -85,7 +87,7 @@ public final RandomAccessFile file() { /** {@inheritDoc} */ @Override public void close() throws IOException { try { - unmap(addr, size); + mapper.unmap(addr, size); } finally { file.close(); @@ -122,16 +124,7 @@ public final RandomAccessFile file() { * @throws IOException */ public static long map(RandomAccessFile f, int mode, long start, long size) throws IOException { - try { - return (Long)map0.invoke(f.getChannel(), mode, start, size); - } - catch (IllegalAccessException e) { - throw new IllegalStateException(e); - } - catch (InvocationTargetException e) { - Throwable target = e.getTargetException(); - throw (target instanceof IOException) ? (IOException)target : new IOException(target); - } + return mapper.map(f, mode, start, size); } /** @@ -141,14 +134,161 @@ public static long map(RandomAccessFile f, int mode, long start, long size) thro * @param size Size of the mapped file. */ public static void unmap(long addr, long size) { - try { - unmap0.invoke(null, addr, size); + mapper.unmap(addr, size); + } + + /** */ + private static Mapper pickMapper() { + int javaVersion = majorJavaVersion(jdkVersion()); + + if (javaVersion >= 19) + return new JDK19Mapper(); + + if (javaVersion >= 14) + return new JDK14Mapper(); + + return new LegacyMapper(); + } + + /** */ + private interface Mapper { + /** */ + long map(RandomAccessFile f, int mode, long start, long size) throws IOException; + + /** */ + void unmap(long addr, long size); + } + + /** */ + private static class LegacyMapper implements Mapper { + /** */ + private static final Method map0 = U.findNonPublicMethod(FileChannelImpl.class, "map0", int.class, long.class, long.class); + + /** */ + private static final Method unmap0 = U.findNonPublicMethod(FileChannelImpl.class, "unmap0", long.class, long.class); + + + /** {@inheritDoc} */ + @Override public long map(RandomAccessFile f, int mode, long start, long size) throws IOException { + try { + return (Long)map0.invoke(f.getChannel(), mode, start, size); + } + catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } + catch (InvocationTargetException e) { + Throwable target = e.getTargetException(); + throw (target instanceof IOException) ? (IOException)target : new IOException(target); + } } - catch (IllegalAccessException e) { - throw new IllegalStateException(e); + + /** {@inheritDoc} */ + @Override public void unmap(long addr, long size) { + try { + unmap0.invoke(null, addr, size); + } + catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } + catch (InvocationTargetException e) { + throw new IllegalStateException(e.getTargetException()); + } } - catch (InvocationTargetException e) { - throw new IllegalStateException(e.getTargetException()); + } + + /** */ + private static class JDK14Mapper extends LegacyMapper { + /** Method {@link FileChannelImpl#map0} has additional parameter since JDK 14, isSync, {@code false} by default. */ + private static final Method map0 = U.findNonPublicMethod(FileChannelImpl.class, "map0", int.class, long.class, + long.class, boolean.class); + + /** {@inheritDoc} */ + @Override public long map(RandomAccessFile f, int mode, long start, long size) throws IOException { + try { + return (Long)map0.invoke(f.getChannel(), mode, start, size, false); + } + catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } + catch (InvocationTargetException e) { + Throwable target = e.getTargetException(); + throw (target instanceof IOException) ? (IOException)target : new IOException(target); + } + } + } + + /** */ + private static class JDK19Mapper implements Mapper { + /** */ + private static final Method map; + + /** */ + private static final Method unmap; + + /** */ + private static final Object dispatcher; + + static { + try { + // These methods are still in {@link FileChannelImpl} class in JDK 19. + Method map0 = U.findNonPublicMethod(FileChannelImpl.class, "map0", FileDescriptor.class, int.class, + long.class, long.class, boolean.class); + + Method unmap0 = U.findNonPublicMethod(FileChannelImpl.class, "unmap0", long.class, long.class); + + if (map0 != null && unmap0 != null) { + map = map0; + unmap = unmap0; + dispatcher = null; + } + else { + // That methods are moved to {@link sun.nio.ch.FileDispatcher}. + Class fileDispatcherCls = Class.forName("sun.nio.ch.FileDispatcher"); + + dispatcher = U.staticField(FileChannelImpl.class, "nd"); + + map = U.findNonPublicMethod(fileDispatcherCls, "map", FileDescriptor.class, int.class, + long.class, long.class, boolean.class); + + unmap = U.findNonPublicMethod(fileDispatcherCls, "unmap", long.class, long.class); + + } + } + catch (ClassNotFoundException | IgniteCheckedException e) { + throw new ExceptionInInitializerError(e); + } + } + + /** {@inheritDoc} */ + @Override public long map(RandomAccessFile f, int mode, long start, long size) throws IOException { + try { + Object fd = U.field(f.getChannel(), "fd"); + + if (dispatcher != null) + return (Long)map.invoke(dispatcher, fd, mode, start, size, false); + else + return (Long)map.invoke(f.getChannel(), fd, mode, start, size, false); + } + catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } + catch (InvocationTargetException e) { + Throwable target = e.getTargetException(); + throw (target instanceof IOException) ? (IOException)target : new IOException(target); + } + } + + /** {@inheritDoc} */ + @Override public void unmap(long addr, long size) { + try { + unmap.invoke(dispatcher, addr, size); // If dispatcher is null, the static method will be called. + } + catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } + catch (InvocationTargetException e) { + throw new IllegalStateException(e.getTargetException()); + } } } } 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 ab64a2ff1459c..3b7b9111815f0 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 ab64a2ff1459c..3b7b9111815f0 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. diff --git a/parent/pom.xml b/parent/pom.xml index aba7b514c489b..d67b144c19376 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -103,7 +103,7 @@ 1.0.0 1.0.6.Final 16.0.3 - 9.4.51.v20230217 + 9.4.52.v20230823 1.13 1.1.1 4.5.2