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);
+    }
+}

Reply via email to