HP OpenVMS Systems Documentation
HP OpenVMS Programming Concepts Manual
30.5.1 Creating RM Instances and Participants
You can create an RMI by calling $DECLARE_RM. This specifies an event handler for the RM in the process and returns the RM_ID that is needed to add participants to transactions.
The RM can add an RM participant as follows:
In either case, the RM specifies a participant name, the RM_ID, which is used as a key to retrieve transaction state information on recovery from an RM or system failure. The RM_ID has the following characteristics:
You can design an RM to be used either with or without DECdtm. In the
latter case, the RM may perform a single request as a transaction
without calling DECdtm. Such RMs must take care when using
$GET_DEFAULT_TRANS. A status of SS$_NOCURTID indicates that either no
transaction has started, or that a transaction started and then aborted
before the RM was called. Therefore, the RM interface must provide some
way for an AP to specify whether requests are for DECdtm transactions
or not, for example, by using an interface function, or by setting a
mode switch with a logical name. Do not decide if a DECdtm transaction
is required just by checking $GET_DEFAULT_TRANS for a TID. The RM
should return an error (for example, SS$_ABORTED) if the AP requires a
DECdtm transaction and there is no current TID.
The DECdtm transaction manager reports events to an RMI and the RM participants associated with it using asynchronous system traps (ASTs) executed in the access mode specified in the call $DECLARE_RM that created that RMI.
The DECdtm transaction manager creates an event report block, and passes its address to the AST routine in the parameter of the AST. Each event report block contains the following:
Table 30-1 describes the fields in an event report block, in alphabetical order.
Each event report must be acknowledged by calling $ACK_EVENT, specifying the identifier of the report. This acknowledgment need not come from AST context.
The DECdtm transaction manager delivers only one event report at a time to each RM participant. For example, if a prepare event report has been delivered to an RM participant, and the transaction is aborted while the RM participant is doing its prepare processing, then the DECdtm transaction manager does not deliver an abort event report to that RM participant until it has acknowledged the prepare event report by a call to $ACK_EVENT. Note that the DECdtm transaction manager may deliver multiple reports to an RMI.
After acknowledging the event report, the RMI or RM participant should
no longer access the event report block.
The primary requirement of an RM participant is that it should respond to the following DECdtm events by calling $ACK_EVENT.
Delivered at the start of phase 1. Normally, the participant saves on disk information needed to commit or abort the transaction, and responds with SS$_PREPARED.
If the participant has not updated any resources during the transaction, it may respond with SS$_FORGET. The participant should then release any locks on its resources. This optimization eliminates an unnecessary commit or abort event.
If the participant had an error while the transaction was active, or is unable to save information to disk, it responds with SS$_VETO. The participant may then abort its transaction and release any locks on its resources.
Delivered as an alternative to DDTM$K_PREPARE if there is a single participant and it is in the process that started the transaction.
The participant may commit the transaction and respond with SS$_NORMAL. This optimization eliminates the need for DECdtm to log information and to deliver a commit event.
The participant may respond with SS$_PREPARED to request a regular two- phase commit, or with SS$_VETO to abort the transaction.
Delivered when all participants have voted SS$_PREPARED in phase 1.
Normally, the participant commits the transaction and responds with SS$_FORGET. This allows DECdtm to discard the transaction from its log. The participant may then release any locks on its resources.
Alternatively, the participant may respond with SS$_REMEMBER. This is used if the RM encounters an error while committing the transaction. DECdtm retains information about the transaction in its log. The RM must commit the transaction later, as a recovery operation.
Delivered after $ABORT_TRANS has been called on any node, or when one or more of the participants have responded with SS$_VETO in phase 1.
Table 30-2 shows the the abort reason codes.
The participant must abort the transaction and respond with SS$_FORGET. It may then release any locks on its resources.
The previous descriptions suggest that a participant drops locks after calling $ACK_EVENT. It could equally well drop locks immediately before calling $ACK_EVENT.
To ensure isolation between transactions (distributed or otherwise), RMs set locks on all resources that are either read or updated, and observe a two-phase lock protocol. This specifies that a transaction must be divided into a phase when locks may be acquired and a following phase when locks may be released. When any lock is released, no further locks may be acquired. An RM may gain a useful improvement in concurrency by releasing locks on non-updated resources at the end of the active phase, before the transaction is saved on disk.
To obey the two-phase lock protocol for distributed transactions, an RM participant must hold all locks until the start of phase 1. In other words, it must wait for the other participants to complete their active phases of the transaction.
(This is not an absolute requirement by DECdtm. Some RMs allow an
application to request reduced isolation between transactions, to get
higher concurrency. But if an RM releases locks on non-updated
resources before phase 1, distributed transactions constructed with
DECdtm will not have the isolation property expected by most
If an RM detects an error during a transaction, it may return an error status to the AP and allow the AP to decide whether to abort the transaction. For some errors, the RM may decide to veto the transaction when it receives a request to prepare.
However, an RM should not call $ABORT_TRANS itself. A synchronized branch is terminated by $ABORT_TRANS and the decision to terminate the branch should be taken by the AP that started it, not by an RM that it called.
DECdtm has no control over the execution of APs. Therefore, an RM must
be prepared to receive and reject application requests for a
transaction after calling $ABORT_TRANS, and after DECdtm has signaled
the start of phase 1. Under rare conditions, an RM may be asked to vote
despite calling $ABORT_TRANS.
An RM may fail at any time, or the process or node on which it is running may fail. When the RM is restarted, it must clean up the on-disk state of any transaction that was running at the time of the failure. Typically, this is done by maintaining an RM-specific log of operations. On recovery, you should examine the log to find updates that must be undone (for transactions that are being aborted) or redone (for transactions that are being committed). The RM cannot resume normal operation until it has either reacquired locks for in-progress transactions, or completed or aborted them appropriately.
Logging is a common technique because it performs well, but other methods may be suitable for specific RMs. The key point is that the RM must store sufficient information on disk so that it can abort or complete in-progress transactions following an RM or node restart.
If the RM failed before voting, the RM can assume that the transaction is to be aborted, because the RM never voted to commit the transaction.
If the RM failed after voting, it must determine the outcome of the transaction from DECdtm. This is done using the $GETDTI system service. The RM may query the outcome of a specific transaction, using a TID stored in its own log. Alternatively, it may select all transactions using a prefix of the RM participant names.
Two features allow the RM to match its log against the DECdtm log. This is desirable because, for instance, the wrong log might be used if either log has been incorrectly restored from backup following a disk failure. Following are the two features:
Two transaction states allow the RM to take action: DTI$K_COMMITTED and DTI$K_ABORTED. The RM may specify that $GETDTI does not complete until a selected transaction has one of these two states.
Alternatively, other states may be returned if the final state of a transaction has not been resolved yet, perhaps because the DECdtm log is unavailable, or DECdtm is still waiting for votes from other RMs or TMs. This allows the RM to continue recovery for other transactions, to take locks for the outstanding unrecovered transactions, and then to resume normal operation.
When an RM has committed or aborted a transaction, it must allow DECdtm to remove the transaction from its log. This is done using the DTI$K_DELETE_RM_NAME function of $SETDTI.
DECdtm implements a presumed-abort optimization. This removes the need for DECdtm to log abort decisions. Therefore, if a query for a TID returns SS$_NOSUCHTID, or the TID is missing from the results of a wildcard query, the RM must assume that the transaction has aborted. There is no need to call $SETDTI in this case.
DECdtm writes the removal of a transaction from its log when the
transaction is committed. This means that following a system failure,
the DECdtm log may hold commit records for transactions that the RM has
forgotten. To prevent such records from eventually filling the log, the
RM must occasionally perform recovery by the wildcard scan method,
instead of querying specific transactions, and remove its association
from any committed transaction that is unknown to the RM.
An RM may be declared as volatile in $DECLARE_RM if it manages resources that do not need to survive an RM or node failure, such as the following:
Declaring an RM as volatile removes the need for DECdtm to log
information about RM participants. By definition, the RM does not need
to perform recovery after a failure, and does not call $GETDTI.
On recovery, RMs are expected to wait until each transaction state can be resolved as committed or aborted. During this time, they may be unavailable for new operations, or they may hold locks that block the normal functioning of applications.
When you use DECdtm within an OpenVMS Cluster, any node can access the DECdtm log for recovery, provided that the log is configured on a clustered disk. However, if the log is on a failed node outside the cluster, if communication to the node has failed, or if the disk holding the log has failed, applications may be blocked indefinitely.
In this scenario, you may prefer to intervene manually rather than to tolerate an unavailable system. The DTI$K_MODIFY_STATE function of $SETDTI allows you to change the state of an in-doubt transaction in a DECdtm log. The DTI$K_DELETE_TRANSACTION allows you to remove a transaction from a DECdtm log.
You can make these changes using the Log Manager Control Program (LMCP)
REPAIR command rather than calling $SETDTI directly. Intervention of
this type is for emergency use and is likely to break the consistency
of distributed resources. You may need to perform application-specific
updates to resources to restore consistency.
An AP may specify a transaction class parameter to $START_TRANS or
$ADD_BRANCH. This is passed as a string to the RM event handler. The
mechanism is provided so that an RM may monitor transaction activity
for suitably labeled transactions or branches. Its use is optional.
A Communication Resource Manager (CRM) is a special resource manager that acts as a gateway between DECdtm and another TM. Typically, the other TM would be on a system other than an OpenVMS system. You can also write a CRM to link two DECdtm systems using an otherwise unsupported communication mechanism such TCP/IP.
A CRM in a subordinate branch of a DECdtm transaction is indistinguishable from a normal RM. It responds to DECdtm events normally, except that internally it forwards the events to the remote TM instead of dealing with them directly.
A CRM may create a DECdtm subordinate branch using the $JOIN_RM service as follows:
The new TID is derived from the remote TM and must be a universal
unique identifier (UUID). If the remote TM does not use UUIDs for its
TIDs, the CRM must generate a new TID (using the $CREATE_UID service)
and maintain a mapping between remote TM TIDs and DECdtm TIDs. If
multiple branches of the same transaction are created, you must use the
same DECdtm TID on all branches. Otherwise, RMs may detect spurious
lock collisions between branches of the same transaction.
The DECdtm XA interface allows a transaction manager (TM) to coordinate transactions performed by a resource manager (RM). For an overview and documentation of the XA interface, see the X/Open CAE Specification document Distributed Transaction Processing: The XA Specification.
The DECdtm XA interface provides the following levels of support for the XA interface:
Figure 30-2 XA Veneer Example
Figure 30-4 TX Wrapper Example
For the convenience of application writers, the DECdtm XA Interface also provides an implementation of the X/Open TX (Transaction Demarcation) interface. This is a simple set of function wrappers for DECdtm system services. (See Figure 30-4.)
The following sections describe the DECdtm XA interface:
30.7.1 Using the XA Veneer
This section describes how to write an application program that uses an
XA-compliant RM in transactions coordinated by DECdtm.
Application programs can use the $START_TRANS, $END_TRANS, and $ABORT_TRANS system services to control transactions.
XA RMs can participate only in the default transaction, because the XA interface model does not allow for explicit transaction IDs passed to RMs by APs.
DECdtm does not support DECthreads or POSIX threads. That is, you can use threading within an application, but the default transaction is managed per process, not per thread.
The XA Veneer does not support the use of $SET_DEFAULT_TRANS to change the current default transaction. That is, an application program may attempt to change the current default transaction, but XA RMs will continue to perform operations in the context of the original default transaction.
The Veneer reports RM xa_start() errors on $START_TRANS by an SS$_ABORT exception. Any RM error also causes the transaction to be aborted and a reason code to be returned from $END_TRANS.
RM return codes are translated to reason codes as follows:
The XA Veneer implements the functions ax_open_decdtm() and ax_close_decdtm(). They are identical to the X/Open TX functions tx_open() and tx_close. If ax_open_decdtm() is not called, XA RMs are automatically opened at the start of the first transaction.
Application programs can use the X/Open TX functions instead of DECdtm system services. The TX functions are available in an object module that can be used with the XA Veneer. The tx_begin() function includes an exception handler that maps XA Veneer exceptions to tx_begin() return codes. While the TX wrapper module requires the XA Veneer, the TX functions apply equally to XA and DECdtm RMs.