Transactions for concurrent object-oriented programming systems (1988)

Concurrent object-oriented programming systems (COOPS) require support for fault tolerance, concurrency control, consistent commitment of changes and program-initiated rollback. It is sometimes suggested that the classical transaction processing model successfully applied in databases and operating systems be integrated directly into COOPS facilities. This is clearly desirable, but by itself is too limiting. COOPS applications require several granularities of transaction-like facilities. A number of transaction-like mechanisms were addressed at the workshop, and no doubt there are many others suitable for COOPS. Here I briefly survey four levels of granularity that were discussed at the workshop. In their workshop paper Linearizable Concurrent Objects and in [1], Maurice Herlihy and Jeannette Wing describe a fine granularity correctness condition for COOPS, linearizability . Linearizability requires that each operation should appear to “take effect” instantaneously and that the order of non-concurrent operations should be preserved. My workshop paper Concurrent Meld discusses the incorporation of atomic blocks as a programming facility into the Meld COOPS. Atomic blocks in effect implement linearizability at the level of blocks (essentially compound statements, which may encompass an entire method). In his workshop paper Nested Objects and in [4], Bruce Martin describes small grain mechanisms for both externally serializable and semantically verifiable operations for COOPS. Externally serializable operations enforce serializability among top-level operations but permit non-serializable computations on subobjects. Semantically verifiable operations do not enforce serializability at all, but instead consider the semantics of apparently conflicting operations in preventing inconsistencies from being introduced. My paper also discusses our plans for integrating medium granularity transactions — that is, classical transactions with atomicity and serializability as the correctness conditions — into Meld. Serializable transactions have been implemented in a separate version of Meld. not yet integrated into the main line. This implementation uses an algorithm for distributed optimistic concurrency control with multiple versions [2], but two phase locking, timestamps, etc. seem equally feasible for COOPS depending on the anticipated applications. We are currently working on large grain transaction-like facilities for COOPS. Our particular concern is an important class of COOPS applications — open-ended activities [5] such as CAD/CAM. VLSI design, medical informatics, office automation and software development — characterized by uncertain duration, uncertain developments and interaction with other concurrent activities. Classical transactions are not suitable for open-ended activities for the following reasons: Fault tolerance implies atomicity, so if there is some failure, the transaction is rolled back and retried. This is entirely inappropriate when the 'transaction' consists of fixing a bug by browsing and editing a number of source files, compiling and linking, executing test cases and generating traces, etc. , which may easily take several hours. Concurrency control requires that users are isolated, and the transactions appear to have been executed in some serial order. But it is not acceptable for a programmer to be locked out from editing a source file just because some other programmer had previously read the file but has not yet finished his changes to other files. Consistent commitment implies simultaneously making all of a transaction's updates publicly available only when the first transaction completes and commits. But programmers must release certain source files so they can be viewed and/or compiled and linked by other programmers cooperating on the same subsystem, while continuing in progress work on other files. An abort deletes all changes made during the transaction, so they are never available to other transactions. A programmer may realize that his original ideas about the cause of a program error were incorrect and decide to start over, but he may want to keep his incorrectly modified versions available for reference. Thus the traditional transaction model is not suitable for open-ended activities such as software development, at least where the 'transactions' are at the granularity of bug fixes, completion of a milestone, or release of a product. An extended transaction processing model, with supporting programming facilities, is necessary for COOPS. We have investigated an extended transaction model, commit-serializability , as a candidate for integration into Meld and other COOPS. The term commit-serializability denotes a model where all committed transactions are in fact serializable in the standard sense, but these transactions may not correspond in a simple way to those transactions that were initiated. In particular, the initiated transactions may be divided during operation and parts committed separately in such ways that these transactions are not serializable. Consider two in-progress transactions T1 and T2. T1 is divided under program or user control into T3 and T4, and shortly thereafter T3 commits while T4 continues. T2 may view the committed updates of T3, some of which were made by T1 before the division, and then itself commits. T4 may then view the committed updates of T2 before it commits. T2, T3 and T4 are serializable, but T1 and T2 are not. The originally initiated transaction T1 in effect disappears, and in particular is neither committed nor aborted. Commit-serializability is supported by two new transaction processing operations, split-transaction and join-transaction [5], in addition to the standard begin-transaction, commit-transaction and abort-transaction operations. The split-transaction operation supports the kind of division described above; the inverse join-transaction operation merges a completed transaction into an in-progress transaction to commit their results together. The two-way versions of the split and join operations take the following arguments. Either statement may be executed as the last statement of any method invoked as part of a transaction T. split-Transaction (A: (AReadSet, AWriteSet, AMessage), B: (BReadSet, BWriteSet, BMessage)) Join-Transaction (S: TID) When the split-transaction operation is invoked during a transaction T, there is a TReadSet consisting of all objects read by T but not updated and a TWriteSet consisting of all objects updated by T. In COOPS, TReadSet is the set of instance variables read by T, including the instance variables of objects (transitively) sent a message where the responding method accessed but did not modify these instance variables of that object. TWriteSet is the set of instance variables assigned by T, including the instance variables of objects (transitively) sent a message where the responding method modified these instance variables of that object. In both cases, the object whose method initiated T acts as coordinator of the cohort. TReadSet is divided, not necessarily disjointly, into AReadSet and BReadSet. TWriteSet is divided disjointly into AWriteSet and BWriteSet; AWriteSet normally must also be disjoint from BReadSet and BWriteSet from AReadSet. AMessage and BMessage are the selectors of messages sent to the same object ($self in Meld) to continue the two transactions. In the special case where A is immediately committed, AMessage is the operation commit-transaction, and objects in AWriteSet may also appear in either BReadSet or BWriteSet. When the join-transaction operation is invoked during a transaction T, target transaction S must be ongoing — and not in conflict with T. TReadSet and TWriteSet are added to SReadSet and SWriteSet, respectively, and S may continue or commit. One difficulty of join-transaction that did not arise for split-transaction is the necessity of naming another transaction S, other than the current one T. This can be done by treating each transaction as a special object, and references to such special objects can be stored in instance variabl