Research

University of Newcastle

Return to Research List
Contact:
Dr. Mark Little
Arjuna Project
Distributed Systems Research
Department of Computing Science,
University of Newcastle
Tyne, UK, NE1 7RU
m.c.little@newcastle.ac.uk

Providing end-to-end transactional Web applications using the Object Transaction Service

1.     Introduction

The Web frequently suffers from failures which can affect both the performance and consistency of applications running over it. For example, if a user purchases a cookie granting access to a newspaper site, it is important that the cookie is delivered and stored if the user’s account is debited; a failure could prevent either from occurring, and leave the system in an inconsistent state. For resources such as documents, failures may simply be annoying to users; for commercial services, they can result in loss of revenue and credibility.

Atomic transactions, with their “all-or-nothing” property, are a well-known technique for guaranteeing application consistency in the presence of failures. Although Web applications exist which offer transactional guarantees to users, these guarantees only extend to resources used at Web servers, or between servers; clients (browsers) are not included, despite their role being significant in applications such as mentioned previously. Providing end-to-end transactional integrity between the browser and the application (server) is therefore important, as it will allow work involving both the browser and the server to be atomic. However, current techniques based on cgi-scripts cannot provide end-to-end guarantees [1]. As illustrated in figure 1 the user selects a URL which references a cgi-script on a Web server (message 1), which then performs the transaction and returns a response to the browser (message 2) after the transaction has completed [2]. Returning the message during the transaction is incorrect since it may not be able to commit the changes.

Figure 1: transactions through cgi-scripts

In a failure free environment, this mechanism works well. However, in the presence of failures it is possible for message 2 to be lost between the server and the browser, resulting in work at the server not being atomic with respect to any browser related work.

With the advent of Java it is possible to empower browsers so that they can fully participate within transactional applications. To be widely applicable any such transaction system must be standards compliant. The most widely accepted standard for distributed transactions is the Object Transaction Service (OTS) [3]. However, rather than require a browser to incorporate a full OTS implementation for all applications, we are interested in the case where it would be considered either undesirable or impractical, e.g., because of the overhead and security implications involved in incorporating the required CORBA services within a browser. In addition, we expect that the majority of an application’s resources, particularly in the area of electronic commerce, will continue to reside within protected domains.

2.     End-to-end transactional guarantees

Our aim was to allow the construction of transactional applications with end-to-end guarantees without requiring (substantial) support from the browser; the level of browser support will depend upon the application, but should be minimal, e.g., simply writing a cookie to the user’s disk. Figure 2 shows a lightweight transactional bank account: apart from necessary persistence mechanisms, the transaction and concurrency control services are all managed for the browser by the server; the cookie object still participates within any transactions involving the bank, and therefore the transaction manager guarantees that its state changes are transactional.

Figure 2: lightweight transactional browser

In the following sections we shall describe how we have provided this lightweight transactional mechanism using the OTS.

2.1     Browser resources

The OTS specification allows transactional objects to delegate their ACID responsibilities to recoverable objects (those which support the Resource interface defined in the CosTransactions module); through this technique it is possible to encapsulate non-transactional resources within OTS Resources, such that they assume the responsibility of ensuring the object is transactional. Therefore, the solution we chose to the problem of providing lightweight end-to-end transactional guarantees is through the use of Resource implementations which “wrap” the non-transactional browser. These Resources are registered with, and driven by, the transaction manager at the server, and work with the browser-side application to make it transactional. This allows the browser portion of the application to be extremely simple and lightweight.

Although this browser Resource will typically be specific to the application for which it was created, the functional requirements all Resources must fulfil will be the same:

·         prepare: the Resource transmits to the browser application the identity of the transaction it has been registered with, which can be used to replay the transaction in the event of a failure. If the Resource passes any results back to the browser application (e.g., a cookie) it should not use them at this stage, since the transaction has not terminated. If the browser does not respond to this message, the server-side Resource may assume it has failed and cause the transaction to abort (by returning VoteRollback from prepare.) If the transaction aborts, all of the other work performed within its scope will be undone.

·         commit: the application is guaranteed that all of the work performed within the transaction will be made durable, despite failures. Crash recovery mechanisms can be relied upon to complete partial transactions arising due to failures. Therefore, the Resource can make any “state changes” permanent, e.g., by instructing the browser to store the cookie, or display/decrypt the purchased document. If the Resource does not reply to the commit request then the transaction manager will assume it has crashed and crash recovery will complete the transaction.

·         rollback: the Resource transmits the reason for the rollback to the browser, e.g., insufficient funds within the user’s account.

This technique provides a lightweight means for Web applications to gain end-to-end transactional integrity. The transaction coordinator, and the majority of the transaction infrastructure, reside within the server, while the browser application remains relatively simple, needing only to be able to make any “changes” permanent in the case of a commit, or to undo them if the action aborts.

3.     Overview of an OTS implementation

We have designed and implemented OTSArjuna, a C++ transaction toolkit which complies with the OTS specification (including supporting subtransactions), and which provides programmers with the ability to implement Web applications with end-to-end transactional guarantees [4]. This OTS implementation is extremely portable, and runs on over 7 different ORBs. However, in the on-line example to be described later we have used Orbix 2.2MT from Iona.

Rather than require programmers to make use of the low-level OTS, concurrency control and persistence APIs, OTSArjuna provides a high-level API for building transactional applications and frameworks [5]. This API automates the activities concerned with participating within an OTS transaction, such as creating and registering appropriate Resource implementations, propagating locks etc. The architecture of the system is shown in figure 3.

Figure 3: OTSArjuna structure

The OTSArjuna model for building transactional applications exploits object-oriented techniques to present programmers with a toolkit of classes from which application classes can inherit to obtain desired properties, such as persistence and concurrency control. Each class is concerned with a single functionality, and these classes form a hierarchy, part of which is shown in figure 4. By inheriting from LockManager, user classes are automatically transactional, with LockManager and StateManager being responsible for guaranteeing the ACID properties (isolation and durability respecitvely). Apart from specifying the scopes of transactions, and setting appropriate locks within objects, the application programmer does not have any other responsibilities: the system guarantees that appropriate Resource objects are registered with transactions, and that in the event of failures crash recovery mechanisms are invoked automatically.

Figure 4: OTSArjuna class hierarchy

4.     Bank cashpoint example

To illustrate the technique of incorporating browsers into transactions, we have implemented a bank account example, which is available on-line (http://arjuna.ncl.ac.uk/). Consider the case of an on-line bank which allows users to inspect, remove, and insert money from their accounts; the bank runs on an ORB which resides on a Web server. When money is removed it is converted into digital cash tokens which are stored and manipulated by the browser, and contain the token’s current “cash” balance; we shall assume that these tokens can be presented to other Web-commerce applications as payment for services. Insertion of money to an account is simply the reverse, whereby a token is consumed, and the user’s account is credited by the amount left within the token. The bank requires to make the delivery of the cash token to the user’s browser and the debiting of the user’s account atomic. Failures must not result in inconsistencies at the browser or the bank.

Figure 5 shows the browser portion of the application, consisting of a Java applet which displays a graphical representation of the bank; user accounts are accessed via a PIN. To guarantee consistency in the presence of failures, each operation is performed within the scope of a transaction; the transaction manager runs at the bank’s Web server. Although the operation to inspect an account is transactional, it only reads the state of the account and therefore there is no actual requirement for end-to-end transactional integrity: if a failure occurs, the user can simply re-issue the request. However, both withdrawing and inserting money require stronger transactional guarantees: each operation must atomically modify the account and either deposit or consume a digital cash token to/from the browser.

During the prepare phase of each transaction the applet will display the unique transaction identifier for the operation. During the commit phase, the bank server will return the digital cash token to the browser and the applet can then use this to animate (e.g., money appears to be dispensed). In a real system the token would need to be stored by the browser. If the transaction aborts, an error message will be displayed giving the reason, e.g., insufficient funds.


 

Figure 5: Bank applet.


4.1     Server application classes

To enable the bank to service multiple clients concurrently, each account is a separate transactional object, responsible for its own persistence and concurrency control. Therefore, concurrent modifications to different bank accounts will not interfere. Using OTSArjuna, each bank account is an instance of the Account class, which is derived from LockManager:

enum Outcome { DONE, NOTDONE, INSUFFICIENT_FUNDS, ACCOUNT_ERROR, LOCKED };   

class Account : public LockManager
{
public:
  Account ();
  virtual ~Account ();

  void insert (int amount);
  void withdraw (int amount);
  void inspect (int& amount);

private:
  int amount;
};

We shall first show the implementation of the withdraw method without browser participation. We will then describe the necessary browser Resource for end-to-end transactional guarantees, and return to the withdraw operation to show how it requires modification in order to incorporate this Resource. The withdraw method first starts a new transaction and then attempts to obtain a lock on the account object (by calling the setlock method of the LockManager class). Because the withdraw operation will modify the state of the account, it tries to obtain an exclusive (write) lock. If the operation is performed successfully (e.g., there is sufficient funds in the account), the transaction is committed, otherwise it is rolled back. (Note: for simplicity the code fragments shown do not perform all necessary error checking.)

void Account::withdraw (int money)
{
    Outcome result = NOTDONE;

    OTS::get_current().begin();
  
    if (setlock(new Lock(WRITE)) == GRANTED)
    {
      /*
       * Check whether the user has sufficient
       * money to withdraw.
       */

      if (amount >= money)
      {
         amount = amount - money;
         result = DONE;
      }
      else
        result = INSUFFICIENT_FUNDS;
    }
    else
       result = LOCKED;

    if (result == DONE)
    {
       OTS::get_current().commit(TRUE);
    }
    else
       OTS::get_current().rollback();
}

In order to involve the browser such that it can receive the cookie when the user’s account is finally debited, we need to create an instance of a specific Resource which will encapsulate the browser for the duration of the transaction. The signature of the BrowserResource is shown below.

class BrowserResource : public CosTransactions::ResourceBOAImpl
{
public:
  BrowserResource (CosTransactions::otid_t tran, int outcome, CashToken& amount);
  virtual ~BrowserResource ();

  CosTransactions::Vote prepare  ();
  void rollback ();
  void commit ();
  void forget ();
  void commit_one_phase ();

private:
  Boolean saveState ();
  Boolean restoreState ();
  void removeState ();

  int opOutcome;
  CashToken cashAmount;
  CosTransactions::otid_t tid;
  Browser applet;  // our handle on the browser side of the application.
};

When created, each BrowserResource is given the identity of the transaction it has been registered with, so that it can transmit it to the browser during the prepare phase; this can be used in the event of a failure. The Resource also receives the outcome of the operation and the cash token to send back to the browser. The browser applet is represented to the resource by an instance of the Browser class; this is simply a traditional client proxy for a corresponding object within the browser.

To make the browser transactional, the BrowserResource must keep a durable record of its progress; this may then be used by crash recovery in the event of a failure. For example, consider the implementation of the prepare method:

CosTransactions::Vote BrowserResource::prepare  ()
{
  if (!saveState())
    return CosTransactions::VoteRollback;

  // invoke operation on browser

  if (applet->prepare(tid))
    return CosTransactions::VoteCommit;
  else
  {
    // Failure - discard Resource’s state

    removeState();
    return CosTransactions::VoteRollback;
  }
}

Before the BrowserResource sends the transaction’s identity it calls saveState which will permanent sufficient information to allow its role in the transaction to be replayed in the event of a failure. If saveState fails, the transaction must abort. If the subsequent invocation on the browser proxy fails, the resource assumes that the browser has failed, removes any state it previously saved, and forces the transaction to rollback. If no errors occur during prepare, the resource informs the transaction coordinator that it is ready to commit. During the commit phase, the Resource sends the token to the browser and awaits an acknowledgement. If no acknowledgement is received, the Resource relies upon crash recovery mechanisms to complete its work.

void BrowserResource::commit ()
{
  // browser acknowledged receipt

  if (applet->commit(cashAmount))
  {
    removeState();
  }
  else
  {
    // Some failure has occurred (browser, network).
    // Crash recovery will have to deal with this.
  }
}

In the event of a rollback the resource will send an error message to the browser indicating the reason for the failure.

void BrowserResource::rollback ()
{
    removeState();

    /*
     * Send reason for failure. If this fails, the
     * browser will try again later, and be told
     * the transaction rolled back.
     */

    applet->rollback(reason);
}

If a failure occurs during the transaction, the user can re-issue the request by supplying the transaction identifier. The crash recovery mechanisms at the server will determine the transaction outcome and complete the work. If no record of the transaction can be found it can be assumed that the transaction aborted.

Having considered the implementation of the BrowserResource, we can return to the withdraw operation. We wish to incorporate the browser within the transaction before it terminates, such that the browser will be informed of the outcome regardless of whether the transaction subsequently commits or rolls back. Therefore, after performing withdrawal we obtain a reference to the current transaction’s Coordinator, and register a new instance of the BrowserResource with it. The transaction then either commits or aborts, depending upon whether the withdrawal was successful, and drives the BrowserResource to either deliver a token or an error message, respectively. If a failure occurs, the user’s account will not be debited and neither will the browser obtain a cash token.

void Account::withdraw (int money)
{
  Outcome result = NOTDONE;

  OTS::get_current().begin();
  
  if (setlock(new Lock(WRITE), 0) == GRANTED)
  {
    if (amount >= money)
    {
      amount = amount - money;
      result = DONE;
    }
    else
      result = INSUFFICIENT_FUNDS;
  }
  else
    result = LOCKED;

  /*
   * Now involve the browser within the transaction.
   */

  Control_ptr cont =
                   OTS::get_current().get_control();
  Coordinator_ptr coord = cont->get_coordinator();
  BrowserResource res =
             new BrowserResource(OTS::get_current(),
                                 result, money);

  coord->register_resource(res);

  if (result == DONE)
  {
    // automatically aborts if it cannot commit

    OTS::get_current().commit(TRUE);
  }
  else
  {
    // undo all work performed

    OTS::get_current().rollback();
  }
}

As can be seen by comparing the new withdraw with the old, the changes (shown in italics) to an application necessary to incorporate a non-transactional browser into its operations are minimal. Therefore, this technique also offers possibilities for integrating Web browsers within existing legacy applications. Changes to the other operations to make them transactional with respect to the browser are similar.

Acknowledgements

The work reported here has been supported in part by a grant from UK Engineering and Physical Sciences Research Council (grant no. GR/L 73708).

References

[1]        T. Sanfilippo and D. Weisman, “Applications of the Secure Web Technology in Transaction Processing Systems”, The Open Group Research Institute, November 1996.

[2]        “Transarc DE-Light Web Client Technical Description”, Transarc Corporation, February 1996.

[3]        “CORBAservices: Common Object Services Specification”, OMG Document Number 95-3-31, March 1995.

[4]        M. C. Little and S. K. Shrivastava, “Java Transactions for the Internet”, Proceedings of the 4th Usenix Conference on Object-Oriented Technologies and Systems, Santa Fe, New Mexico, April 1998.

[5]        M. C. Little and S. K. Shrivastava, “Distributed Transactions in Java”, Proceedings of the 7th International Workshop on High Performance Transaction Systems, September 1997, pp. 151-155.