Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 15 Next »

BTM Implementation details

BTM is made of multiple modules which map as close as possible the JTA API.

This page contains descriptions of those components and how they work internally once BTM 1.3 will be released, as versions 1.2 and before did not fully respect this modularization.


Bitronix implementation specifics


The JTA specification defines XID as an interface for which an implementation must be provided by the transaction manager. There are 3 important pieces composing a XID: the format ID, the Global TRansaction ID (GTRID) and the Branch QUALilifier (BQUAL).

Format ID

The format ID identifies the transaction manager which generated the XID. It basically is an integer which must be unique across all implementations. The BTM format ID simply is the int-encoded version of the "Btnx" ASCII string: 0x42746e78.


The GTRID uniquely identifies the global transaction across all participating resources. The JTA spec says it must fit in a 64 bytes array and must be globally unique. The BTM implementation builds them by combining 3 data: the serverId, a timestamp and a sequence number.


The BQUAL uniquely identifies the local part of a global transaction inside a single participating resource. As for the GTRID the JTA spec says it must fit in a 64 bytes array and must be globally unique. The BTM BQUALs are built with the exact same format as the GTRID.

2PC engine


XA connection pooling framework


Disk journal

The disk journal is a simple two-files (called fragments) rollover transaction store. It provides services to the transaction manager engine to record transaction states and reporting of transactions left in an unfinished state.

Recovery engine


This setting is very important when you're running a cluster of virtual machines all working on the same resource. In this case BTM will run multiple times in parallel, each node creating different transactions on the resource. Since the XIDs are guaranteed to be globally unique this isn't a problem for the transaction manager core.

The recovery engine can on the other hand get confused with this setup. Take for instance this scenario:

Two servers are accessing a single database. Server 1 started a transaction identified by XID 1 while at the same time server 2 started a transaction identified by XID 2. Now what would happen if recovery kicks in in the background on server 1 (or if server 1 gets restarted) while XID 2 is still in-flight on server 2 ? Server 1 would ask its journal for a list of unfinished transactions and compare that against the list of XIDs it got by querying the database. We can ignore XID 1 in this case as the TM has knowledge of it and we can assume it would handle it fine. But what is server 1 supposed to do with XID 2 ? It is reported by the database as an unfinished transaction and server 1 has no trace of it in its journal. As per the presumed abort optimization the recovery engine will assume that the transaction needs to be rolled back as it has no knowledge that it still is running on server 2 !

  • No labels