From 4776a1ab8406073cb62f732734ec09a1e933d9ad Mon Sep 17 00:00:00 2001 From: a-polyakov Date: Mon, 18 Jun 2018 19:11:32 +0300 Subject: [PATCH] IGNITE-8601 Add to control.sh utility information about transaction start time - Fixes #4070. --- .../internal/TransactionsMXBeanImpl.java | 2 +- .../internal/commandline/CommandHandler.java | 6 ++- .../ignite/internal/visor/tx/VisorTxInfo.java | 37 +++++++++++++++-- .../internal/visor/tx/VisorTxSortOrder.java | 8 +++- .../ignite/internal/visor/tx/VisorTxTask.java | 20 ++++++++- .../ignite/util/GridCommandHandlerTest.java | 41 +++++++++++-------- 6 files changed, 89 insertions(+), 25 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/TransactionsMXBeanImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/TransactionsMXBeanImpl.java index 6937ebd146c4a..210a32008d313 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/TransactionsMXBeanImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/TransactionsMXBeanImpl.java @@ -25,7 +25,6 @@ import java.util.UUID; import java.util.stream.Collectors; import org.apache.ignite.IgniteCompute; -import org.apache.ignite.IgniteException; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.S; @@ -107,6 +106,7 @@ else if ("SIZE".equals(order)) w.println(" Tx: [xid=" + info.getXid() + ", label=" + info.getLabel() + ", state=" + info.getState() + + ", startTime=" + info.getFormattedStartTime() + ", duration=" + info.getDuration() / 1000 + ", isolation=" + info.getIsolation() + ", concurrency=" + info.getConcurrency() + 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 be33991fa96c0..ed85f0c850ba9 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 @@ -236,6 +236,9 @@ public class CommandHandler { /** */ private static final String TX_ORDER = "order"; + /** */ + public static final String CMD_TX_ORDER_START_TIME="START_TIME"; + /** */ private static final String TX_SERVERS = "servers"; @@ -1079,6 +1082,7 @@ else if (arg.getOperation() == VisorTxOperation.KILL) log(" Tx: [xid=" + info.getXid() + ", label=" + info.getLabel() + ", state=" + info.getState() + + ", startTime=" + info.getFormattedStartTime() + ", duration=" + info.getDuration() / 1000 + ", isolation=" + info.getIsolation() + ", concurrency=" + info.getConcurrency() + @@ -1826,7 +1830,7 @@ public int execute(List rawArgs) { usage(" Set baseline topology based on version:", BASELINE, " version topologyVersion [--force]"); usage(" List or kill transactions:", TX, " [xid XID] [minDuration SECONDS] " + "[minSize SIZE] [label PATTERN_REGEX] [servers|clients] " + - "[nodes consistentId1[,consistentId2,....,consistentIdN] [limit NUMBER] [order DURATION|SIZE] [kill] [--force]"); + "[nodes consistentId1[,consistentId2,....,consistentIdN] [limit NUMBER] [order DURATION|SIZE|", CMD_TX_ORDER_START_TIME, "] [kill] [--force]"); if(enableExperimental) { usage(" Print absolute paths of unused archived wal segments on each node:", WAL, diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxInfo.java index 89bf274653165..ecf3e0d79fb4c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxInfo.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxInfo.java @@ -20,8 +20,11 @@ import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; -import java.io.Serializable; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.Collection; +import java.util.TimeZone; import java.util.UUID; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; @@ -37,9 +40,17 @@ public class VisorTxInfo extends VisorDataTransferObject { /** */ private static final long serialVersionUID = 0L; + /** */ + private static DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); + /** */ private IgniteUuid xid; + /** + * Transaction start time. + */ + private long startTime; + /** */ private long duration; @@ -73,6 +84,7 @@ public VisorTxInfo() { /** * @param xid Xid. + * @param startTime Start time of transaction. * @param duration Duration. * @param isolation Isolation. * @param concurrency Concurrency. @@ -82,10 +94,11 @@ public VisorTxInfo() { * @param state State. * @param size Size. */ - public VisorTxInfo(IgniteUuid xid, long duration, TransactionIsolation isolation, + public VisorTxInfo(IgniteUuid xid, long startTime, long duration, TransactionIsolation isolation, TransactionConcurrency concurrency, long timeout, String lb, Collection primaryNodes, TransactionState state, int size) { this.xid = xid; + this.startTime = startTime; this.duration = duration; this.isolation = isolation; this.concurrency = concurrency; @@ -101,6 +114,16 @@ public IgniteUuid getXid() { return xid; } + /** */ + public long getStartTime() { + return startTime; + } + + /** */ + public String getFormattedStartTime() { + return dateTimeFormatter.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(startTime), TimeZone.getDefault().toZoneId())); + } + /** */ public long getDuration() { return duration; @@ -141,6 +164,11 @@ public int getSize() { return size; } + /** {@inheritDoc} */ + @Override public byte getProtocolVersion() { + return V2; + } + /** {@inheritDoc} */ @Override protected void writeExternalData(ObjectOutput out) throws IOException { U.writeGridUuid(out, xid); @@ -152,10 +180,12 @@ public int getSize() { U.writeCollection(out, primaryNodes); U.writeEnum(out, state); out.writeInt(size); + out.writeLong(startTime); } /** {@inheritDoc} */ - @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException { + @Override protected void readExternalData(byte protoVer, + ObjectInput in) throws IOException, ClassNotFoundException { xid = U.readGridUuid(in); duration = in.readLong(); isolation = TransactionIsolation.fromOrdinal(in.readByte()); @@ -165,6 +195,7 @@ public int getSize() { primaryNodes = U.readCollection(in); state = TransactionState.fromOrdinal(in.readByte()); size = in.readInt(); + startTime = protoVer >= V2 ? in.readLong() : 0L; } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxSortOrder.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxSortOrder.java index 382cf9152207b..9a18882c24958 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxSortOrder.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxSortOrder.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal.visor.tx; +import org.apache.ignite.internal.commandline.CommandHandler; import org.jetbrains.annotations.Nullable; /** @@ -25,7 +26,9 @@ public enum VisorTxSortOrder { /** Sort by duration. */ DURATION, /** Sort by size. */ - SIZE; + SIZE, + /** Sort by startTime */ + START_TIME; /** Enumerated values. */ private static final VisorTxSortOrder[] VALS = values(); @@ -50,6 +53,9 @@ public static VisorTxSortOrder fromString(String name) { if (SIZE.toString().equals(name)) return SIZE; + if (CommandHandler.CMD_TX_ORDER_START_TIME.equals(name)) + return START_TIME; + throw new IllegalArgumentException("Sort order is unknown: " + name); } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTask.java index 579abbe9261a9..25a69d1d67e06 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTask.java @@ -194,7 +194,7 @@ private VisorTxJob(VisorTxTaskArg arg, boolean debug) { if (arg.getMinSize() != null && size < arg.getMinSize()) continue; - infos.add(new VisorTxInfo(locTx.xid(), duration, locTx.isolation(), locTx.concurrency(), + infos.add(new VisorTxInfo(locTx.xid(), locTx.startTime(), duration, locTx.isolation(), locTx.concurrency(), locTx.timeout(), locTx.label(), mappings, locTx.state(), size)); if (arg.getOperation() == VisorTxOperation.KILL) @@ -218,6 +218,11 @@ private VisorTxJob(VisorTxTaskArg arg, boolean debug) { break; + case START_TIME: + comp = TxStartTimeComparator.INSTANCE; + + break; + default: } } @@ -228,6 +233,19 @@ private VisorTxJob(VisorTxTaskArg arg, boolean debug) { } } + /** + * + */ + private static class TxStartTimeComparator implements Comparator { + /** Instance. */ + public static final TxStartTimeComparator INSTANCE = new TxStartTimeComparator(); + + /** {@inheritDoc} */ + @Override public int compare(VisorTxInfo o1, VisorTxInfo o2) { + return Long.compare(o2.getStartTime(), o1.getStartTime()); + } + } + /** * */ diff --git a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java index 11389bf97b905..62f15181f537b 100644 --- a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java +++ b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java @@ -456,16 +456,13 @@ else if (entry.getKey().equals(node2)) { validate(h, map -> { VisorTxTaskResult res = map.get(grid(0).localNode()); - for (VisorTxInfo info:res.getInfos()){ + for (VisorTxInfo info : res.getInfos()) assertNull(info.getLabel()); - } - }, "--tx", "label", "null"); - // test check minSize - int minSize=10; + int minSize = 10; validate(h, map -> { VisorTxTaskResult res = map.get(grid(0).localNode()); @@ -482,7 +479,7 @@ else if (entry.getKey().equals(node2)) { validate(h, map -> { VisorTxTaskResult res = map.get(grid(0).localNode()); - assertTrue(res.getInfos().get(0).getSize() >= res.getInfos().get(1).getSize()); + assertTrue(res.getInfos().get(0).getSize() >= res.getInfos().get(1).getSize()); }, "--tx", "order", "SIZE"); @@ -490,10 +487,18 @@ else if (entry.getKey().equals(node2)) { validate(h, map -> { VisorTxTaskResult res = map.get(grid(0).localNode()); - assertTrue(res.getInfos().get(0).getDuration() >= res.getInfos().get(1).getDuration()); + assertTrue(res.getInfos().get(0).getDuration() >= res.getInfos().get(1).getDuration()); }, "--tx", "order", "DURATION"); + // test order by start_time. + validate(h, map -> { + VisorTxTaskResult res = map.get(grid(0).localNode()); + + for (int i = res.getInfos().size() - 1; i > 1; i--) + assertTrue(res.getInfos().get(i - 1).getStartTime() >= res.getInfos().get(i).getStartTime()); + }, "--tx", "order", CommandHandler.CMD_TX_ORDER_START_TIME); + // Trigger topology change and test connection. IgniteInternalFuture startFut = multithreadedAsync(() -> { try { @@ -846,16 +851,16 @@ private void validate(CommandHandler h, IgniteInClosure generate(int from, int cnt) { Map map = new TreeMap<>(); - for (int i = 0; i < cnt; i++ ) + for (int i = 0; i < cnt; i++) map.put(i + from, i + from); return map; } /** - * Test execution of --wal print command. + * Test execution of --wal print command. * - * @throws Exception if failed. + * @throws Exception if failed. */ public void testUnusedWalPrint() throws Exception { Ignite ignite = startGrids(2); @@ -864,14 +869,14 @@ public void testUnusedWalPrint() throws Exception { List nodes = new ArrayList<>(2); - for (ClusterNode node: ignite.cluster().forServers().nodes()) + for (ClusterNode node : ignite.cluster().forServers().nodes()) nodes.add(node.consistentId().toString()); injectTestSystemOut(); assertEquals(EXIT_CODE_OK, execute("--wal", "print")); - for(String id: nodes) + for (String id : nodes) assertTrue(testOut.toString().contains(id)); assertTrue(!testOut.toString().contains("error")); @@ -886,9 +891,9 @@ public void testUnusedWalPrint() throws Exception { } /** - * Test execution of --wal delete command. + * Test execution of --wal delete command. * - * @throws Exception if failed. + * @throws Exception if failed. */ public void testUnusedWalDelete() throws Exception { Ignite ignite = startGrids(2); @@ -897,14 +902,14 @@ public void testUnusedWalDelete() throws Exception { List nodes = new ArrayList<>(2); - for (ClusterNode node: ignite.cluster().forServers().nodes()) + for (ClusterNode node : ignite.cluster().forServers().nodes()) nodes.add(node.consistentId().toString()); injectTestSystemOut(); assertEquals(EXIT_CODE_OK, execute("--wal", "delete")); - for(String id: nodes) + for (String id : nodes) assertTrue(testOut.toString().contains(id)); assertTrue(!testOut.toString().contains("error")); @@ -919,11 +924,11 @@ public void testUnusedWalDelete() throws Exception { } /** - * * @param lockLatch Lock latch. * @param unlockLatch Unlock latch. */ - private IgniteInternalFuture startTransactions(CountDownLatch lockLatch, CountDownLatch unlockLatch) throws Exception { + private IgniteInternalFuture startTransactions(CountDownLatch lockLatch, + CountDownLatch unlockLatch) throws Exception { IgniteEx client = grid("client"); AtomicInteger idx = new AtomicInteger();