The transaction
statistic can show which
classes are involved in transaction lock contention. Often, this
is sufficient to help the developer already familiar with the application,
identify application changes for reducing the contention. For cases
where the code paths involved in the contention are not already known,
the transactioncontention
statistic can be useful.
Enabling the transactioncontention
statistic
causes the ActiveSpaces® Transactions
runtime to collect a stack backtrace each
time a transaction lock encounters contention. The stacks are saved
per managed class name.
The collection of transaction contention statistics is very expensive computationally and should only be used in development or test systems. |
To use transaction contention statistics, enable them with the
administrator enable statistics statistics=transactioncontention
command.
If your application is not already running, start it. This example uses the TransactionContention snippet shown below.
// $Revision: 1.1.2.1 $ package com.kabira.snippets.tuning; import com.kabira.platform.Transaction; import com.kabira.platform.annotation.Managed; /** * Simple transaction contention generator * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = A * </ul> * Note this sample needs to be explicitly stopped. */ public class TransactionContention { public static void main(String[] args) { // // Create a managed object to use for // generating transaction lock contention // final MyManaged myManaged = createMyManaged(); // // Create/start a thread which will // transactionally contend for the object. // new MyThread(myManaged).start(); while (true) { // // Contend for the object here // from // the main thread (competing // with the thread started above). // generateContention(myManaged); nap(200); } } static MyManaged createMyManaged() { return new Transaction("createMyManaged") { MyManaged m_object; @Override protected void run() { m_object = new MyManaged(); } MyManaged create() { execute(); return m_object; } }.create(); } static void generateContention(final MyManaged myManaged) { new Transaction("generateContention") { @Override protected void run() { writeLockObject(myManaged); } }.execute(); } @Managed static class MyManaged { } static void nap(int milliseconds) { try { Thread.sleep(milliseconds); } catch (InterruptedException e) { } } static class MyThread extends Thread { MyManaged m_object; MyThread(MyManaged myManaged) { m_object = myManaged; } @Override public void run() { while (true) { generateContention(m_object); nap(200); } } } }
After your application has run long enough to generate
some transaction lock contention, stop the data collection with the
administrator disable statistics statistics=transactioncontention
command.
Display the collected data with the
administrator display statistics statistics=transactioncontention
command.
======== transaction contention report for A ======== 24 occurrences on type com.kabira.snippets.tuning.TransactionContention$MyManaged of stack: com.kabira.platform.Transaction.lockObject(Native Method) com.kabira.platform.Transaction.writeLockObject(Transaction.java:706) com.kabira.snippets.tuning.TransactionContention$2.run(TransactionContention.java:48) com.kabira.platform.Transaction.execute(Transaction.java:484) com.kabira.platform.Transaction.execute(Transaction.java:542) com.kabira.snippets.tuning.TransactionContention.generateContention(TransactionContention.java:43) com.kabira.snippets.tuning.TransactionContention$MyThread.run(TransactionContention.java:84) 57 occurrences on type com.kabira.snippets.tuning.TransactionContention$MyManaged of stack: com.kabira.platform.Transaction.lockObject(Native Method) com.kabira.platform.Transaction.writeLockObject(Transaction.java:706) com.kabira.snippets.tuning.TransactionContention$2.run(TransactionContention.java:48) com.kabira.platform.Transaction.execute(Transaction.java:484) com.kabira.platform.Transaction.execute(Transaction.java:542) com.kabira.snippets.tuning.TransactionContention.generateContention(TransactionContention.java:43) com.kabira.snippets.tuning.TransactionContention.main(TransactionContention.java:16) sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) java.lang.reflect.Method.invoke(Method.java:483) com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) java.lang.reflect.Method.invoke(Method.java:483) com.kabira.platform.MainWrapper.invokeMain(MainWrapper.java:65)
This output shows the two call paths which experienced contention.
The collected data may be cleared with the
administrator clear statistics statistics=transactioncontention
command.