Monday, July 31, 2006

OMG Object Transaction Service

Transactions Series Part 4

This specification is based on Distributed Transaction Processing: The XA Specification, X/Open Document C193 (http://www.opengroup.org/onlinepubs/9698909699/toc.pdf). The difference ofcourse being that the interface is object oriented and IDL based.

Architecture

At the heart of this specification is the concept of a transactional object which is any CORBA object whose behavior guarentees ACID properties. In simpler words, its changes can be recovered and rolled back. The key players in this technology are -

  • Transaction client - A CORBA client which initiates a transaction and makes use of or calls on Transactional objects
  • Transactional Object - A CORBA object whose changes can be recovered and rolled back.
  • Recoverable Object - A transactional CORBA object which hosts data and can take participate in transaction protocols such as 2PC
Application Programming Model

Application programming using OTS interfaces depends on -

  • Context Management
  • Context Propagation
Context Management

Two kinds of context management is possible using OTS interfaces -

  • Direct Context Management - Context is managed using explicity OTS interfaces such as Control object.
  • Indirect Context Management - Thread specific Current interface is used for context maangement
Context Propagation

Propagation is the mechanism of associating the client's transaction context with the target object on which invocation is to be made. This could be -

  • Implicit - context is transparently propagated to the target object
  • Explicit - context is explicitly propagated to the target object using explicit parameters in the method call and using OTS interfaces.
Thus, using Direct and Indirect Context management and Implicit and Explicit Propagation fours styles of programming models is possible.

Checked Transactions

The value of checked transactions is to maintain the transactional integrity. The bottomline of checked transactions is that commit will not succeed unless all transactional objects involved in the transaction have completed the processing of their transactional requests.

There are apparently many ways of achieving this, but one commonly used mechanism is as illustrated by X/Open Checked Transactions.

X/Open Checked Transaction

A prime requirement in this pattern is that the application programming model has to be Implicit Transaction Context propagation. When implicit propagation is used, the objects involved in a transaction at any given time may be represented as a tree, the request tree for the transaction. The beginner of the transaction is the root of the tree. Requests add nodes to the tree, replies remove the replying node from the tree.

Synchronous requests, automatically ensures that the tree collapses to a single point before commit is issued. In addition, transaction manager applies resume check to ensure that the transaction is only resumed by application programs in the correct part of the request tree. I think because of resume checking, an invocation in a correct request path cannot create another thread, and then expect the created thread to resume the transaction, even though it would want to wait for the sub thread to complete its operation.

If a transaction uses explicit propagation, the Transaction Service cannot know which objects are or will be involved in the transaction; that is, a request tree cannot be constructed or assured. Therefore, the use of explicit propagation is not permitted by a Transaction Service implementation that enforces X/Open-style checked behavior.

With deferred synchronous calls, certain other conditions need to be checked. These are -
  • Reply Check - Before allowing an object to reply to a transactional request, a check is made to ensure that the object has received replies to all its deferred synchronous requests that propagated the transaction in the original request. If this condition is not met, an exception is raised and the transaction is marked as rollback-only, that is, it cannot be successfully committed. A Transaction Service may check that a reply is issued within the context of the transaction associated with the request
  • Commit Check - Before allowing commit to proceed, a check is made to ensure that (1) The commit request for the transaction is being issued from the same execution environment that created the transaction. (2) The client issuing commit has received replies to all the deferred synchronous requests it made that caused the propagation of the transaction
  • Resume Check - Before allowing a client or object to associate a transaction context with its thread of control, a check is made to ensure that this transaction context was previously associated with the execution environment of the thread. This would be true if the thread either created the transaction or received it in a transactional operation
Typical Use Case

A typical use case will consist of a Transaction originator which is responsible for starting the transaction. Typically, the model chosen will be Indirect Context Management with Implicit propagation. This model will consist of the the transaction originator using the TransactionCurrent object to initiate the transaction by calling begin() operation. This will associate the current thread with a new transaction context.

The transaction originator will then call methods of a Transactional object. Because the model chosen is implict transaction context propagation, the context is automatically sent over the wire to the transactional object. The transactional object can access the transaction context by using the TransactionCurrent object. To preserve the transactional integrity, it may not actually do much with the transaction, but to suggest rolling back. If it tries to do anything else, the checked transaction behavior may be compromised. The transactional object itself may not have reliable and recoverable data store. If it did, then it would also be a recoverable object. Typically, such objects may call on external recoverable objects most likely which would be database objects. Databases can be integrated into the OTS model by adapting a resource object to participate in the OTS transaction and perform the XA operations on its behalf. A transactional object could call on many such recoverable objects.

The recoverable objects are responsible for maintaining the data by making sure that the data change is isolated and durable. The recoverable object participates in the transaction by registering a Resource object with the transaction. The recoverable object could call get_control() operation on the Transaction Current object to get access to the Control object for the transaction. Using this Control object it could further access the Coordinator object by using the get_coordinator() operation on the Control object. Using the Coordinator object, it can then register the Resource object. Please note that the recoverable object may recieve multiple invocations as part of a transaction. So, typically a new resource is NOT registered each time. has_transactioin() and is_same_transaction() operations can be used on the Control object to verify if it is the same transaction or a different transaction.

The resource object would then participate later in transaction completion. If there are multiple resource objects registered, then a 2-phase completion would be enacted otherwise one phase completion would do.

A transaction object could also register a Synchronization object with the transaction to get notifications before and after transaction completions.

Once the transaction is completed, the transaction originator commits or rolls back the transaction. At this stage by passing in true for the report_heuristics flag into commit, the originator can wait for the result of the transaction completion. If the flag is set to false, commit() returns immediately after the coordinator has made decision to commit or rollback. It does not wait for the 2-PC to complete.

Creating a Transactional CORBA object

With the original OMG OTS (1.0 and 1.1) specification, for making an an object transactional, its interface was required to inherit from the marker interface TransactionalObject. However, this scheme of things did not quite work out well, as the CORBA object's transactional behavior was hard-coded right at the design time. Another issue with this approach was that the specification provided a weak transactional semantics for the transactional object. There was no way to specify that the client always required to have a transactional context.

Another issue with this approach was that it always had the concept of the "shared transaction". Before the introduction of AMI - asynchronous messaging interface, the transaction model was end-to-end shared by the client and the server, as it was a single request. However, with the introduction of AMI, this model did not suffice as a request between a client and a server is split into multiple requests between the client, its intermediary routers and the server. This needed a new notion of unshared transactional model by which multiple shared transactions are used each completing before the next begins.

To support these requirements, OMG uses the POA policies to describe the transactional behavior.

OTSPolicy

This POA policy specifies the explicit transactional behavior. It can have three values
  • REQUIRES - The behavior of the target object depends on the existence of a current transaction. If the invocation does not have a current transaction, a TRANSACTION_REQUIRED exception will be raised.
  • FORBIDS - The behavior of the target object depends on the absence of a current transaction. If the invocation does have a current transaction, an INVALID_TRANSACTION exception will be raised.
  • ADAPTS - The behavior of the target object will be adjusted to take advantage of a current transaction, if one exists. If not, it will exhibit a different behavior (i.e., the target object is sensitive to the presence or absence of a current transaction).
InvocationPolicy

This supports the specification of whether shared or unshared model of transaction is needed. With the introduction of AMI, the old shared model will not work any more. So, depending on the kind of client, either shared or unshared needs to be chosen. The values of this policy are -
  • SHARED - All invocations which do not involve a routing element (i.e., the client ORB directly invokes the target object with no intermediate routers). This includes:(1) synchronous stub based invocations, (2) synchronous or deferred synchronous invocations using Dynamic Invocation Interface (DII)
  • UNSHARED - All invocations that involve a routing element. This includes Asynchronous Method Invocations (AMI) with an effective RoutingPolicy of ROUTE_FORWARD or ROUTE_STORE_AND_FORWARD.
s
Transaction Completion

Following are the steps that occur during transaction completion.
  • Before starting the completion, call before_completion on all the synchronization objects.
  • If all before_completion return successfully, then call prepare on each registered resource object.
  • If all resource prepare return VOTE_READONLY, then the transaction is considered completed and after_completion is called on each of the synchronization object and if client had asked for heuristics outcome, it is returned back.
  • If all resouce prepare return either VOTE_READONLY or VOTE_COMMIT, the transaction outcome is considered committed and commit is called on each resource that returned VOTE_COMMIT. After this, after_completion is called on each of the synchronization object and if the client had asked for heuristics outcome, it is returned back.
  • If any resource prepare returns VOTE_ROLLBACK, the transaction is considered rolledback and rollback is called on each of the previous resources which had returned VOTE_COMMIT. after_completion is then called on all the synchronization objects and the heuristics outcome is returned back to the client if asked for.
s

Friday, July 14, 2006

Distributed Transactions Standards

Transactions Series Part 2

Some of the currently available standards are

  • X/Open Distributed Transaction Processing Model
  • OMG Object Transaction Service
  • J2EE JTA and JTS
  • Microsoft Transaction Server
X/Open Distributed Transaction Processing Model

The X/Open Distributed Transaction Processing (DTP) model is a distributed transaction processing model proposed by the Open Group, a vendor consortium. This model is a standard among most of the commercial vendors in transaction processing and database domains.

This model consists of four components -


  • Application Programs to implement transactional operations.
  • Resource Managers as discussed above.
  • Transaction Managers as discussed above.
  • Communication Resource Manager to facilitate interoperability between different transaction managers in different transaction processing domains.
This model has the following set of Interface APIs -

  • TX Interface - This is an interface between the application program and the transaction manager, and is implemented by the transaction manager. This interface provides transaction demarcation services, by allowing the application programs to bound transactional operations within global transaction
  • XA Interface - This is a bidirectional interface between resource managers and transaction managers. This interface specifies two sets of functions. The first set, called as xa_*() functions are implemented by resource managers for use by the transaction manager. The second set of functions, called as ax_*() functions, are implemented by the transaction manager for use by resource managers
  • XA+ Interface - This interface is used to support global transactions across different transaction manager domains via communication resource managers
  • TXRPC Interface - This interface provides portability for communication between application programs within a global transaction
  • CRM-OSI TP - An interface between a communication resource manager and the OSI transaction processing services
Some of the well known vendors compliant to this specification are IBM-Encina and BEA-Tuxedo

X/Open DTP components and Global Transaction

Though we previously identified four components, in principle, there are three components -
  • AP - Application program
  • RM - Resource Manager
  • TM - Transaction Monotor
Application program is the actual application which is needing a distributed transaction. It needs to do a "unit of work" accessing distributed multiple shared resources each of which could do smaller atomic parts of the larger unit of work. In this context, the application program starts doing the "unit of work" which is referred to as the "Global Transaction" and to delineate this global transaction, from other work that it might be doing, informs the transaction monitor of the start of the global transaction and thus specifying the boundaries of the transaction.

Transaction Monitor's responsibility is to manage this global transaction in terms of its atomicity, isolation and durability. It does this by marking the global transaction with each of the participating resource managers using what is referred to as transaction branches which is identified by XID. Later, when the global transaction is completed, the transaction monitor also initiates competion and in case of any failures, initiates recovery.

The resource manager provides access to resources on which the application program performs work. The resource manager in this context does work for the application program and also works with the transaction monitor in completion of the global transaction. To identify multiple work that it may be doing for application programs and to keep it separate, it makes use of the "transaction context".

So, the idea here is that an application program needs to do work, which is constituted of multiple smaller pieces of work which are done by/on distributed shared resources on distributed resource managers. This piece of work is referred to as Global Transaction. For this global transaction to have the ACID properties, it is clear that no one resource manager can do the job, as there will be synchronization needed between the various resource managers. This is where the transaction monitor comes in. Transaction monitor now gives a definition to the global transaction when the application program initiates it on the transaction monitor, then keeps each of the resource manager in the transaction context when the application program is actually doing work thereby trying to achieve the necessary isolation, and finally when the application program specifies the completion of the work, it coordinates in ensuring that each
each of the individual pieces of work is durably and atomically made permanant by initiating the 2-phase commit and on successful preparation, taking care of any recovery if a failure occurs afterwards.

Transaction Branch and Thread of Control

Transaction branch is actually an atomic part of the global transaction that is being done by a resource manager. Each transaction branch is identified by an XID which is nothing but a structure which contains (1) format id (2) global transaction id length, (3) branch qualifier length and (4) actual data ID data.

Before the application program does any work on a resource, the transaction monitor will need to tell the resource manager that such a work is going to start, which it does by calling xa_start() API. This API feeds the resource manager with the XID which is unique to the transaction manager for all the transaction branches it is controlling. Once the XID is fed into the resource manager, the transaction monitor can in effect forget about the XID as its job is done. Typically, at this stage what happens is that the xa_start() implementation of the resource manager [which is linked into the application program] will make note of the XID in probably a thread local storage area and initializes its transaction context. There after, when work is being done by the application program on the resource manager, each time, the transaction context is sent across to the resource manager which then takes ownership of providing the necessary isolation for the transaction branch in the resouce manager.

So, the concept of thread of control is central to this whole architecture.

Please note that every thread of control which might want to act on the resource manager, will have to first own a XA connection to the resource manager. This connection is thread specific and cannot be shared between threads. Typically, this is done with a call to xa_open() and generally can happen at application start. When the application is done with all resource manager access, it can close this connection by calling xa_close().

When an application starts the transaction by calling tx_open(), transaction monitor will have to some how know which resource managers are going to be accessed by the application program. So, probably in the call to tx_open(), it might know which resource is being accessed and start the transaction branch with the resourc manager by calling xa_start(). At this point, the XID is sent to the resource manager, and it probably records the transaction context (which includes the XID) in the thread local storage of the thread of control. At this point, we say that the thread is associated with the transaction branch. A thread can have only a single association with a transaction branch. However, it may be associated with other transaction branches, which could be part of the same global transaction, but on other resource managers. Now, after this step, when the application program tries to make invocation on the resource manager to do work, the transaction context is implicitly propagated to the resource manager and hence it knows that the current work being performed is part of a specific transaction.

Another thread of control may also want to join this specific transaction branch by calling xa_start() again using a specific flag and the same XID. In this case, the second thread may wait till the first thread's association completes.

A thread of control may want to suspend its association with a transaction. It can then call xa_end() with a specific flag which will keep the association of the tranaction in a suspended state with respect to this specific thread. The thread may later resume the transaction context by calling xa_start() with a specific flag.

Once the thread of control is done with its work on the transaction branch, it can call xa_end() which will then terminate its association with the transaction branch. Please note that if it so needs it can later join the transaction branch again.

For a transaction branch to be completed, all threads of control should have broken their association with the branch. Only after this, can prepare be called.

Tightly and loosely coupled Threads of Control

This is also called Tightly and Loosely coupled Transaction Branches

When a multiple threads of control want to join the same transaction branch, the threads are said to be tightly coupled. The way this can happen is if all these threads use the same XID when calling xa_start(). In this scenario, the RM guarentees that from the perspective of isolation, it will see all these tightly coupled threads as the same entity. This means that half baked changes of one thread will be seen by the other. Also, the RM will need to guarentee that the threads will not deadlock on any resources in the branch. Typically, in this scenario what happens is that when a thread of control is having an active association, then when another thread tries to join, the second thread will have to wait till the first thread disassociates from the transaction branch.

Now, on the other hand, if the second thread used a different XID, it is actually starting up a new branch in the RM, but still part of the same global transaction. From the perspective of RM, the two branches are isolated from each other. This is called Loosely coupled threads of control.

From the perspective of concurrency, loosely coupled threads of control are more concurrent that the tightly coupled ones.

Dynamic Registration of Resource Managers

We have seen in the previous cases that a transaction branch gets created when xa_start() is called by the transaction monitor on the resource manager and typically, the transaction monitor does this for all RMs. Even if an RM is not involved in a branch, it gets registered. To avoud this overhead, resourc managers can register themselves with transaction monitors for completion only when the application actually accesses them. This is done using the ax_reg(). The only point to be noted here is that the resource manager needs to call ax_reg() from the application program's thread of control.

Also note that the transaction monitor will call xa_start() in the normal case only if the resource manager does not support automatic registration.
TX Interface
  • tx_open - Opens the transaction manager and the set of associated resource managers
  • tx_close - Closes the transaction manager and the set of associated resource managers
  • tx_begin - Begins a new transaction
  • tx_rollback - Rolls back the transaction
  • tx_commit - Commits the transaction
  • tx_set_commit_return - Commits the transaction
  • tx_set_transaction_control - Switches between chained and unchained mode. In the case of chained transactions, the work is broken into pieces with each piece being under control of a flat transaction. Once a piece of work is complete it is committed or rolled back independent of the state of the other pieces
  • tx_set_transaction_timeout - Sets a transaction timeout interval
  • tx_info - Returns transaction information such as its identifier, state of the transaction etc
XA Interface

  • xa_start - Directs a resource manager to associate the subsequent requests by application programs to a transaction identified by the supplied identifier
  • xa_end - Ends the association of a resource manager with the transaction
  • xa_prepare - Prepares the resource manager for the commit operation. Issued by the transaction manager in the first phase of the two-phase commit operation
  • xa_commit - Commits the transactional operations. Issued by the transaction manager in the second phase of the two-phase commit operation
  • xa_recover - Retrieves a list of prepared and heuristically committed or heuristically rolled back transactions
  • xa_forget - Forgets the heuristic transaction associated with the given transaction identifier

  • ax_reg - Dynamically enlists with the transaction manager
  • ax_unreg - Dynamically delists from the transaction manager

OMG Object Transaction Service

Object Transaction Service (OTS) is a distributed transaction processing service specified by the OMG. This specification extends CORBA model model and defines a set of interfaces to perform transaction processing across multiple CORBA objects.

The OTS model is based on the X/Open DTP model with the following enhancements -

  • The OTS model replaces the functional XA and TX interfaces with CORBA IDL interfaces.
  • The various objects in this model communicate via CORBA method calls over IIOP.
Interfaces

  • Current - Responsibilities include Transaction demarcation (begin, commit, rollback, rollback_only, set_time_out) , Status of the transaction (get_status), Name of the transaction (get_transaction_name), Transaction context (get_control)
  • TransactionFactory - Explicit transaction creation
  • Control - Explicit transaction context management
  • Terminator - Commit or rollback a transaction
  • Coordinator - Status of the transaction (get_status, get_parent_status, get_top_level_status) , Transaction information (is_same_transaction, is_related_transaction, is_ancestor_transaction, is_descendant_transaction, is_top_level_transaction, hash_transaciton, hash_top_level_transaction, get_transaction_name, get_txcontext), Resource enlistment (register_resource, register_subtrans_aware) , Registration of synchronization objects (register_synchronization) , Set the transaction for rollback (rollback_only)
  • RecoveryCoordinator - Coordinate recovery in case of failure (replay_completion)
  • Resource - Participation in two-phase commit and recovery protocol (prepare, rollback, commit, commit_one_phase, forget)
  • Synchronization - Application synchronization before beginning and after completion of two-phase commit (before_completion, after_completion)
  • TransactionalObject - A marker interface to be implemented by all transactional objects

s

Distributed Transactions

Transactions Series Part 2

A great article - http://www.subbu.org/articles/transactions/NutsAndBoltsOfTP.html

Distributed Transactions

In the previous part, we saw the properties of a transaction. When an application is dealing with a single database, the features are the responsibility of the database provider.

However, in the case of a network scenario, where the application could be composed of multiple distributed components and a unit of work dealing with mulitple components dealing with multiple data sources, the notion of a transaction gets complicated. In such cases, it may be required that a group of operations on (distributed) resources be treated as one unit of work. Such applications should maintain integrity of data (as defined by the business rules of the application) under the following circumstances
  • distributed access to a single resource of data
  • access to distributed resources from a single application component
The responsibility of maintenance of the state of the operation regarding whether the operation is successful or is a failure falls on the application. Such systems can then be easily realised by a transaction manager where the application talks to the transaction manager to start, commit and rollback an operation. The transaction manager itself deals with the multiple resource managers (each database could be a resource manager) managing multiple resources and driving a protocol to commit or rollback for the Atomicity feature and also a recovery protocol for the durability feature.

Distriuted Transaction Processing Architecture

It has the following components -
  • Application Components - Application components are clients for the transactional resources. These are the programs with which the application developer implements business transactions.
    With the help of the transaction manager, these components create global transactions, propagate the transaction context if necessary, and operate on the transactional resources with in the scope of these transactions. These components are not responsible for implementing semantics for preserving ACID properties of transactions. However, as part of the application logic, these components generally make a decision whether to commit or rollback transactions. It has the following responsibilities - (1) Create and demarcate transactions (2) Propagate transaction context (3) Operate on data via resource managers
  • Resource Manager - resource manager is a component that manages persistent and stable data storage system, and participates in the two phase commit and recovery protocols with the transaction manager.
    A resource manager is typically a driver or a wrapper over a stable storage system, with interfaces for operating on the data (for the application components), and for participating in two phase commit and recovery protocols coordinated by a transaction manager. This component may also, directly or indirectly, register resources with the transaction manager so that the transaction manager can keep track of all the resources participating in a transaction. This process is called as resource enlistment. For implementing the two-phase commit and recovery protocols, the resource manager should implement supplementary mechanisms using which recovery is possible.
    Resource managers provide two sets of interfaces: one set for the application components to get connections and perform operations on the data, and the other set for the transaction manager to participate in the two-phase commit and recovery protocol. It has the following responsibilities - (1) Enlist resources with the transaction manager (2) Participate in two-phase commit protocol and recovery protocol.
  • Transaction Manager - The transaction manager is the core component of a transaction processing environment. Its primary responsibilities are to create transactions when requested by application components, allow resource enlistment and delistment, and to conduct the two-phase commit or recovery protocol with the resource managers.
    A typical transactional application begins a transaction by issuing a request to a transaction manager to initiate a transaction. In response, the transaction manager starts a transaction and associates it with the calling thread. The transaction manager also establishes a transaction context. All application components and/or threads participating in the transaction share the transaction context. The thread that initially issued the request for beginning the transaction, or, if the transaction manager allows, any other thread may eventually terminate the transaction by issuing a commit or rollback request.
    Before a transaction is terminated, any number of components and/or threads may perform transactional operations on any number of transactional resources known to the transaction manager. If allowed by the transaction manager, a transaction may be suspended or resumed before finally completing the transaction.
    Once the application issues the commit request, the transaction manager prepares all the resources for a commit operation (by conducting a voting), and based on whether all resources are ready for a commit or not, issues a commit or rollback request to all the resources. It has the following responsibilities - (1) Establish and maintain transaction context (2) Maintain association between a transaction and the participating resources (3) Initiate and conduct two-phase commit and recovery protocol with the resource managers (4) Make synchronization calls to the application components before beginning and after end of two-phase commit and recovery process
Transaction Processing Concepts
  • Transaction Demarcation - A transaction can be specified by what is known as transaction demarcation. Transaction demarcation enables work done by distributed components to be bound by a global transaction. It is a way of marking groups of operations to constitute a transaction.
    The most common approach to demarcation is to mark the thread executing the operations for transaction processing. This is called as programmatic demarcation. The transaction so established can be suspended by unmarking the thread, and be resumed later by explicitly propagating the transaction context from the point of suspension to the point of resumption.
    The transaction demarcation ends after a commit or a rollback request to the transaction manager. The commit request directs all the participating resources managers to record the effects of the operations of the transaction permanently. The rollback request makes the resource managers undo the effects of all operations on the transaction.
    An alternative to programmatic demarcation is declarative demarcation. Component based transaction processing systems such as Microsoft Transaction Server, and application servers based on the Enterprise Java Beans specification support declarative demarcation. In this technique, components are marked as transactional at the deployment time. This has two implications. Firstly, the responsibility of demarcation is shifted from the application to the container hosting the component. For this reason, this technique is also called as container managed demarcation. Secondly, the demarcation is postponed from application build time (static) to the component deployment time (dynamic).
  • Transaction Context and Propagation - Since multiple application components and resources participate in a transaction, it is necessary for the transaction manager to establish and maintain the state of the transaction as it occurs. This is usually done in the form of transaction context.
    Transaction context is an association between the transactional operations on the resources, and the components invoking the operations. During the course of a transaction, all the threads participating in the transaction share the transaction context. Thus the transaction context logically envelops all the operations performed on transactional resources during a transaction. The transaction context is usually maintained transparently by the underlying transaction manager.
  • Resource Enlistment- Resource enlistment is the process by which resource managers inform the transaction manager of their participation in a transaction. This process enables the transaction manager to keep track of all the resources participating in a transaction. The transaction manager uses this information to coordinate transactional work performed by the resource managers and to drive two-phase commit and recovery protocol.
    At the end of a transaction (after a commit or rollback) the transaction manager delists the resources. Thereafter, association between the transaction and the resources does not hold.
  • Two-Phase Commit - This protocol between the transaction manager and all the resources enlisted for a transaction ensures that either all the resource managers commit the transaction or they all abort. In this protocol, when the application requests for committing the transaction, the transaction manager issues a prepare request to all the resource managers involved. Each of these resources may in turn send a reply indicating whether it is ready for commit or not. Only when all the resource managers are ready for a commit, does the transaction manager issue a commit request to all the resource managers. Otherwise, the transaction manager issues a rollback request and the transaction will be rolled back.
s

Thursday, July 13, 2006

Transactions Basics

Transactions Series Part 1

Transaction

It is a single logical operation on data.

ACID properties of Transaction

Atomic

The entire operation on the data should happen in its entirety, or should not happen at all. A transaction could involve multiple steps and for the transaction to complete, either all the steps should complete successfully or none at all. Any failure should abort the entire transaction.

Consistency

Data has data integrity or legal values which it can have. This data integrity should not be compromized by the transactions. For example, an account cannot have negative balance.

Isolation

The property which makes changes made by an operation local to it and not make other operations on system see it until its completion.

There are typically two ways of achieving isolation
  • Lock based concurrency control
  • Multiversion concurrency control
In the lock based concurrency model, typically objects are locked, so that another transaction will have to wait till the lock is released, which typically could be at the end of transaction.

In MVCC, multiple versions of the object are created for each transaction. For example, consider an object P, then this object has a read time called P-RT. Now, when a transaction Ti reads this object, a version of object P is created for the transaction and a time stamp for the transaction - Ti-TS is noted. Now, if the transaction Ti wants to write back any changes to P, then it is allowed to do only if another transaction Tj, whose time stamp Tj-TS is greater than Ti-TS and the object read time P-RT is less than Ti-TS. Otherwise the transaction is aborted and restarted.

By ANSI SQL standards, there are four levels of isolation -
  • Serializable - This is the most strict form of isolation level possible. In this mode, the system makes all the transaction run serially. In the case of lock base concurrency control, the database system seems to acquire a range lock. This level guarentees that a select query always returns the same number of records with the same values when inside a transaction. With MVCC, a snapshot isolated view is created and shared for each accessing transaction. If the transaction updates, ofcoure, there is a potential for abortion with MVCC.
  • Repeatable Read - This is the next level of isolation. With lock base concurrency control, all the data records or tuples are locked, but the range is not locked, and hence phantom reads are possible.
    Phantom Read - For example, If "select * from users where age between 10 and 30" selects 10 records, then these 10 records are locked and cannot be modified by another transaction. On the other hand, another transaction can write a new record with age 27, and if the first transaction ran the same query again, it would get another result with an extra tuple. This is because the range was locked. This is called phantom read. In this case, the system acquires a record lock on all the retrieved records but does not acquire a range lock allowing other transactions to insert records. This isolation level guarentees that a select query always returns the same value of the record.
  • Read Committed - In this case, records retrieved by a query are allowed to be modifiable by other transactions. No locks are acquired at all. This is a Non-Repeatable-Read isolation level. Meaning that the value of a record may change between multiple select statement in a transaction; only if another transaction commits.
  • Read Uncommitted - Same as Read Committed, the only difference being that a transaction can also see the dirty writes of another transaction. For example, a transaction can write data and before it can commit, the data is visible to other transactions. This is the lowest level of isolation.
Durability

This is the guarentee that once the user has committed the changes, the changes will persist and not be undone. It will survive any system failure, and that the database system has checked the integrity constraints and won't need to abort the transaction.

Atomicity and Durability are guarenteed by either of two types of strategies -
  • Write ahead logging (WAL)
  • Shadow writing.
Write ahead logging - In a system using WAL, all modifications are written to a log before they are applied to the database. Usually both redo and undo information is stored in the log. The motivation for WAL is to allow updates of the database to be done in-place.

Shadow logging - Shadow paging is a copy-on-write technique for avoiding in-place updates of pages. Instead, when a page is to be modified, a shadow page is allocated. Since the shadow page has no references (from other pages on disk), it can be modified liberally, without concern for consistency constraints, etc. When the page is ready to become durable, all pages that referred to the original are updated to refer to the new replacement page instead. Because the page is "activated" only when it is ready, it is atomic. If the referring pages must also be updated via shadow paging, this procedure may recurse many times, becoming quite costly.