diff --git a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerIndexingCheckSizeTest.java b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerIndexingCheckSizeTest.java index e31bd4fc0f261..b4341acdcd332 100644 --- a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerIndexingCheckSizeTest.java +++ b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerIndexingCheckSizeTest.java @@ -436,7 +436,12 @@ private void checkNoCheckSizeInCaseBrokenData(String cacheName) { ); String out = testOut.toString(); + assertContains(log, out, "issues found (listed above)"); + + assertContains(log, out, String.format("Index issues found on node %s [consistentId='%s']:", + crd.localNode().id().toString(), crd.localNode().consistentId())); + assertNotContains(log, out, "Size check"); } @@ -471,8 +476,7 @@ private void validateCheckSizes( assertContains(log, out, "Size check"); Map valIdxCheckSizeResults = - ((ValidateIndexesTaskResult)lastOperationResult).results().get(node.localNode().id()) - .checkSizeResult(); + ((ValidateIndexesTaskResult)lastOperationResult).jobResult(node.localNode()).checkSizeResult(); assertEquals(rmvByTbl.size(), valIdxCheckSizeResults.size()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/api/CommandUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/management/api/CommandUtils.java index f3a8a7e57cadd..ad6d5ac724b56 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/management/api/CommandUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/api/CommandUtils.java @@ -549,17 +549,31 @@ public static boolean printErrors(Map exceptions, String infoMs printer.accept(infoMsg); - for (Map.Entry e : exceptions.entrySet()) { - printer.accept(INDENT + "Node ID: " + e.getKey()); - - printer.accept(INDENT + "Exception message:"); - printer.accept(DOUBLE_INDENT + e.getValue().getMessage()); - printer.accept(""); - } + exceptions.forEach((nodeId, err) -> printNodeError(printer, nodeId, null, err)); return true; } + /** + * Prints single node exception message to the log. + * + * @param printer Printer to use. + * @param nodeId Node id. + * @param consistentId Node consistent id. + * @param err Exception. + */ + public static void printNodeError( + Consumer printer, + UUID nodeId, + @Nullable Object consistentId, + Exception err + ) { + printer.accept(INDENT + "Node ID: " + nodeId + (consistentId == null ? "" : " [consistentId='" + consistentId + "']")); + printer.accept(INDENT + "Exception message:"); + printer.accept(DOUBLE_INDENT + err.getMessage()); + printer.accept(""); + } + /** */ public static boolean experimental(Command cmd) { return cmd.getClass().isAnnotationPresent(IgniteExperimental.class); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheValidateIndexesCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheValidateIndexesCommand.java index 525ddb244f2b5..9941797519ede 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheValidateIndexesCommand.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/CacheValidateIndexesCommand.java @@ -19,7 +19,6 @@ import java.util.Collection; import java.util.Map; -import java.util.UUID; import java.util.function.Consumer; import org.apache.ignite.internal.client.GridClientNode; import org.apache.ignite.internal.management.api.CommandUtils; @@ -64,9 +63,15 @@ public class CacheValidateIndexesCommand ValidateIndexesTaskResult res0, Consumer printer ) { - boolean errors = CommandUtils.printErrors(res0.exceptions(), "Index validation failed on nodes:", printer); + boolean errors = !F.isEmpty(res0.exceptions()); - for (Map.Entry nodeEntry : res0.results().entrySet()) { + if (errors) { + printer.accept("Index validation failed on nodes:"); + + res0.exceptions().forEach((node, err) -> CommandUtils.printNodeError(printer, node.id(), node.consistentId(), err)); + } + + for (Map.Entry nodeEntry : res0.results().entrySet()) { ValidateIndexesJobResult jobRes = nodeEntry.getValue(); if (!jobRes.hasIssues()) @@ -74,7 +79,8 @@ public class CacheValidateIndexesCommand errors = true; - printer.accept("Index issues found on node " + nodeEntry.getKey() + ":"); + printer.accept("Index issues found on node " + nodeEntry.getKey().id() + " [consistentId='" + + nodeEntry.getKey().consistentId() + "']:"); for (IndexIntegrityCheckIssue is : jobRes.integrityCheckFailures()) printer.accept(INDENT + is); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/ValidateIndexesTask.java b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/ValidateIndexesTask.java index 8b48e8b75e0f4..8a3c390a9d007 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/ValidateIndexesTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/ValidateIndexesTask.java @@ -20,10 +20,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.UUID; import org.apache.ignite.IgniteException; @@ -52,17 +50,16 @@ public class ValidateIndexesTask extends VisorMultiNodeTask list) throws IgniteException { - Map exceptions = new HashMap<>(); - Map jobResults = new HashMap<>(); + ValidateIndexesTaskResult taskResult = new ValidateIndexesTaskResult(); for (ComputeJobResult res : list) { if (res.getException() != null) - exceptions.put(res.getNode().id(), res.getException()); + taskResult.addException(res.getNode(), res.getException()); else - jobResults.put(res.getNode().id(), res.getData()); + taskResult.addResult(res.getNode(), res.getData()); } - return new ValidateIndexesTaskResult(jobResults, exceptions); + return taskResult; } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/ValidateIndexesTaskResult.java b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/ValidateIndexesTaskResult.java index 6ce7c2b2f4dca..345e0385371d1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/ValidateIndexesTaskResult.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/ValidateIndexesTaskResult.java @@ -17,14 +17,21 @@ package org.apache.ignite.internal.management.cache; +import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.UUID; +import org.apache.ignite.cluster.ClusterNode; 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.jetbrains.annotations.Nullable; /** * @@ -34,39 +41,50 @@ public class ValidateIndexesTaskResult extends VisorDataTransferObject { private static final long serialVersionUID = 0L; /** Exceptions. */ - private Map exceptions; + private @Nullable Map exceptions; /** Results from cluster. */ - private Map results; + private @Nullable Map results; /** - * @param results Results. - * @param exceptions Exceptions. + * Adds single node job result. */ - public ValidateIndexesTaskResult(Map results, - Map exceptions) { - this.exceptions = exceptions; - this.results = results; + public void addResult(ClusterNode clusterNode, ValidateIndexesJobResult jobResult) { + if (results == null) + results = new HashMap<>(); + + results.put(new NodeInfo(clusterNode.id(), clusterNode.consistentId()), jobResult); } /** - * For externalization only. + * @return Single node job result or {@code null} if not found. */ - public ValidateIndexesTaskResult() { + public @Nullable ValidateIndexesJobResult jobResult(ClusterNode clusterNode) { + return results().get(new NodeInfo(clusterNode.id(), clusterNode.consistentId())); } /** - * @return Exceptions. + * @return Results from cluster. */ - public Map exceptions() { - return exceptions; + public Map results() { + return results == null ? Collections.emptyMap() : results; } /** - * @return Results from cluster. + * Adds single node job failure. */ - public Map results() { - return results; + public void addException(ClusterNode clusterNode, Exception exception) { + if (exceptions == null) + exceptions = new HashMap<>(); + + exceptions.put(new NodeInfo(clusterNode.id(), clusterNode.consistentId()), exception); + } + + /** + * @return Exceptions. + */ + public Map exceptions() { + return exceptions == null ? Collections.emptyMap() : exceptions; } /** {@inheritDoc} */ @@ -85,4 +103,54 @@ public Map results() { @Override public String toString() { return S.toString(ValidateIndexesTaskResult.class, this); } + + /** + * Holds node id and consistent id. + */ + public static final class NodeInfo implements Serializable { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final UUID id; + + /** */ + private final Object consistentId; + + /** */ + private NodeInfo(UUID id, Object consistentId) { + assert consistentId instanceof Serializable || consistentId instanceof Externalizable; + + this.id = id; + this.consistentId = consistentId; + } + + /** */ + public UUID id() { + return id; + } + + /** */ + public Object consistentId() { + return consistentId; + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object o) { + if (this == o) + return true; + + if (o == null || getClass() != o.getClass()) + return false; + + NodeInfo id1 = (NodeInfo)o; + + return id.equals(id1.id) && consistentId.equals(id1.consistentId); + } + + /** {@inheritDoc} */ + @Override public int hashCode() { + return Objects.hash(id, consistentId); + } + } } diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/LongDestroyDurableBackgroundTaskTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/LongDestroyDurableBackgroundTaskTest.java index cdc81b0371caf..3220bc8f41e89 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/LongDestroyDurableBackgroundTaskTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/LongDestroyDurableBackgroundTaskTest.java @@ -380,23 +380,23 @@ private void validateIndexes(Ignite ignite) { ignite.compute().execute(ValidateIndexesTask.class.getName(), new VisorTaskArgument<>(nodeIds, taskArg, false)); if (!taskRes.exceptions().isEmpty()) { - for (Map.Entry e : taskRes.exceptions().entrySet()) - log.error("Exception while validation indexes on node id=" + e.getKey().toString(), e.getValue()); + for (Map.Entry e : taskRes.exceptions().entrySet()) + log.error("Exception while validation indexes on node id=" + e.getKey().id().toString(), e.getValue()); } - for (Map.Entry nodeEntry : taskRes.results().entrySet()) { - if (nodeEntry.getValue().hasIssues()) { - log.error("Validate indexes issues had been found on node id=" + nodeEntry.getKey().toString()); + taskRes.results().forEach((nodeInfo, res) -> { + if (res.hasIssues()) { + log.error("Validate indexes issues had been found on node id=" + nodeInfo.id().toString()); - log.error("Integrity check failures: " + nodeEntry.getValue().integrityCheckFailures().size()); + log.error("Integrity check failures: " + res.integrityCheckFailures().size()); - nodeEntry.getValue().integrityCheckFailures().forEach(f -> log.error(f.toString())); + res.integrityCheckFailures().forEach(f -> log.error(f.toString())); - logIssuesFromMap("Partition results", nodeEntry.getValue().partitionResult()); + logIssuesFromMap("Partition results", res.partitionResult()); - logIssuesFromMap("Index validation issues", nodeEntry.getValue().indexResult()); + logIssuesFromMap("Index validation issues", res.indexResult()); } - } + }); assertTrue(taskRes.exceptions().isEmpty()); diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexRebuildTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexRebuildTest.java index 8fb52068f8cb6..92049fe63eb27 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexRebuildTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexRebuildTest.java @@ -230,7 +230,7 @@ public void testFullIndexRebuild() throws Exception { ValidateIndexesTaskResult res = exec.get(); - Map results = res.results(); + Map results = res.results(); boolean hasIssue = false; @@ -329,7 +329,7 @@ public void testPartialIndexRebuild() throws Exception { ValidateIndexesTaskResult res = execute.get(); - Map results = res.results(); + Map results = res.results(); boolean hasIssue = false;