IGNITE-8277 Added utilities to check and display cache info
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/4296fdd8 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/4296fdd8 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/4296fdd8 Branch: refs/heads/ignite-2.5 Commit: 4296fdd8f0731c5a839a45e0d8a142dcf5829ffa Parents: e190e35 Author: Ivan Rakov <[email protected]> Authored: Thu Apr 26 18:57:38 2018 +0300 Committer: Alexey Goncharuk <[email protected]> Committed: Thu Apr 26 20:02:26 2018 +0300 ---------------------------------------------------------------------- .../ignite/internal/commandline/Arguments.java | 21 +- .../ignite/internal/commandline/Command.java | 5 +- .../internal/commandline/CommandHandler.java | 433 ++++++++++++++++++- .../commandline/cache/CacheArguments.java | 163 +++++++ .../commandline/cache/CacheCommand.java | 93 ++++ .../processors/cache/verify/CacheInfo.java | 322 ++++++++++++++ .../cache/verify/ContentionClosure.java | 162 +++++++ .../processors/cache/verify/ContentionInfo.java | 72 +++ .../cache/verify/ViewCacheClosure.java | 185 ++++++++ .../visor/verify/IndexValidationIssue.java | 88 ++++ .../verify/ValidateIndexesPartitionResult.java | 145 +++++++ .../visor/verify/VisorContentionJobResult.java | 80 ++++ .../visor/verify/VisorContentionTask.java | 100 +++++ .../visor/verify/VisorContentionTaskArg.java | 84 ++++ .../visor/verify/VisorContentionTaskResult.java | 100 +++++ .../visor/verify/VisorIdleAnalyzeTask.java | 124 ++++++ .../visor/verify/VisorIdleAnalyzeTaskArg.java | 88 ++++ .../verify/VisorIdleAnalyzeTaskResult.java | 76 ++++ .../visor/verify/VisorIdleVerifyTask.java | 97 +++++ .../visor/verify/VisorIdleVerifyTaskArg.java | 74 ++++ .../visor/verify/VisorIdleVerifyTaskResult.java | 76 ++++ .../verify/VisorValidateIndexesJobResult.java | 73 ++++ .../verify/VisorValidateIndexesTaskArg.java | 74 ++++ .../verify/VisorValidateIndexesTaskResult.java | 88 ++++ .../visor/verify/VisorViewCacheCmd.java | 47 ++ .../visor/verify/VisorViewCacheTask.java | 75 ++++ .../visor/verify/VisorViewCacheTaskArg.java | 86 ++++ .../visor/verify/VisorViewCacheTaskResult.java | 74 ++++ .../resources/META-INF/classnames.properties | 114 ++++- .../ignite/util/GridCommandHandlerTest.java | 312 +++++++++++-- .../visor/verify/ValidateIndexesClosure.java | 356 +++++++++++++++ .../visor/verify/VisorValidateIndexesTask.java | 99 +++++ .../util/GridCommandHandlerIndexingTest.java | 121 ++++++ 33 files changed, 4026 insertions(+), 81 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/4296fdd8/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java index 83a272b..ce72693 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java @@ -18,6 +18,7 @@ package org.apache.ignite.internal.commandline; import org.apache.ignite.internal.client.GridClientConfiguration; +import org.apache.ignite.internal.commandline.cache.CacheArguments; import org.apache.ignite.internal.visor.tx.VisorTxTaskArg; /** @@ -62,6 +63,11 @@ public class Arguments { private final VisorTxTaskArg txArg; /** + * Arguments for --cache subcommand. + */ + private CacheArguments cacheArgs; + + /** * @param cmd Command. * @param host Host. * @param port Port. @@ -73,10 +79,11 @@ public class Arguments { * @param force Force flag. * @param pingTimeout Ping timeout. See {@link GridClientConfiguration#pingTimeout}. * @param pingInterval Ping interval. See {@link GridClientConfiguration#pingInterval}. + * @param cacheArgs --cache subcommand arguments. */ - public Arguments(Command cmd, String host, String port, String user, String pwd, - String baselineAct, String baselineArgs, long pingTimeout, - long pingInterval, VisorTxTaskArg txArg, boolean force) { + public Arguments(Command cmd, String host, String port, String user, String pwd, String baselineAct, + String baselineArgs, long pingTimeout, long pingInterval, VisorTxTaskArg txArg, boolean force, + CacheArguments cacheArgs) { this.cmd = cmd; this.host = host; this.port = port; @@ -88,6 +95,7 @@ public class Arguments { this.pingInterval = pingInterval; this.force = force; this.txArg = txArg; + this.cacheArgs = cacheArgs; } /** @@ -170,4 +178,11 @@ public class Arguments { public boolean force() { return force; } + + /** + * @return Arguments for --cache subcommand. + */ + public CacheArguments cacheArgs() { + return cacheArgs; + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/4296fdd8/modules/core/src/main/java/org/apache/ignite/internal/commandline/Command.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/Command.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/Command.java index c8c7db5..52098d6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/Command.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/Command.java @@ -34,7 +34,10 @@ public enum Command { BASELINE("--baseline"), /** */ - TX("--tx"); + TX("--tx"), + + /** */ + CACHE("--cache"); /** */ private final String text; http://git-wip-us.apache.org/repos/asf/ignite/blob/4296fdd8/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java index 08488ea..ff05684 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java @@ -19,15 +19,19 @@ package org.apache.ignite.internal.commandline; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Scanner; +import java.util.Set; import java.util.UUID; import java.util.logging.Logger; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import java.util.stream.Collectors; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.internal.client.GridClient; import org.apache.ignite.internal.client.GridClientAuthenticationException; @@ -42,6 +46,12 @@ import org.apache.ignite.internal.client.GridClientHandshakeException; import org.apache.ignite.internal.client.GridClientNode; import org.apache.ignite.internal.client.GridServerUnreachableException; import org.apache.ignite.internal.client.impl.connection.GridClientConnectionResetException; +import org.apache.ignite.internal.commandline.cache.CacheArguments; +import org.apache.ignite.internal.commandline.cache.CacheCommand; +import org.apache.ignite.internal.processors.cache.verify.CacheInfo; +import org.apache.ignite.internal.processors.cache.verify.ContentionInfo; +import org.apache.ignite.internal.processors.cache.verify.PartitionHashRecord; +import org.apache.ignite.internal.processors.cache.verify.PartitionKey; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.X; import org.apache.ignite.internal.util.typedef.internal.U; @@ -58,6 +68,20 @@ import org.apache.ignite.internal.visor.tx.VisorTxSortOrder; import org.apache.ignite.internal.visor.tx.VisorTxTask; import org.apache.ignite.internal.visor.tx.VisorTxTaskArg; import org.apache.ignite.internal.visor.tx.VisorTxTaskResult; +import org.apache.ignite.internal.visor.verify.IndexValidationIssue; +import org.apache.ignite.internal.visor.verify.ValidateIndexesPartitionResult; +import org.apache.ignite.internal.visor.verify.VisorContentionTask; +import org.apache.ignite.internal.visor.verify.VisorContentionTaskArg; +import org.apache.ignite.internal.visor.verify.VisorContentionTaskResult; +import org.apache.ignite.internal.visor.verify.VisorIdleVerifyTask; +import org.apache.ignite.internal.visor.verify.VisorIdleVerifyTaskArg; +import org.apache.ignite.internal.visor.verify.VisorIdleVerifyTaskResult; +import org.apache.ignite.internal.visor.verify.VisorValidateIndexesJobResult; +import org.apache.ignite.internal.visor.verify.VisorValidateIndexesTaskArg; +import org.apache.ignite.internal.visor.verify.VisorValidateIndexesTaskResult; +import org.apache.ignite.internal.visor.verify.VisorViewCacheTask; +import org.apache.ignite.internal.visor.verify.VisorViewCacheTaskArg; +import org.apache.ignite.internal.visor.verify.VisorViewCacheTaskResult; import org.apache.ignite.lang.IgniteClosure; import org.apache.ignite.plugin.security.SecurityCredentials; import org.apache.ignite.plugin.security.SecurityCredentialsBasicProvider; @@ -66,6 +90,7 @@ import static org.apache.ignite.internal.IgniteVersionUtils.ACK_VER_STR; import static org.apache.ignite.internal.IgniteVersionUtils.COPYRIGHT; import static org.apache.ignite.internal.commandline.Command.ACTIVATE; import static org.apache.ignite.internal.commandline.Command.BASELINE; +import static org.apache.ignite.internal.commandline.Command.CACHE; import static org.apache.ignite.internal.commandline.Command.DEACTIVATE; import static org.apache.ignite.internal.commandline.Command.STATE; import static org.apache.ignite.internal.commandline.Command.TX; @@ -74,6 +99,8 @@ import static org.apache.ignite.internal.visor.baseline.VisorBaselineOperation.C import static org.apache.ignite.internal.visor.baseline.VisorBaselineOperation.REMOVE; import static org.apache.ignite.internal.visor.baseline.VisorBaselineOperation.SET; import static org.apache.ignite.internal.visor.baseline.VisorBaselineOperation.VERSION; +import static org.apache.ignite.internal.visor.verify.VisorViewCacheCmd.GROUPS; +import static org.apache.ignite.internal.visor.verify.VisorViewCacheCmd.SEQ; /** * Class that execute several commands passed via command line. @@ -103,6 +130,23 @@ public class CommandHandler { /** */ private static final String CMD_USER = "--user"; + /** Force option is used for auto confirmation. */ + private static final String CMD_FORCE = "--force"; + + /** List of optional auxiliary commands. */ + private static final Set<String> AUX_COMMANDS = new HashSet<>(); + static { + AUX_COMMANDS.add(CMD_HELP); + AUX_COMMANDS.add(CMD_HOST); + AUX_COMMANDS.add(CMD_PORT); + AUX_COMMANDS.add(CMD_PASSWORD); + AUX_COMMANDS.add(CMD_USER); + AUX_COMMANDS.add(CMD_FORCE); + } + + /** Broadcast uuid. */ + private static final UUID BROADCAST_UUID = UUID.randomUUID(); + /** */ protected static final String CMD_PING_INTERVAL = "--ping-interval"; @@ -130,9 +174,6 @@ public class CommandHandler { /** */ private static final String DELIM = "--------------------------------------------------------------------------------"; - /** Force option is used for auto confirmation. */ - private static final String CMD_FORCE = "--force"; - /** */ public static final int EXIT_CODE_OK = 0; @@ -157,6 +198,9 @@ public class CommandHandler { /** */ private static final Scanner IN = new Scanner(System.in); + /** Validate indexes task name. */ + private static final String VALIDATE_INDEXES_TASK = "org.apache.ignite.internal.visor.verify.VisorValidateIndexesTask"; + /** */ private static final String TX_LIMIT = "limit"; @@ -194,7 +238,7 @@ public class CommandHandler { private String peekedArg; /** */ - private Object lastOperationResult; + private Object lastOperationRes; /** * Output specified string to console. @@ -279,16 +323,22 @@ public class CommandHandler { switch (args.command()) { case DEACTIVATE: str = "Warning: the command will deactivate a cluster."; + break; case BASELINE: if (!BASELINE_COLLECT.equals(args.baselineAction())) str = "Warning: the command will perform changes in baseline."; + break; case TX: if (args.transactionArguments().getOperation() == VisorTxOperation.KILL) str = "Warning: the command will kill some transactions."; + + break; + + default: break; } @@ -392,12 +442,52 @@ public class CommandHandler { * @throws GridClientException If failed to execute task. */ private <R> R executeTask(GridClient client, Class<?> taskCls, Object taskArgs) throws GridClientException { + return executeTaskByNameOnNode(client, taskCls.getName(), taskArgs, null); + } + + /** + * @param client Client + * @param taskClsName Task class name. + * @param taskArgs Task args. + * @param nodeId Node ID to execute task at (if null, random node will be chosen by balancer). + * @return Task result. + * @throws GridClientException If failed to execute task. + */ + private <R> R executeTaskByNameOnNode(GridClient client, String taskClsName, Object taskArgs, UUID nodeId + ) throws GridClientException { GridClientCompute compute = client.compute(); - GridClientNode node = getBalancedNode(compute); + if (nodeId == BROADCAST_UUID) { + Collection<GridClientNode> nodes = compute.nodes(GridClientNode::connectable); + + if (F.isEmpty(nodes)) + throw new GridClientDisconnectedException("Connectable nodes not found", null); + + List<UUID> nodeIds = nodes.stream() + .map(GridClientNode::nodeId) + .collect(Collectors.toList()); + + return client.compute().execute(taskClsName, new VisorTaskArgument<>(nodeIds, taskArgs, false)); + } + + GridClientNode node = null; + + if (nodeId == null) + node = getBalancedNode(compute); + else { + for (GridClientNode n : compute.nodes()) { + if (n.connectable() && nodeId.equals(n.nodeId())) { + node = n; - return compute.execute(taskCls.getName(), - new VisorTaskArgument<>(node.nodeId(), taskArgs, false)); + break; + } + } + + if (node == null) + throw new IllegalArgumentException("Node with id=" + nodeId + " not found"); + } + + return compute.projection(node).execute(taskClsName, new VisorTaskArgument<>(node.nodeId(), taskArgs, false)); } /** @@ -405,11 +495,7 @@ public class CommandHandler { * @return balanced node */ private GridClientNode getBalancedNode(GridClientCompute compute) throws GridClientException { - List<GridClientNode> nodes = new ArrayList<>(); - - for (GridClientNode node : compute.nodes()) - if (node.connectable()) - nodes.add(node); + Collection<GridClientNode> nodes = compute.nodes(GridClientNode::connectable); if (F.isEmpty(nodes)) throw new GridClientDisconnectedException("Connectable node not found", null); @@ -418,6 +504,175 @@ public class CommandHandler { } /** + * Executes --cache subcommand. + * + * @param client Client. + * @param cacheArgs Cache args. + */ + private void cache(GridClient client, CacheArguments cacheArgs) throws Throwable { + switch (cacheArgs.command()) { + case HELP: + printCacheHelp(); + + break; + + case IDLE_VERIFY: + cacheIdleVerify(client, cacheArgs); + + break; + + case VALIDATE_INDEXES: + cacheValidateIndexes(client, cacheArgs); + + break; + + case CONTENTION: + cacheContention(client, cacheArgs); + + break; + + default: + cacheView(client, cacheArgs); + + break; + } + } + + /** + * + */ + private void printCacheHelp() { + log("--cache subcommand allows to do the following operations:"); + + usage(" Show information about caches, groups or sequences that match a regex:", CACHE, " list regexPattern [groups|seq] [nodeId]"); + usage(" Show hot keys that are point of contention for multiple transactions:", CACHE, " contention minQueueSize [nodeId] [maxPrint]"); + usage(" Verify partition counters and hashes between primary and backups on idle cluster:", CACHE, " idle_verify [cache1,...,cacheN]"); + usage(" Validate custom indexes on idle cluster:", CACHE, " validate_indexes [cache1,...,cacheN] [nodeId]"); + + log(" If [nodeId] is not specified, cont and validate_indexes commands will be broadcasted to all server nodes."); + log(" Another commands where [nodeId] is optional will run on a random server node."); + nl(); + } + + /** + * @param client Client. + * @param cacheArgs Cache args. + */ + private void cacheContention(GridClient client, CacheArguments cacheArgs) throws GridClientException { + VisorContentionTaskArg taskArg = new VisorContentionTaskArg( + cacheArgs.minQueueSize(), cacheArgs.maxPrint()); + + UUID nodeId = cacheArgs.nodeId() == null ? BROADCAST_UUID : cacheArgs.nodeId(); + + VisorContentionTaskResult res = executeTaskByNameOnNode( + client, VisorContentionTask.class.getName(), taskArg, nodeId); + + if (!F.isEmpty(res.exceptions())) { + log("Contention check failed on nodes:"); + + for (Map.Entry<UUID, Exception> e : res.exceptions().entrySet()) { + log("Node ID = " + e.getKey()); + + log("Exception message:"); + log(e.getValue().getMessage()); + nl(); + } + } + + for (ContentionInfo info : res.getInfos()) + info.print(); + } + + /** + * @param client Client. + * @param cacheArgs Cache args. + */ + private void cacheValidateIndexes(GridClient client, CacheArguments cacheArgs) throws GridClientException { + VisorValidateIndexesTaskArg taskArg = new VisorValidateIndexesTaskArg(cacheArgs.caches()); + + UUID nodeId = cacheArgs.nodeId() == null ? BROADCAST_UUID : cacheArgs.nodeId(); + + VisorValidateIndexesTaskResult taskRes = executeTaskByNameOnNode( + client, VALIDATE_INDEXES_TASK, taskArg, nodeId); + + if (!F.isEmpty(taskRes.exceptions())) { + log("Index validation failed on nodes:"); + + for (Map.Entry<UUID, Exception> e : taskRes.exceptions().entrySet()) { + log("Node ID = " + e.getKey()); + + log("Exception message:"); + log(e.getValue().getMessage()); + nl(); + } + } + + boolean errors = false; + + for (Map.Entry<UUID, VisorValidateIndexesJobResult> nodeEntry : taskRes.results().entrySet()) { + Map<PartitionKey, ValidateIndexesPartitionResult> map = nodeEntry.getValue().response(); + + for (Map.Entry<PartitionKey, ValidateIndexesPartitionResult> e : map.entrySet()) { + ValidateIndexesPartitionResult res = e.getValue(); + + if (!res.issues().isEmpty()) { + errors = true; + + log(e.getKey().toString() + " " + e.getValue().toString()); + + for (IndexValidationIssue is : res.issues()) + log(is.toString()); + } + } + } + + if (!errors) + log("validate_indexes has finished, no issues found."); + else + log("validate_indexes has finished with errors (listed above)."); + } + + /** + * @param client Client. + * @param cacheArgs Cache args. + */ + private void cacheView(GridClient client, CacheArguments cacheArgs) throws GridClientException { + VisorViewCacheTaskArg taskArg = new VisorViewCacheTaskArg(cacheArgs.regex(), cacheArgs.cacheCommand()); + + VisorViewCacheTaskResult res = executeTaskByNameOnNode( + client, VisorViewCacheTask.class.getName(), taskArg, cacheArgs.nodeId()); + + for (CacheInfo info : res.cacheInfos()) + info.print(cacheArgs.cacheCommand()); + } + + /** + * @param client Client. + * @param cacheArgs Cache args. + */ + private void cacheIdleVerify(GridClient client, CacheArguments cacheArgs) throws GridClientException { + VisorIdleVerifyTaskResult res = executeTask( + client, VisorIdleVerifyTask.class, new VisorIdleVerifyTaskArg(cacheArgs.caches())); + + Map<PartitionKey, List<PartitionHashRecord>> conflicts = res.getConflicts(); + + if (conflicts.isEmpty()) { + log("idle_verify check has finished, no conflicts have been found."); + nl(); + } + else { + log ("idle_verify check has finished, found " + conflicts.size() + " conflict partitions."); + nl(); + + for (Map.Entry<PartitionKey, List<PartitionHashRecord>> entry : conflicts.entrySet()) { + log("Conflict partition: " + entry.getKey()); + + log("Partition instances: " + entry.getValue()); + } + } + } + + /** * Change baseline. * * @param client Client. @@ -508,7 +763,7 @@ public class CommandHandler { Map<String, VisorBaselineNode> baseline = res.getBaseline(); - Map<String, VisorBaselineNode> servers = res.getServers(); + Map<String, VisorBaselineNode> srvs = res.getServers(); if (F.isEmpty(baseline)) log("Baseline nodes not found."); @@ -517,7 +772,7 @@ public class CommandHandler { for(VisorBaselineNode node : baseline.values()) { log(" ConsistentID=" + node.getConsistentId() + ", STATE=" + - (servers.containsKey(node.getConsistentId()) ? "ONLINE" : "OFFLINE")); + (srvs.containsKey(node.getConsistentId()) ? "ONLINE" : "OFFLINE")); } log(DELIM); @@ -527,7 +782,7 @@ public class CommandHandler { List<VisorBaselineNode> others = new ArrayList<>(); - for (VisorBaselineNode node : servers.values()) { + for (VisorBaselineNode node : srvs.values()) { if (!baseline.containsKey(node.getConsistentId())) others.add(node); } @@ -645,7 +900,7 @@ public class CommandHandler { try { Map<ClusterNode, VisorTxTaskResult> res = executeTask(client, VisorTxTask.class, arg); - lastOperationResult = res; + lastOperationRes = res; if (res.isEmpty()) log("Nothing found."); @@ -778,6 +1033,8 @@ public class CommandHandler { boolean force = false; + CacheArguments cacheArgs = null; + List<Command> commands = new ArrayList<>(); initArgIterator(rawArgs); @@ -824,6 +1081,13 @@ public class CommandHandler { break; + case CACHE: + commands.add(CACHE); + + cacheArgs = parseAndValidateCacheArgs(); + + break; + default: throw new IllegalArgumentException("Unexpected command: " + str); } @@ -862,14 +1126,17 @@ public class CommandHandler { case CMD_USER: user = nextArg("Expected user name"); + break; case CMD_PASSWORD: pwd = nextArg("Expected password"); + break; case CMD_FORCE: force = true; + break; default: @@ -895,7 +1162,118 @@ public class CommandHandler { throw new IllegalArgumentException("Both user and password should be specified"); return new Arguments(cmd, host, port, user, pwd, baselineAct, baselineArgs, - pingTimeout, pingInterval, txArgs, force); + pingTimeout, pingInterval, txArgs, force, cacheArgs); + } + + /** + * Parses and validates cache arguments. + * + * @return --cache subcommand arguments in case validation is successful. + */ + private CacheArguments parseAndValidateCacheArgs() { + if (!hasNextCacheArg()) { + throw new IllegalArgumentException("Arguments are expected for --cache subcommand, " + + "run --cache help for more info."); + } + + CacheArguments cacheArgs = new CacheArguments(); + + String str = nextArg("").toLowerCase(); + + CacheCommand cmd = CacheCommand.of(str); + + if (cmd == null) + cmd = CacheCommand.HELP; + + cacheArgs.command(cmd); + + switch (cmd) { + case HELP: + break; + + case IDLE_VERIFY: + parseCacheNamesIfPresent(cacheArgs); + + break; + + case CONTENTION: + cacheArgs.minQueueSize(Integer.parseInt(nextArg("Min queue size expected"))); + + if (hasNextCacheArg()) + cacheArgs.nodeId(UUID.fromString(nextArg(""))); + + if (hasNextCacheArg()) + cacheArgs.maxPrint(Integer.parseInt(nextArg(""))); + else + cacheArgs.maxPrint(10); + + break; + + case VALIDATE_INDEXES: + parseCacheNamesIfPresent(cacheArgs); + + if (hasNextCacheArg()) + cacheArgs.nodeId(UUID.fromString(nextArg(""))); + + break; + + default: + cacheArgs.regex(nextArg("Regex is expected")); + + if (hasNextCacheArg()) { + String tmp = nextArg(""); + + switch (tmp) { + case "groups": + cacheArgs.cacheCommand(GROUPS); + + break; + + case "seq": + cacheArgs.cacheCommand(SEQ); + + break; + + default: + cacheArgs.nodeId(UUID.fromString(tmp)); + } + } + + break; + } + + if (hasNextCacheArg()) + throw new IllegalArgumentException("Unexpected argument of --cache subcommand: " + peekNextArg()); + + return cacheArgs; + } + + /** + * @return <code>true</code> if there's next argument for --cache subcommand. + */ + private boolean hasNextCacheArg() { + return hasNextArg() && Command.of(peekNextArg()) == null && !AUX_COMMANDS.contains(peekNextArg()); + } + + /** + * @param cacheArgs Cache args. + */ + private void parseCacheNamesIfPresent(CacheArguments cacheArgs) { + if (hasNextCacheArg()) { + String cacheNames = nextArg(""); + + String[] cacheNamesArr = cacheNames.split(","); + Set<String> cacheNamesSet = new HashSet<>(); + + for (String cacheName : cacheNamesArr) { + if (F.isEmpty(cacheName)) + throw new IllegalArgumentException("Non-empty cache names expected."); + + cacheNamesSet.add(cacheName.trim()); + } + + cacheArgs.caches(cacheNamesSet); + } } /** @@ -1002,7 +1380,7 @@ public class CommandHandler { try { Pattern.compile(lbRegex); } - catch (PatternSyntaxException e) { + catch (PatternSyntaxException ignored) { throw new IllegalArgumentException("Illegal regex syntax"); } @@ -1046,7 +1424,7 @@ public class CommandHandler { return val; } - catch (NumberFormatException e) { + catch (NumberFormatException ignored) { throw new IllegalArgumentException("Invalid value for " + lb + ": " + str); } } @@ -1079,6 +1457,10 @@ public class CommandHandler { "[minSize SIZE] [label PATTERN_REGEX] [servers|clients] " + "[nodes consistentId1[,consistentId2,....,consistentIdN] [limit NUMBER] [order DURATION|SIZE] [kill] [--force]"); + log("The utility has --cache subcommand to view and control state of caches in cluster."); + log(" More info: control.sh --cache help"); + nl(); + log("By default commands affecting the cluster require interactive confirmation. "); log(" --force option can be used to execute commands without prompting for confirmation."); nl(); @@ -1122,26 +1504,35 @@ public class CommandHandler { } try (GridClient client = GridClientFactory.start(cfg)) { - switch (args.command()) { case ACTIVATE: activate(client); + break; case DEACTIVATE: deactivate(client); + break; case STATE: state(client); + break; case BASELINE: baseline(client, args.baselineAction(), args.baselineArguments()); + break; case TX: transactions(client, args.transactionArguments()); + + break; + + case CACHE: + cache(client, args.cacheArgs()); + break; } } @@ -1177,7 +1568,7 @@ public class CommandHandler { */ @SuppressWarnings("unchecked") public <T> T getLastOperationResult() { - return (T)lastOperationResult; + return (T)lastOperationRes; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/4296fdd8/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheArguments.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheArguments.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheArguments.java new file mode 100644 index 0000000..6f315ef --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheArguments.java @@ -0,0 +1,163 @@ +/* +* 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.commandline.cache; + +import java.util.Set; +import java.util.UUID; +import org.apache.ignite.internal.visor.verify.VisorViewCacheCmd; +import org.jetbrains.annotations.Nullable; + +/** + * + */ +public class CacheArguments { + /** Command. */ + private CacheCommand cmd; + + /** Caches. */ + private Set<String> caches; + + /** Partition id. */ + private int partId; + + /** Regex. */ + private String regex; + + /** Node id. */ + private UUID nodeId; + + /** Min queue size. */ + private int minQueueSize; + + /** Max print. */ + private int maxPrint; + + /** Cache view command. */ + private @Nullable VisorViewCacheCmd cacheCmd; + + /** + * @return Command. + */ + public CacheCommand command() { + return cmd; + } + + /** + * @return Cache view command. + */ + @Nullable public VisorViewCacheCmd cacheCommand() { + return cacheCmd; + } + + /** + * @param cmd Cache view command. + */ + public void cacheCommand(VisorViewCacheCmd cmd) { + this.cacheCmd = cmd; + } + + /** + * @param cmd New command. + */ + public void command(CacheCommand cmd) { + this.cmd = cmd; + } + + /** + * @return Caches. + */ + public Set<String> caches() { + return caches; + } + + /** + * @param caches New caches. + */ + public void caches(Set<String> caches) { + this.caches = caches; + } + + /** + * @return Partition id. + */ + public int partitionId() { + return partId; + } + + /** + * @param partId New partition id. + */ + public void partitionId(int partId) { + this.partId = partId; + } + + /** + * @return Regex. + */ + public String regex() { + return regex; + } + + /** + * @param regex New regex. + */ + public void regex(String regex) { + this.regex = regex; + } + + /** + * @return Node id. + */ + public UUID nodeId() { + return nodeId; + } + + /** + * @param nodeId New node id. + */ + public void nodeId(UUID nodeId) { + this.nodeId = nodeId; + } + + /** + * @return Min queue size. + */ + public int minQueueSize() { + return minQueueSize; + } + + /** + * @param minQueueSize New min queue size. + */ + public void minQueueSize(int minQueueSize) { + this.minQueueSize = minQueueSize; + } + + /** + * @return Max print. + */ + public int maxPrint() { + return maxPrint; + } + + /** + * @param maxPrint New max print. + */ + public void maxPrint(int maxPrint) { + this.maxPrint = maxPrint; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4296fdd8/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheCommand.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheCommand.java new file mode 100644 index 0000000..6aec6d7 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/CacheCommand.java @@ -0,0 +1,93 @@ +/* +* 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.commandline.cache; + +import org.jetbrains.annotations.Nullable; + +/** + * + */ +public enum CacheCommand { + /** + * Prints out help for the cache command. + */ + HELP("help"), + + /** + * Checks consistency of primary and backup partitions assuming no concurrent updates are happening in the cluster. + */ + IDLE_VERIFY("idle_verify"), + + /** + * Prints info regarding caches, groups or sequences. + */ + LIST("list"), + + /** + * Validates indexes attempting to read each indexed entry. + */ + VALIDATE_INDEXES("validate_indexes"), + + /** + * Prints info about contended keys (the keys concurrently locked from multiple transactions). + */ + CONTENTION("contention"); + + /** Enumerated values. */ + private static final CacheCommand[] VALS = values(); + + /** Name. */ + private final String name; + + /** + * @param name Name. + */ + CacheCommand(String name) { + this.name = name; + } + + /** + * @param text Command text. + * @return Command for the text. + */ + public static CacheCommand of(String text) { + for (CacheCommand cmd : CacheCommand.values()) { + if (cmd.text().equalsIgnoreCase(text)) + return cmd; + } + + return null; + } + + /** + * @return Name. + */ + public String text() { + return name; + } + + /** + * Efficiently gets enumerated value from its ordinal. + * + * @param ord Ordinal value. + * @return Enumerated value or {@code null} if ordinal out of range. + */ + @Nullable public static CacheCommand fromOrdinal(int ord) { + return ord >= 0 && ord < VALS.length ? VALS[ord] : null; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4296fdd8/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/CacheInfo.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/CacheInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/CacheInfo.java new file mode 100644 index 0000000..9a090a0 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/CacheInfo.java @@ -0,0 +1,322 @@ +/* + * 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.processors.cache.verify; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import org.apache.ignite.cache.CacheMode; +import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.internal.visor.VisorDataTransferObject; +import org.apache.ignite.internal.visor.verify.VisorViewCacheCmd; + +/** + * Cache info DTO. + */ +public class CacheInfo extends VisorDataTransferObject { + /** */ + private static final long serialVersionUID = 0L; + + /** Sequence name. */ + private String seqName; + + /** Sequence value. */ + private long seqVal; + + /** Cache name. */ + private String cacheName; + + /** Cache id. */ + private int cacheId; + + /** Group name. */ + private String grpName; + + /** Group id. */ + private int grpId; + + /** Caches count. */ + private int cachesCnt; + + /** Partitions. */ + private int partitions; + + /** Mapped. */ + private int mapped; + + /** Topology version. */ + public AffinityTopologyVersion topVer; + + /** Mode. */ + private CacheMode mode; + + /** Backups count. */ + private int backupsCnt; + + /** Affinity class name. */ + private String affinityClsName; + + /** */ + public String getSeqName() { + return seqName; + } + + /** + * @param seqName Sequence name. + */ + public void setSeqName(String seqName) { + this.seqName = seqName; + } + + /** + * + */ + public String getCacheName() { + return cacheName; + } + + /** + * @param cacheName Cache name. + */ + public void setCacheName(String cacheName) { + this.cacheName = cacheName; + } + + /** + * + */ + public int getCacheId() { + return cacheId; + } + + /** + * @param cacheId Cache id. + */ + public void setCacheId(int cacheId) { + this.cacheId = cacheId; + } + + /** + * + */ + public String getGrpName() { + return grpName; + } + + /** + * @param grpName Group name. + */ + public void setGrpName(String grpName) { + this.grpName = grpName; + } + + /** + * + */ + public int getGrpId() { + return grpId; + } + + /** + * @param grpId Group id. + */ + public void setGrpId(int grpId) { + this.grpId = grpId; + } + + /** + * + */ + public int getCachesCnt() { + return cachesCnt; + } + + /** + * @param cachesCnt Caches count. + */ + public void setCachesCnt(int cachesCnt) { + this.cachesCnt = cachesCnt; + } + + /** + * + */ + public int getPartitions() { + return partitions; + } + + /** + * @param partitions Partitions. + */ + public void setPartitions(int partitions) { + this.partitions = partitions; + } + + /** + * + */ + public int getMapped() { + return mapped; + } + + /** + * @param mapped Mapped. + */ + public void setMapped(int mapped) { + this.mapped = mapped; + } + + /** + * + */ + public AffinityTopologyVersion getTopologyVersion() { + return topVer; + } + + /** + * @param topologyVersion Topology version. + */ + public void setTopologyVersion(AffinityTopologyVersion topologyVersion) { + this.topVer = topologyVersion; + } + + /** + * @param seqVal Sequence value. + */ + public void setSeqVal(long seqVal) { + this.seqVal = seqVal; + } + + /** + * + */ + public long getSeqVal() { + return seqVal; + } + + /** + * + */ + public CacheMode getMode() { + return mode; + } + + /** + * @param mode Mode. + */ + public void setMode(CacheMode mode) { + this.mode = mode; + } + + /** + * + */ + public int getBackupsCnt() { + return backupsCnt; + } + + /** + * @param backupsCnt Backups count. + */ + public void setBackupsCnt(int backupsCnt) { + this.backupsCnt = backupsCnt; + } + + /** + * + */ + public String getAffinityClsName() { + return affinityClsName; + } + + /** + * @param affinityClsName Affinity class name. + */ + public void setAffinityClsName(String affinityClsName) { + this.affinityClsName = affinityClsName; + } + + /** + * @param cmd Command. + */ + public void print(VisorViewCacheCmd cmd) { + if (cmd == null) + cmd = VisorViewCacheCmd.CACHES; + + switch (cmd) { + case SEQ: + System.out.println("[seqName=" + getSeqName() + ", curVal=" + seqVal + ']'); + + break; + + case GROUPS: + System.out.println("[grpName=" + getGrpName() + ", grpId=" + getGrpId() + ", cachesCnt=" + getCachesCnt() + + ", prim=" + getPartitions() + ", mapped=" + getMapped() + ", mode=" + getMode() + + ", backups=" + getBackupsCnt() + ", affCls=" + getAffinityClsName() + ']'); + + break; + + default: + System.out.println("[cacheName=" + getCacheName() + ", cacheId=" + getCacheId() + + ", grpName=" + getGrpName() + ", grpId=" + getGrpId() + ", prim=" + getPartitions() + + ", mapped=" + getMapped() + ", mode=" + getMode() + + ", backups=" + getBackupsCnt() + ", affCls=" + getAffinityClsName() + ']'); + } + } + + /** {@inheritDoc} */ + @Override protected void writeExternalData(ObjectOutput out) throws IOException { + U.writeString(out, seqName); + out.writeLong(seqVal); + U.writeString(out, cacheName); + out.writeInt(cacheId); + U.writeString(out, grpName); + out.writeInt(grpId); + out.writeInt(partitions); + out.writeInt(mapped); + out.writeObject(topVer); + U.writeEnum(out, mode); + out.writeInt(backupsCnt); + U.writeString(out, affinityClsName); + out.writeInt(cachesCnt); + } + + /** {@inheritDoc} */ + @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException { + seqName = U.readString(in); + seqVal = in.readLong(); + cacheName = U.readString(in); + cacheId = in.readInt(); + grpName = U.readString(in); + grpId = in.readInt(); + partitions = in.readInt(); + mapped = in.readInt(); + topVer = (AffinityTopologyVersion)in.readObject(); + mode = CacheMode.fromOrdinal(in.readByte()); + backupsCnt = in.readInt(); + affinityClsName = U.readString(in); + cachesCnt = in.readInt(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(CacheInfo.class, this); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/4296fdd8/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/ContentionClosure.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/ContentionClosure.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/ContentionClosure.java new file mode 100644 index 0000000..e97378e --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/ContentionClosure.java @@ -0,0 +1,162 @@ +/* + * 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.processors.cache.verify; + +import java.util.ArrayList; +import java.util.Collection; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.processors.cache.GridCacheEntryEx; +import org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException; +import org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate; +import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; +import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry; +import org.apache.ignite.internal.processors.cache.transactions.IgniteTxLocalAdapter; +import org.apache.ignite.internal.processors.cache.transactions.IgniteTxLocalState; +import org.apache.ignite.internal.processors.cache.transactions.IgniteTxManager; +import org.apache.ignite.internal.processors.cache.transactions.IgniteTxState; +import org.apache.ignite.internal.processors.cache.transactions.IgniteTxStateImpl; +import org.apache.ignite.internal.util.typedef.internal.CU; +import org.apache.ignite.lang.IgniteCallable; +import org.apache.ignite.resources.IgniteInstanceResource; + +/** + */ +public class ContentionClosure implements IgniteCallable<ContentionInfo> { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** Ignite. */ + @IgniteInstanceResource + protected transient IgniteEx ignite; + + /** */ + private int minQueueSize; + + /** */ + private int maxPrint; + + /** + * @param minQueueSize Min candidate queue size to account. + * @param maxPrint Max entries to print. + */ + public ContentionClosure(int minQueueSize, int maxPrint) { + this.minQueueSize = minQueueSize; + this.maxPrint = maxPrint; + } + + /** {@inheritDoc} */ + @Override public ContentionInfo call() throws Exception { + final IgniteTxManager tm = ignite.context().cache().context().tm(); + + final Collection<IgniteInternalTx> activeTxs = tm.activeTransactions(); + + ContentionInfo ci = new ContentionInfo(); + + ci.setNode(ignite.localNode()); + ci.setEntries(new ArrayList<>()); + + for (IgniteInternalTx tx : activeTxs) { + if (ci.getEntries().size() == maxPrint) + break; + + // Show only primary txs. + if (tx.local()) { + IgniteTxLocalAdapter tx0 = (IgniteTxLocalAdapter)tx; + + final IgniteTxLocalState state0 = tx0.txState(); + + if (!(state0 instanceof IgniteTxStateImpl)) + continue; + + final IgniteTxStateImpl state = (IgniteTxStateImpl)state0; + + final Collection<IgniteTxEntry> entries = state.allEntriesCopy(); + + IgniteTxEntry bad = null; + + int qSize = 0; + + for (IgniteTxEntry entry : entries) { + Collection<GridCacheMvccCandidate> locs; + + GridCacheEntryEx cached = entry.cached(); + + while(true) { + try { + locs = cached.localCandidates(); + + break; + } + catch (GridCacheEntryRemovedException ignored) { + cached = entry.context().cache().entryEx(entry.key()); + } + } + + if (locs != null) + qSize += locs.size(); + + final Collection<GridCacheMvccCandidate> rmts = cached.remoteMvccSnapshot(); + + if (rmts != null) + qSize += rmts.size(); + + if (qSize >= minQueueSize) { + bad = entry; + + break; + } + else + qSize = 0; + } + + if (bad != null) { + StringBuilder b = new StringBuilder(); + + b.append("TxEntry [cacheId=").append(bad.cacheId()). + append(", key=").append(bad.key()). + append(", queue=").append(qSize). + append(", op=").append(bad.op()). + append(", val=").append(bad.value()). + append(", tx=").append(CU.txString(tx)). + append(", other=["); + + final IgniteTxState st = tx.txState(); + + if (st instanceof IgniteTxStateImpl) { + IgniteTxStateImpl st0 = (IgniteTxStateImpl)st; + + final Collection<IgniteTxEntry> cp = st0.allEntriesCopy(); + + for (IgniteTxEntry entry : cp) { + if (entry == bad) + continue; + + b.append(entry.toString()).append('\n'); + } + } + + b.append("]]"); + + ci.getEntries().add(b.toString()); + } + } + } + + return ci; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4296fdd8/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/ContentionInfo.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/ContentionInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/ContentionInfo.java new file mode 100644 index 0000000..c7bfbeb --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/ContentionInfo.java @@ -0,0 +1,72 @@ +/* + * 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.processors.cache.verify; + +import java.io.Serializable; +import java.util.List; +import org.apache.ignite.cluster.ClusterNode; + +/** + */ +public class ContentionInfo implements Serializable { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private ClusterNode node; + + /** */ + private List<String> entries; + + /** + * @return Node. + */ + public ClusterNode getNode() { + return node; + } + + /** + * @param node Node. + */ + public void setNode(ClusterNode node) { + this.node = node; + } + + /** + * @return Entries. + */ + public List<String> getEntries() { + return entries; + } + + /** + * @param entries Entries. + */ + public void setEntries(List<String> entries) { + this.entries = entries; + } + + /** */ + public void print() { + System.out.println("[node=" + node + ']'); + + for (String entry : entries) + System.out.println(" " + entry); + } +} + http://git-wip-us.apache.org/repos/asf/ignite/blob/4296fdd8/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/ViewCacheClosure.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/ViewCacheClosure.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/ViewCacheClosure.java new file mode 100644 index 0000000..1f363f3 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/ViewCacheClosure.java @@ -0,0 +1,185 @@ +/* + * 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.processors.cache.verify; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; +import javax.cache.Cache; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.cluster.ClusterGroup; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.IgniteKernal; +import org.apache.ignite.internal.processors.cache.CacheGroupContext; +import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor; +import org.apache.ignite.internal.processors.cache.IgniteInternalCache; +import org.apache.ignite.internal.processors.datastructures.AtomicDataStructureValue; +import org.apache.ignite.internal.processors.datastructures.DataStructureType; +import org.apache.ignite.internal.processors.datastructures.DataStructuresProcessor; +import org.apache.ignite.internal.processors.datastructures.GridCacheAtomicSequenceValue; +import org.apache.ignite.internal.processors.datastructures.GridCacheInternalKey; +import org.apache.ignite.internal.visor.verify.VisorViewCacheCmd; +import org.apache.ignite.lang.IgniteCallable; +import org.apache.ignite.resources.IgniteInstanceResource; + +/** + * View cache closure. + */ +public class ViewCacheClosure implements IgniteCallable<List<CacheInfo>> { + /** */ + private static final long serialVersionUID = 0L; + + /** Regex. */ + private String regex; + + /** {@code true} to skip cache destroying. */ + private VisorViewCacheCmd cmd; + + @IgniteInstanceResource + private Ignite ignite; + + /** + * @param regex Regex name for stopping caches. + * @param cmd Command. + */ + public ViewCacheClosure(String regex, VisorViewCacheCmd cmd) { + this.regex = regex; + this.cmd = cmd; + } + + /** {@inheritDoc} */ + @Override public List<CacheInfo> call() throws Exception { + Pattern compiled = Pattern.compile(regex); + + List<CacheInfo> cacheInfo = new ArrayList<>(); + + IgniteKernal k = (IgniteKernal)ignite; + + if (cmd == null) + cmd = VisorViewCacheCmd.CACHES; + + switch (cmd) { + case SEQ: + collectSequences(k.context(), compiled, cacheInfo); + + return cacheInfo; + + case GROUPS: + Collection<CacheGroupContext> contexts = k.context().cache().cacheGroups(); + + for (CacheGroupContext context : contexts) { + if (!compiled.matcher(context.cacheOrGroupName()).find()) + continue; + + CacheInfo ci = new CacheInfo(); + ci.setGrpName(context.cacheOrGroupName()); + ci.setGrpId(context.groupId()); + ci.setCachesCnt(context.caches().size()); + ci.setPartitions(context.config().getAffinity().partitions()); + ci.setBackupsCnt(context.config().getBackups()); + ci.setAffinityClsName(context.config().getAffinity().getClass().getSimpleName()); + ci.setMode(context.config().getCacheMode()); + ci.setMapped(mapped(context.caches().iterator().next().name())); + + cacheInfo.add(ci); + } + + return cacheInfo; + + default: + Map<String, DynamicCacheDescriptor> descMap = k.context().cache().cacheDescriptors(); + + for (Map.Entry<String, DynamicCacheDescriptor> entry : descMap.entrySet()) { + + DynamicCacheDescriptor desc = entry.getValue(); + + if (!compiled.matcher(desc.cacheName()).find()) + continue; + + CacheInfo ci = new CacheInfo(); + + ci.setCacheName(desc.cacheName()); + ci.setCacheId(desc.cacheId()); + ci.setGrpName(desc.groupDescriptor().groupName()); + ci.setGrpId(desc.groupDescriptor().groupId()); + ci.setPartitions(desc.cacheConfiguration().getAffinity().partitions()); + ci.setBackupsCnt(desc.cacheConfiguration().getBackups()); + ci.setAffinityClsName(desc.cacheConfiguration().getAffinity().getClass().getSimpleName()); + ci.setMode(desc.cacheConfiguration().getCacheMode()); + ci.setMapped(mapped(desc.cacheName())); + + cacheInfo.add(ci); + } + + return cacheInfo; + } + } + + /** + * @param cacheName Cache name. + */ + private int mapped(String cacheName) { + int mapped = 0; + + ClusterGroup srvs = ignite.cluster().forServers(); + + Collection<ClusterNode> nodes = srvs.forDataNodes(cacheName).nodes(); + + for (ClusterNode node : nodes) + mapped += ignite.affinity(cacheName).primaryPartitions(node).length; + + return mapped; + } + + /** + * @param ctx Context. + * @param compiled Compiled pattern. + * @param cacheInfo Cache info. + */ + private void collectSequences(GridKernalContext ctx, Pattern compiled, List<CacheInfo> cacheInfo) throws IgniteCheckedException { + String dsCacheName = DataStructuresProcessor.ATOMICS_CACHE_NAME + "@default-ds-group"; + + IgniteInternalCache<GridCacheInternalKey, AtomicDataStructureValue> cache0 = ctx.cache().cache(dsCacheName); + + final Iterator<Cache.Entry<GridCacheInternalKey, AtomicDataStructureValue>> iter = cache0.scanIterator(false, null); + + while (iter.hasNext()) { + Cache.Entry<GridCacheInternalKey, AtomicDataStructureValue> entry = iter.next(); + + final AtomicDataStructureValue val = entry.getValue(); + + if (val.type() == DataStructureType.ATOMIC_SEQ) { + final String name = entry.getKey().name(); + + if (compiled.matcher(name).find()) { + CacheInfo ci = new CacheInfo(); + ci.setSeqName(name); + ci.setSeqVal(((GridCacheAtomicSequenceValue)val).get()); + + cacheInfo.add(ci); + } + + } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4296fdd8/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/IndexValidationIssue.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/IndexValidationIssue.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/IndexValidationIssue.java new file mode 100644 index 0000000..37f9360 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/IndexValidationIssue.java @@ -0,0 +1,88 @@ +/* + * 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.visor.verify; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import org.apache.ignite.internal.util.tostring.GridToStringExclude; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.internal.visor.VisorDataTransferObject; + +/** + * + */ +public class IndexValidationIssue extends VisorDataTransferObject { + /** */ + private static final long serialVersionUID = 0L; + + /** Key. */ + private String key; + + /** Cache name. */ + private String cacheName; + + /** Index name. */ + private String idxName; + + /** T. */ + @GridToStringExclude + private Throwable t; + + /** + * + */ + public IndexValidationIssue() { + // Default constructor required for Externalizable. + } + + /** + * @param key Key. + * @param cacheName Cache name. + * @param idxName Index name. + * @param t T. + */ + public IndexValidationIssue(String key, String cacheName, String idxName, Throwable t) { + this.key = key; + this.cacheName = cacheName; + this.idxName = idxName; + this.t = t; + } + + /** {@inheritDoc} */ + @Override protected void writeExternalData(ObjectOutput out) throws IOException { + U.writeString(out, key); + U.writeString(out, cacheName); + U.writeString(out, idxName); + out.writeObject(t); + } + + /** {@inheritDoc} */ + @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException { + key = U.readString(in); + cacheName = U.readString(in); + idxName = U.readString(in); + t = (Throwable)in.readObject(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(IndexValidationIssue.class, this) + ", " + t.getClass() + ": " + t.getMessage(); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4296fdd8/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesPartitionResult.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesPartitionResult.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesPartitionResult.java new file mode 100644 index 0000000..1889960 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/ValidateIndexesPartitionResult.java @@ -0,0 +1,145 @@ +/* +* 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.visor.verify; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.ArrayList; +import java.util.List; +import org.apache.ignite.internal.util.tostring.GridToStringExclude; +import org.apache.ignite.internal.util.tostring.GridToStringInclude; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.internal.visor.VisorDataTransferObject; + +/** + * + */ +public class ValidateIndexesPartitionResult extends VisorDataTransferObject { + /** */ + private static final long serialVersionUID = 0L; + + /** Update counter. */ + private long updateCntr; + + /** Size. */ + private long size; + + /** Is primary. */ + private boolean isPrimary; + + /** Consistent id. */ + @GridToStringInclude + private Object consistentId; + + /** Issues. */ + @GridToStringExclude + private List<IndexValidationIssue> issues = new ArrayList<>(10); + + /** + * + */ + public ValidateIndexesPartitionResult() { + // Empty constructor required for Externalizable. + } + + /** + * @param updateCntr Update counter. + * @param size Size. + * @param isPrimary Is primary. + * @param consistentId Consistent id. + */ + public ValidateIndexesPartitionResult(long updateCntr, long size, boolean isPrimary, Object consistentId) { + this.updateCntr = updateCntr; + this.size = size; + this.isPrimary = isPrimary; + this.consistentId = consistentId; + } + + /** + * + */ + public long updateCntr() { + return updateCntr; + } + + /** + * + */ + public long size() { + return size; + } + + /** + * + */ + public boolean primary() { + return isPrimary; + } + + /** + * + */ + public Object consistentId() { + return consistentId; + } + + /** + * + */ + public List<IndexValidationIssue> issues() { + return issues; + } + + /** + * @param t Issue. + * @return True if there are already enough issues. + */ + public boolean reportIssue(IndexValidationIssue t) { + if (issues.size() >= 10) + return true; + + issues.add(t); + + return false; + } + + /** {@inheritDoc} */ + @Override protected void writeExternalData(ObjectOutput out) throws IOException { + out.writeLong(updateCntr); + out.writeLong(size); + out.writeBoolean(isPrimary); + out.writeObject(consistentId); + U.writeCollection(out, issues); + } + + /** {@inheritDoc} */ + @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException { + updateCntr = in.readLong(); + size = in.readLong(); + isPrimary = in.readBoolean(); + consistentId = in.readObject(); + issues = U.readList(in); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(ValidateIndexesPartitionResult.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4296fdd8/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionJobResult.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionJobResult.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionJobResult.java new file mode 100644 index 0000000..4272244 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionJobResult.java @@ -0,0 +1,80 @@ +/* +* 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.visor.verify; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.List; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.processors.cache.verify.ContentionInfo; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.internal.visor.VisorDataTransferObject; + +/** + * + */ +public class VisorContentionJobResult extends VisorDataTransferObject { + /** */ + private static final long serialVersionUID = 0L; + + /** Info. */ + private ContentionInfo info; + + /** + * @param info Info. + */ + public VisorContentionJobResult(ContentionInfo info) { + this.info = info; + } + + /** + * For externalization only. + */ + public VisorContentionJobResult() { + } + + /** + * @return Contention info. + */ + public ContentionInfo info() { + return info; + } + + /** {@inheritDoc} */ + @Override protected void writeExternalData(ObjectOutput out) throws IOException { + out.writeObject(info.getNode()); + U.writeCollection(out, info.getEntries()); + } + + /** {@inheritDoc} */ + @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException { + Object node = in.readObject(); + List<String> entries = U.readList(in); + + info = new ContentionInfo(); + info.setNode((ClusterNode)node); + info.setEntries(entries); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(VisorContentionJobResult.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4296fdd8/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionTask.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionTask.java new file mode 100644 index 0000000..4e7e12c --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionTask.java @@ -0,0 +1,100 @@ +/* +* 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.visor.verify; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.apache.ignite.IgniteException; +import org.apache.ignite.compute.ComputeJobResult; +import org.apache.ignite.internal.processors.cache.verify.ContentionClosure; +import org.apache.ignite.internal.processors.cache.verify.ContentionInfo; +import org.apache.ignite.internal.processors.task.GridInternal; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.internal.visor.VisorJob; +import org.apache.ignite.internal.visor.VisorMultiNodeTask; +import org.jetbrains.annotations.Nullable; + +/** + * + */ +@GridInternal +public class VisorContentionTask extends VisorMultiNodeTask<VisorContentionTaskArg, + VisorContentionTaskResult, VisorContentionJobResult> { + /** */ + private static final long serialVersionUID = 0L; + + /** {@inheritDoc} */ + @Nullable @Override protected VisorContentionTaskResult reduce0(List<ComputeJobResult> list) throws IgniteException { + Map<UUID, Exception> exceptions = new HashMap<>(); + List<VisorContentionJobResult> infos = new ArrayList<>(); + + for (ComputeJobResult res : list) { + if (res.getException() != null) + exceptions.put(res.getNode().id(), res.getException()); + else + infos.add(res.getData()); + } + + return new VisorContentionTaskResult(infos, exceptions); + } + + /** {@inheritDoc} */ + @Override protected VisorJob<VisorContentionTaskArg, VisorContentionJobResult> job(VisorContentionTaskArg arg) { + return new VisorContentionJob(arg, debug); + } + + /** + * + */ + private static class VisorContentionJob extends VisorJob<VisorContentionTaskArg, VisorContentionJobResult> { + /** */ + private static final long serialVersionUID = 0L; + + /** + * @param arg Argument. + * @param debug Debug. + */ + protected VisorContentionJob(@Nullable VisorContentionTaskArg arg, boolean debug) { + super(arg, debug); + } + + /** {@inheritDoc} */ + @Override protected VisorContentionJobResult run(@Nullable VisorContentionTaskArg arg) throws IgniteException { + try { + ContentionClosure clo = new ContentionClosure(arg.minQueueSize(), arg.maxPrint()); + + ignite.context().resource().injectGeneric(clo); + + ContentionInfo info = clo.call(); + + return new VisorContentionJobResult(info); + } + catch (Exception e) { + throw new IgniteException(e); + } + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(VisorContentionJob.class, this); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4296fdd8/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionTaskArg.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionTaskArg.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionTaskArg.java new file mode 100644 index 0000000..ecfc9d8 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionTaskArg.java @@ -0,0 +1,84 @@ +/* +* 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.visor.verify; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.internal.visor.VisorDataTransferObject; + +/** + * + */ +public class VisorContentionTaskArg extends VisorDataTransferObject { + /** */ + private static final long serialVersionUID = 0L; + + /** Min queue size. */ + private int minQueueSize; + + /** Max print size. */ + private int maxPrint; + + /** + * @param minQueueSize Min queue size. + * @param maxPrint Max print. + */ + public VisorContentionTaskArg(int minQueueSize, int maxPrint) { + this.minQueueSize = minQueueSize; + this.maxPrint = maxPrint; + } + + /** + * For externalization only. + */ + public VisorContentionTaskArg() { + } + + /** + * @return Min queue size. + */ + public int minQueueSize() { + return minQueueSize; + } + + /** + * @return Max print size. + */ + public int maxPrint() { + return maxPrint; + } + + /** {@inheritDoc} */ + @Override protected void writeExternalData(ObjectOutput out) throws IOException { + out.writeInt(minQueueSize); + out.writeInt(maxPrint); + } + + /** {@inheritDoc} */ + @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException { + minQueueSize = in.readInt(); + maxPrint = in.readInt(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(VisorContentionTaskArg.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4296fdd8/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionTaskResult.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionTaskResult.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionTaskResult.java new file mode 100644 index 0000000..5c452ca --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/verify/VisorContentionTaskResult.java @@ -0,0 +1,100 @@ +/* +* 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.visor.verify; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; +import org.apache.ignite.internal.processors.cache.verify.ContentionInfo; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.internal.visor.VisorDataTransferObject; + +/** + * + */ +public class VisorContentionTaskResult extends VisorDataTransferObject { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** Cluster infos. */ + private List<VisorContentionJobResult> clusterInfos; + + /** Exceptions. */ + private Map<UUID, Exception> exceptions; + + /** + * @param clusterInfos Cluster infos. + * @param exceptions Exceptions. + */ + public VisorContentionTaskResult(List<VisorContentionJobResult> clusterInfos, + Map<UUID, Exception> exceptions) { + this.clusterInfos = clusterInfos; + this.exceptions = exceptions; + } + + /** + * For externalization only. + */ + public VisorContentionTaskResult() { + } + + /** + * @return Cluster infos. + */ + public Collection<VisorContentionJobResult> jobResults() { + return clusterInfos; + } + + /** + * @return Collection of {@link ContentionInfo} collected during task execution. + */ + public Collection<ContentionInfo> getInfos() { + return clusterInfos.stream().map(VisorContentionJobResult::info).collect(Collectors.toList()); + } + + /** + * @return Exceptions. + */ + public Map<UUID, Exception> exceptions() { + return exceptions; + } + + /** {@inheritDoc} */ + @Override protected void writeExternalData(ObjectOutput out) throws IOException { + U.writeCollection(out, clusterInfos); + U.writeMap(out, exceptions); + } + + /** {@inheritDoc} */ + @Override protected void readExternalData(byte protoVer, ObjectInput in + ) throws IOException, ClassNotFoundException { + clusterInfos = U.readList(in); + exceptions = U.readMap(in); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(VisorContentionTaskResult.class, this); + } +}
