In the Reflective Transaction Framework, reflection is realized through transaction adapters, which are software modules built on top of the legacy TP monitor. Each adapter corresponds to a particular aspect (functional component) of the TP monitor, such as transaction execution, lock management, conflict detection, and log management. Transaction adapters contain a number of meta objects which represent selected behaviors of the underlying functional components, and a meta interface (what some might call a programmer's interface or Meta-Object Protocol) to control the behavior of that component. This is illustrated in Figure 2. The behavior of the TP monitor functional components can be changed by explicitly updating these meta objects through the adapter meta interface, allowing users to ``reach in'' and make changes to the behavior of the TP monitor. As such, adapters provide access to aspects of a legacy TP monitor that are often hidden.
Transaction adapters are application level objects, which means applications have access to them through the meta interface. Changes or modifications made to an adapter by an application affects the behavior of the TP monitor component for only that application. For example, if an application would like to relax the isolation properties of a transaction in order to enable cooperation with another application, it can use the appropriate meta interface operations to change the conflict detection method for that transaction. Therefore, transaction adapters allow an application to enhance the underlying mechanisms of a legacy TP monitor incrementally, dynamically, and in a modular manner at the granularity of each (extended) transaction execution.
In the context of a legacy TP monitor, reflection is the ability of an executing TP monitor to make selected aspects of the underlying functional components, such as transaction operation dispatch, lock management, conflict detection and log file updates, to be themselves the subject of computation. The steps involved in this reflection consist of: reification of structures and behaviors of the underlying TP monitor component into objects that represent or model aspects of the underlying TP monitor component, reflective computation using the reified aspects as data, and reflective update that modifies the actual computational state of the underlying TP monitor component.
In the Reflective Transaction Framework, reification is the representation of structural and computational aspects of the underlying TP monitor component as an object within the corresponding transaction adapter. Reification in our framework is based on callbacks, also known as upcalls [Cla85]. Upcalls support efficient cross-layer communications and enable the functional components in the TP monitor to pass relevant state information to a transaction adapter where it is reified, as illustrated in Figure 3. The most important decisions to be made in designing a transaction adapter are what aspects of the underlying TP monitor component should be reified. As an example, for the Lock Adapter depicted in Figure 3, such aspects include the locks being held by a transaction, pending lock requests, the procedure used to grant lock requests, and the structure of the lock table. Depending on the transaction model, however, several other aspects could also be reified, for example the operations being performed on a locked data object, or the mode in which a lock has been granted to a transaction. To make adapters as flexible as possible, they are designed to be extensible. Should the need arise, additional aspects of the underlying functional component can be reified by adding appropriate upcalls to the TP monitor and associated reification methods to the transaction adapter. Reifying selected aspects of the underlying TP monitor component into metalevel objects that are dynamically accessible and modifiable enables reflective computation and reflective update.
The shift in computation from the TP monitor functional component to reflective computation in the transaction adapter occurs in an event-driven manner. A transaction significant event is raised whenever a transaction attempts to change state, e.g. the transaction aborts or commits, or when a transaction requests a service from the TP monitor. For each transaction event there is an adapter assigned to process the event, and when the event is raised, control is passed to the assigned transaction adapter along with all information relating to the event. For example, when the LOCK MANAGER detects a lock conflict between two transactions during a lock request, control is passed to the Lock Adapter through an upcall, along with all information pertaining to the conflicting request. The Lock Adapter can then apply operation or application-specific semantic information to determine if the request should be granted according to the semantics of the transaction model. The Lock Adapter can then grant the lock request, or deny it by simply returning control back to the LOCK MANAGER, effectively implementing semantics-based concurrency control [BPZH95]. As this example illustrates, reflective computation not only allows transaction adapters to expose default behaviors of the underlying TP monitor, but also augment legacy functionality with new extended transaction model behaviors.
If the reflective computation updates the reified data, then the modifications are reflected down to the actual computational state of the underlying TP monitor component in what is called a reflective update. Reflective update is implemented through calls to the API provided by each TP monitor functional component. Through the API the transaction adapter can update the structures and computational state of the underlying functional component. The most challenging issue when implementing an adapter is to identify the appropriate API calls in order to implement each reflective update. Ideally, this task is performed only once, by the designer of the Reflective Transaction Framework, who is familiar with the inner workings of the monitor functional components. When an adapter needs to perform a reflective update, it issues the appropriate sequence of API calls, as illustrated in Figure 3. Thus, each transaction adapter not only reifies aspects of the TP monitor functional component, enabling reflective computation, but also provides the means to affect the state and control the component's behavior through reflective update. This is termed causal-connection [Mae87], and is satisfied by transaction adapters in the Reflective Transaction Framework.
To design each transaction adapter, we introduced a systematic procedure to select aspects of the transaction and TP monitor for reification, determine how these aspects would be represented as metalevel objects, and establish methods to manipulate these objects through the adapter meta interface. This was an important process in the development of the framework, because it effectively determined what extended behaviors could be realized on the underlying TP monitor and, correspondingly, what extended transaction models could be implemented by the Reflective Transaction Framework. Details of this systematic procedure are not appropriate for this discussion, and can be found elsewhere [BP95]. For practicality and portability, the functional design of each transaction adapter was based on the commands and functionality of the well-documented TP monitor reference architecture [GR93]. The TP monitor reference architecture is general enough to allow us to make observations on TP monitors in general, and yet concrete enough to make implementation details obvious in a modern commercial TP monitors. Further, our implementation of the adapters relied only on a small, widely supported, set of commands found in the API of the TP monitor reference architecture.
In the remainder of this section, we will highlight some of the objects reified by transaction adapters, and describe selected commands from the adapter meta interface.
Transaction Management Adapter -- reifies transactions executing extended behaviors, and provides a meta interface to control these transactions and adjust the behavior of the underlying TRANSACTION MANAGER functional component. Commands in the Transaction Management Adapter meta interface include: Instantiate, Reflect, Delegate_Ops, Form_Dependency, Create_Group, Create_Tran, Terminate_Tran, and Wait. Primary meta objects reified by the Transaction Management Adapter include a metatransaction descriptor for each extended transaction, see Figure 4, a reflective transaction table, and a transaction dependency graph.
metatransaction Descriptor{
self: <TRID>
groupID: [<TRID>];
execMode: <state>;
dependsOn: [<TRID>, <TRID>,...];
waitOn: [<event>];
lockList: [<lockID>, <lockID>,...];
opList: [<opName>, <opName>,...];
initiateOperations: {<Begin, atomicBegin>};
processOperations: nil;
terminateOperations: {<Commit, atomicCommit>,
<Abort, atomicAbort>}};
|
An extended transaction is entered into the reflective transaction framework through the command instantiate, at which time a metatransaction descriptor is created for the transaction. All information relating to the execution and current status of the transaction will be reified in this metatransaction descriptor. Afterwards, an instantiated transaction can be assigned a set of extended control operations (semantics) through the command reflect. When an extended transaction invokes a control operation, the actual code executed is determined by its metatransaction. For example, if the transaction were to invoke the Commit operation this would result in a transaction significant event being raised and control would be passed to the Transaction Management Adapter. Processing the command involves first verifying this control operation is permitted for the transaction; a simple comparison with the metatransaction descriptor is performed. Once the Transaction Management Adapter has verified the commit operation is valid then the function identified in the metatransaction descriptor is executed. Afterwards, any results from the transaction control operation are returned to the base level transaction as if for a normal operation call.
Conflict Adapter -- reifies information on the conflicts that occur between transactions attempting to acquire shared resources, and provides a meta interface to control the definition of conflict and appropriately adjust the behavior of the underlying LOCK MANAGER. Commands in the Conflict Adapter meta interface include: Relax_Conflict, No_Conflict, Allow, Wait and Revoke. Primary meta objects reified by the Conflict Adapter include a a compatibility table defining conflict relationships between operations, and a no-conflict table that records all conflicts explicitly relaxed between extended transactions.
Depending on the semantics of a transaction and its relationship to other transactions, not all conflicts between transactions need to produce dependencies or serialization orderings. To capture this, the Conflict Adapter can selectively present and change the definition of conflict for one or more underlying data objects or extended transactions. By adapting the definition of conflict offered by the underlying TP system, the conflict adapter is able to provide support for a variety of extended transaction models and semantics-based concurrency control protocols [BPZH95].
Lock Adapter -- reifies information on locks held by transactions and on the state of the lock table, and provides a meta interface to control these locks and adjust the behavior of the underlying LOCK MANAGER functional component. Commands in the Lock Adapter meta interface include: Release_Lock, Acquire_Lock, Delegate_Lock, Share, Wait, Peak and Upgrade_Mode. Primary meta objects reified by the Lock Adapter include a transaction lock list, lock mode table, and an active locks list.
Locks on data objects can restrict the ability of a transaction to see the effects of other transactions on data objects while they are executing. The Lock Adapter allows greater control over the visibility of data objects by enabling a transaction to grant other transactions access to data objects on which they hold locks. The Lock adapter also enables an extended transaction to delegate ownership of its locks to another transaction prior to termination through the delegate_lock command. The delegate_lock command allows the transaction to specify whether it wishes to delegate all the locks it currently holds or only those for specified data objects. The conflict adapter records access rights granted between extended transactions in the no-conflict table, while the lock adapter provides the transactions access to the locked data object(s).