This is an automated email from the ASF dual-hosted git repository. irakov pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push: new 71b1f54 IGNITE-12516 Dump active transaction from near node does not work if transaction not follow first - Fixes #7221. 71b1f54 is described below commit 71b1f54557293faaea703cb38f2e6c8eeb57402d Author: denis-chudov <regmoongl...@gmail.com> AuthorDate: Wed Jan 29 19:43:38 2020 +0300 IGNITE-12516 Dump active transaction from near node does not work if transaction not follow first - Fixes #7221. Signed-off-by: Ivan Rakov <ira...@apache.org> --- .../cache/FetchActiveTxOwnerTraceClosure.java | 37 ++----- .../cache/GridCachePartitionExchangeManager.java | 121 +++++++++++---------- ...CacheLongRunningTransactionDiagnosticsTest.java | 35 +++--- 3 files changed, 90 insertions(+), 103 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/FetchActiveTxOwnerTraceClosure.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/FetchActiveTxOwnerTraceClosure.java index 0c51c83..4020f84 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/FetchActiveTxOwnerTraceClosure.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/FetchActiveTxOwnerTraceClosure.java @@ -16,12 +16,10 @@ */ package org.apache.ignite.internal.processors.cache; +import org.apache.ignite.internal.util.GridStringBuilder; +import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteCallable; -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadInfo; -import java.lang.management.ThreadMXBean; - /** * Closure that is computed on near node to get the stack trace of active transaction owner thread. */ @@ -30,9 +28,6 @@ public class FetchActiveTxOwnerTraceClosure implements IgniteCallable<String> { private static final long serialVersionUID = 0L; /** */ - private static final StackTraceElement[] STACK_TRACE_ELEMENT_EMPTY = new StackTraceElement[0]; - - /** */ private final long txOwnerThreadId; /** */ @@ -47,33 +42,15 @@ public class FetchActiveTxOwnerTraceClosure implements IgniteCallable<String> { * @throws Exception If failed */ @Override public String call() throws Exception { - StringBuilder traceDump = new StringBuilder("Stack trace of the transaction owner thread:\n"); - - for (StackTraceElement stackTraceElement : getStackTrace()) { - traceDump.append(stackTraceElement.toString()); - traceDump.append("\n"); - } - - return traceDump.toString(); - } - - /** - * Gets the stack trace of the transaction owner thread - * - * @return stack trace elements - */ - private StackTraceElement[] getStackTrace() { - ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); - - ThreadInfo threadInfo; + GridStringBuilder traceDump = new GridStringBuilder("Stack trace of the transaction owner thread:\n"); try { - threadInfo = threadMXBean.getThreadInfo(txOwnerThreadId, Integer.MAX_VALUE); + U.printStackTrace(txOwnerThreadId, traceDump); } - catch (SecurityException | IllegalArgumentException ignored) { - threadInfo = null; + catch (SecurityException | IllegalArgumentException e) { + traceDump = new GridStringBuilder("Could not get stack trace of the transaction owner thread: " + e.getMessage()); } - return threadInfo == null ? STACK_TRACE_ELEMENT_EMPTY : threadInfo.getStackTrace(); + return traceDump.toString(); } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java index 9d9917a..308e6a4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Map; import java.util.NavigableMap; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.TreeMap; import java.util.UUID; @@ -2151,7 +2152,11 @@ public class GridCachePartitionExchangeManager<K, V> extends GridCacheSharedMana if (warnings.canAddMessage()) { warnings.add(longRunningTransactionWarning(tx, curTime)); - if (ltrDumpLimiter.allowAction(tx)) + if (cctx.tm().txOwnerDumpRequestsAllowed() + && !Optional.ofNullable(cctx.kernalContext().config().isClientMode()).orElse(false) + && tx.local() + && tx.state() == TransactionState.ACTIVE + && ltrDumpLimiter.allowAction(tx)) dumpLongRunningTransaction(tx); } else @@ -2232,77 +2237,75 @@ public class GridCachePartitionExchangeManager<K, V> extends GridCacheSharedMana * @param tx Transaction. */ private void dumpLongRunningTransaction(IgniteInternalTx tx) { - if (cctx.tm().txOwnerDumpRequestsAllowed() && tx.local() && tx.state() == TransactionState.ACTIVE) { - Collection<UUID> masterNodeIds = tx.masterNodeIds(); + Collection<UUID> masterNodeIds = tx.masterNodeIds(); - if (masterNodeIds.size() == 1) { - UUID nearNodeId = masterNodeIds.iterator().next(); + if (masterNodeIds.size() == 1) { + UUID nearNodeId = masterNodeIds.iterator().next(); - long txOwnerThreadId = tx.threadId(); + long txOwnerThreadId = tx.threadId(); - Ignite ignite = cctx.kernalContext().grid(); + Ignite ignite = cctx.kernalContext().grid(); - ClusterGroup nearNode = ignite.cluster().forNodeId(nearNodeId); + ClusterGroup nearNode = ignite.cluster().forNodeId(nearNodeId); - String txRequestInfo = String.format( - "[xidVer=%s, nodeId=%s]", - tx.xidVersion().toString(), - nearNodeId.toString() - ); + String txRequestInfo = String.format( + "[xidVer=%s, nodeId=%s]", + tx.xidVersion().toString(), + nearNodeId.toString() + ); - if (allNodesSupports(nearNode.nodes(), TRANSACTION_OWNER_THREAD_DUMP_PROVIDING)) { - IgniteCompute compute = ignite.compute(ignite.cluster().forNodeId(nearNodeId)); + if (allNodesSupports(nearNode.nodes(), TRANSACTION_OWNER_THREAD_DUMP_PROVIDING)) { + IgniteCompute compute = ignite.compute(ignite.cluster().forNodeId(nearNodeId)); - try { - compute - .callAsync(new FetchActiveTxOwnerTraceClosure(txOwnerThreadId)) - .listen(new IgniteInClosure<IgniteFuture<String>>() { - @Override public void apply(IgniteFuture<String> strIgniteFut) { - String traceDump = null; + try { + compute + .callAsync(new FetchActiveTxOwnerTraceClosure(txOwnerThreadId)) + .listen(new IgniteInClosure<IgniteFuture<String>>() { + @Override public void apply(IgniteFuture<String> strIgniteFut) { + String traceDump = null; - try { - traceDump = strIgniteFut.get(); - } - catch (ClusterGroupEmptyException e) { - U.error( - diagnosticLog, - "Could not get thread dump from transaction owner because near node " + - "is now out of topology. " + txRequestInfo - ); - } - catch (Exception e) { - U.error( - diagnosticLog, - "Could not get thread dump from transaction owner near node " + txRequestInfo, - e - ); - } + try { + traceDump = strIgniteFut.get(); + } + catch (ClusterGroupEmptyException e) { + U.error( + diagnosticLog, + "Could not get thread dump from transaction owner because near node " + + "is out of topology now. " + txRequestInfo + ); + } + catch (Exception e) { + U.error( + diagnosticLog, + "Could not get thread dump from transaction owner near node " + txRequestInfo, + e + ); + } - if (traceDump != null) { - U.warn( - diagnosticLog, - String.format( - "Dumping the near node thread that started transaction %s\n%s", - txRequestInfo, - traceDump - ) - ); - } + if (traceDump != null) { + U.warn( + diagnosticLog, + String.format( + "Dumping the near node thread that started transaction %s\n%s", + txRequestInfo, + traceDump + ) + ); } - }); - } - catch (Exception e) { - U.error(diagnosticLog, "Could not send dump request to transaction owner near node " + txRequestInfo, e); - } + } + }); } - else { - U.warn( - diagnosticLog, - "Could not send dump request to transaction owner near node: node does not support this feature. " + - txRequestInfo - ); + catch (Exception e) { + U.error(diagnosticLog, "Could not send dump request to transaction owner near node " + txRequestInfo, e); } } + else { + U.warn( + diagnosticLog, + "Could not send dump request to transaction owner near node: node does not support this feature. " + + txRequestInfo + ); + } } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheLongRunningTransactionDiagnosticsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheLongRunningTransactionDiagnosticsTest.java index 00ac8b5..196a6ad 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheLongRunningTransactionDiagnosticsTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheLongRunningTransactionDiagnosticsTest.java @@ -16,10 +16,6 @@ */ package org.apache.ignite.internal.processors.cache; -import java.lang.management.ManagementFactory; -import javax.management.MBeanServer; -import javax.management.MBeanServerInvocationHandler; -import javax.management.ObjectName; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.GridJobExecuteRequest; @@ -27,8 +23,9 @@ import org.apache.ignite.internal.GridTopic; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.TestRecordingCommunicationSpi; import org.apache.ignite.internal.TransactionsMXBeanImpl; -import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.mxbean.TransactionsMXBean; +import org.apache.ignite.testframework.ListeningTestLogger; +import org.apache.ignite.testframework.LogListener; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.apache.ignite.transactions.Transaction; import org.junit.Test; @@ -55,6 +52,9 @@ public class GridCacheLongRunningTransactionDiagnosticsTest extends GridCommonAb /** */ private static String longOpTimeoutCommon; + /** */ + private final LogListener dumpLsnr = LogListener.matches("Dumping the near node thread that started transaction").build(); + /** {@inheritDoc} */ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); @@ -77,6 +77,12 @@ public class GridCacheLongRunningTransactionDiagnosticsTest extends GridCommonAb cfg.setCacheConfiguration(ccfg); } + ListeningTestLogger testLog = new ListeningTestLogger(false, log); + + testLog.registerListener(dumpLsnr); + + cfg.setGridLogger(testLog); + return cfg; } @@ -154,6 +160,8 @@ public class GridCacheLongRunningTransactionDiagnosticsTest extends GridCommonAb * @throws Exception if failed. */ private void imitateLongTransaction(boolean shouldRcvThreadDumpReq) throws Exception { + dumpLsnr.reset(); + final int val = 0; final IgniteEx client = startGrid("client"); @@ -181,20 +189,19 @@ public class GridCacheLongRunningTransactionDiagnosticsTest extends GridCommonAb shouldRcvThreadDumpReq, FetchActiveTxOwnerTraceClosure.class.getName().equals(taskNameContainer.toString()) ); + + assertEquals(shouldRcvThreadDumpReq, dumpLsnr.check()); } /** * */ private TransactionsMXBean txMXBean(int igniteInt) throws Exception { - ObjectName mbeanName = U.makeMBeanName(getTestIgniteInstanceName(igniteInt), "Transactions", - TransactionsMXBeanImpl.class.getSimpleName()); - - MBeanServer mbeanSrv = ManagementFactory.getPlatformMBeanServer(); - - if (!mbeanSrv.isRegistered(mbeanName)) - fail("MBean is not registered: " + mbeanName.getCanonicalName()); - - return MBeanServerInvocationHandler.newProxyInstance(mbeanSrv, mbeanName, TransactionsMXBean.class, true); + return getMxBean( + getTestIgniteInstanceName(igniteInt), + "Transactions", + TransactionsMXBean.class, + TransactionsMXBeanImpl.class + ); } }