Analyzing Transaction Lock Contention

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.

[Note]

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.