|
|
|
Sponsored Link •
|
|
Advertisement
|
As long as only one transaction executes on the network at any given time, you can easily provide this guarantee: All transaction steps perform consecutively, with no one else permitted to read or write the data those steps access. When one transaction completes before another begins, the transactions execute serially.
To illustrate this, imagine another transaction that uses the credit card service but is unrelated to the book purchase -- a transaction that arranges your utility bill payment using your credit card, for example. This transaction transfers money between two accounts: your credit card and the utility company's bank account. It coordinates work (the transfer) between CreditCard and a utility account service, Utility. Let's designate this transaction as TPayUtility, and denote the original book purchase transaction as TBuyBook.
Figure 2 shows the steps of these two transactions when all TBuyBook steps complete before any TPayUtility steps begin (i.e., when the two transactions execute serially).
Figure 2. Serial execution of two transactions
|
Neat as this arrangement appears, the Jini federation cannot ensure a purely serial transaction execution. Doing so requires a central controller -- a transaction scheduler -- that tracks the beginnings and ends of transactions, causing others to wait to begin until a transaction executes all its steps. In addition, forcing serial transaction execution severely limits the network's ability to execute transactions on time -- the network's transaction throughput -- as most transactions are delayed. Transactions that don't execute sequentially can easily violate the consistency of shared data. To see how this could happen, we must first change our vantage point of what occurs inside a transaction.
Thus far, we've taken a birds-eye view. We've considered the distributed transaction's actions in all the nodes (services) with which it interacts. However, in a distributed system without a central controlling entity, that is an artificial viewpoint. Any service involved in a transaction is aware only of what read and write operations occur locally, and has no way to gain a global perspective on a transaction. Therefore, we will change our observation point and look at the serial execution of two transactions as they interact with just one service, CreditCard.
Viewed inside CreditCard, TBuyBook first reads the credit card's existing balance as well as the maximum allowed balance. If the purchase falls below the maximum limit, the transaction then increments the current balance, and writes that amount back to stable storage. If the purchase of the book would push the card's balance over the credit limit, the current balance is left intact; in that case, the service returns a CreditCardException from the method call. TPayUtility works similarly: It begins by reading the account balance and maximum allowed credit limit, and determines if it can charge the utility bill on the card. If so, it increments the balance, and writes the new amount to persistent store. Figure 3 illustrates the performance of these transactions inside CreditCard.
Figure 3. Read and write steps performed in
|
While these actions occur, each transaction interacts with other services, of which CreditCard is not aware and any of which can cause the transactions to abort. For instance, after TBuyBook-related actions complete inside CreditCard, the ShippingService might cause the transaction to abort for lack of available shipping route. At that point, CreditCard must restore the old balance. Therefore, the transaction's abort will appear as a new write operation inside CreditCard.
Figure 4 shows four possible sequences of read and write operations, considering a transaction abort as a new write action. The four possible execution histories show what can go wrong when actions from concurrently executing transactions interleave.
Figure 4. Concurrently executing transactions introduce possible anomalies: lost updates, dirty reads, and unrepeatable reads. If both transactions only read the data, no anomalies occur.
|
You can easily imagine what goes wrong in H1, H2, and H3 with an example. Suppose you purchase the book for $30, and the Jini service pays the $50 utility bill. Your initial account balance is $100. Based on these initial facts, concurrently executing transactions would introduce the following anomalies:
You can avoid these anomalies, and ensure consistency, by making concurrently executing transactions appear as if they were executing serially. In other words, from the Jini federation's point of view, transactions might execute concurrently, but from a service's vantage point, transactions should appear to execute one after another, in isolation (the I in ACID). As long as each service ensures transaction isolation, concurrently executing transactions won't threaten data consistency.
|
Sponsored Links
|