(Internal classification: major example)

Reference paper: “KALA: Kernel Aspect Language for Advanced Transactions” Johan Fabry, Eric Tanter, Theo D'Hondt, In Elsevier Science of Computer Programs 71(3) P 165 – 180, 2008.

Domain of the language

Advanced transaction management

Transactions are the cornerstone of concurrency management in multi-tier distributed systems. Originally designed to provide concurrency management for short and unstructured data accesses to databases, they are however now used outside of this domain. This observation is not new, and significant research has been performed to address the shortcomings of classical transactions through the use of advanced transaction models (ATMS). There are many such advanced models, each specifically tailored to address one shortcoming. To achieve this, ATMS typically relax some of the ACID properties associated with classical transactions, and add new properties to the transaction model, in a structured way. Chrysanthis and Ramamritham defined a formalism, called ACTA 1), that allows for a formal specificiation of how a given model modifies/adds these properties.

The major issue with using an ATMS in an application is how these extra properties can be specified. In other words, how programmer attaches the extra transactional properties to parts of the application code that are ment to run within a transaction.

Intent of the language

A KALA program declares transactional properties for a number of transactions in a Java program, based on the life-cycle of a given transaction. As is usual in OO programs that use transactions, the life-cycle of every transaction coincides with the life-cycle of a method. The transaction begins when the method begins, commits when the method ends normally, and aborts if the method ends with a specific type of exception.

Transactional properties take effect at given times in the life-cycle of the transaction: properties can be declared to apply at begin time, commit time and abort time. This is done by placing these declarations, which are KALA statements, in a begin block commit block and abort block, respectively. Outside of these blocks, a number of statements can be placed in the preliminaries.

Transactional properties are taken from the ACTA formal model: views, delegation and dependencies. Each of these properties is reified as a statement in KALA, respectively view, del and dep statements.

Join Point Model and Advice Model

  • JPM: Domain-Specific: Method executions and within their dynamic scope calls to setter and getters of 'special' classes. Special classes either implement a specific interface or are identified in the KALA program.
  • AM: Domain-Specific: Executable variant of the ACTA formal model for advanced transactions.

Anatomy of the language

We provide the SDF definition from the ReLAx 2) paper:

KDecl* ->  CompilationUnit \\
FQMPattern KBody                -> KDecl
"{" Prelim? BeginBlock? CommitBlock? AbortBlock? "}" -> KBody
PrelimStm*                 -> Prelim
"begin"  "{" BlockStm* "}" -> BeginBlock
"commit" "{" BlockStm* "}" -> CommitBlock
"abort"  "{" BlockStm* "}" -> AbortBlock
AStartStm     -> PrelimStm
NamingStm     -> PrelimStm
NamingStm     -> BlockStm
DepStm        -> BlockStm
ViewStm       -> BlockStm
DelStm        -> BlockStm
TermStm       -> BlockStm
"autostart" "(" MethSig ASActuals KBody ")" ";" -> AStartStm
"alias" "(" KBinding ")" ";"          -> NamingStm
"name"  "(" KBinding ")" ";"          -> NamingStm
"groupAdd" "(" KBinding ")" ";"       -> NamingStm
"dep" "(" JavaId JavaId JavaId ")" ";"-> DepStm
"view" "(" Min? JavaId JavaId ")" ";" -> ViewStm
"del" "(" JavaId JavaId  ")" ";"      -> DelStm
"terminate" "(" JavaExpr  ")" ";"     -> TermStm
JavaId JavaExpr                       -> KBinding 

A KALA declaration consists of a signature and body. The join-point model contains method executions, the signatures are the pointcut expressions, and the body constitutes advice. The advice specifies the transactional properties of a set of methods, specified by the pointcut expressions. Furthermore, within those methods reads and writes to objects that implement the Resourceable interface are made transactional.

Dependencies, views and delegation need to be able to denote the two transactions they affect; therefore there is a need for a variable binding mechanism. Within KALA code, such a binding is known as an alias. An alias is looked up through the use of a global naming service, which is declared using the alias statement. This statement takes as argument the alias for a transaction, i.e. the variable name, and a Java expression that evaluates to a key that is used to look up the transaction reference in the name service. This expression, as all expressions in KALA, has access to the actual parameters of the method and to aliases which have already been resolved. Special cases are the alias self, which is always bound to the currently running transaction, and the null transaction, which is the result of a lookup failure. KALA statements which have as an argument the null transaction fail silently. Adding transactions to the naming service is performed using the name statement, which takes as argument an alias and a Java expression that evaluates to the key for the naming service.

When placed in the preliminaries, aliases are looked up and names are registered immediately before the transaction starts. Aliases placed in begin, commit and abort blocks are looked up at that particular moment in the life-cycle of the transaction. The scope of aliases within a KALA declaration follows the usual lexical scoping rules: aliases obtained in the preliminaries of a declaration are accessible thoughout the remainder of the KALA code for that declaration; aliases placed in begin, commit and abort blocks are only accessible there.

KALA provides support for named groups of transactions. A transaction can be added to a group using the groupAdd statement. All KALA statements have an overloaded behavior for groups, e.g. setting a view from a transaction to a group of transactions implies setting the view to each member of the group. The only non-obvious case is when a group is a destination of a delegation statement. As semantically this has no sense –delegating some changes to a group of transactions–, a failure is produced.

Because dependencies may refer to transactions which have already ended, it is impossible to perform automatic garbage collection of names and dependency relationships when transactions have ended. Instead the KALA programmer is made responsible for such cleanup operations. This is performed through the terminate statement, which takes as argument a Java expression. This expression is resolved to a name of the transaction or group of transactions to be collected. Termination of transactions can be performed within a begin, commit and abort block. Note that if a transaction is terminated when it has not yet ended, it is immediately forced to rollback.

Typical Example: Nested Transactions

This model is one of the oldest and arguably the best-known ATMS. It enables a running transaction T to have a number of child transactions T_c. Each T_c can view the data used by T. This is in contrast to classical transactions, where the data of T is not shared with other transactions. T_c may itself also have a number of children T_{gc}, forming a tree of nested transactions. When a child transaction T_c commits its data, this data is not written to the database, but instead it is delegated to its parent T, where it becomes part of the data of T. If a transaction T_x is the root of a transaction tree, i.e. it has no parent, its data is committed to the database when it commits. Another characteristic of this model is that if a child transaction T_c aborts, the parent T is not required to abort, i.e. when it ends it may choose to either commit or abort.

util.strategy.Hierarchical.child*() {
  alias(parent Thread.currentThread() );
  name(self Thread.currentThread());
  groupAdd(self "ChildrenOf"+parent);
  begin { dep(self wd parent); dep(parent cd self); view(self parent); }
  commit { del(self parent); 
        name(parent Thread.currentThread());
        terminate("ChildrenOf"+self); }
  abort { name(parent Thread.currentThread()); 
       terminate("ChildrenOf"+self);} } 

The first line of the KALA code above is the KALA signature, which identifies the transactional methods. As a result, all data accesses to shared data within these methods (and within methods called by these methods) are included in the transaction.

The view property declared in the code above states that the current transaction, which is a child transaction, can see the data of its parent transaction. This property is established when the transaction begins. The delegation property (del) states that upon commit, the child transaction delegates its data changes to its parent transaction. The dependency self wd parent states that if the parent aborts before this transaction ends, then this transaction will be forced to also abort. parent cd self states that if the parent wants to commit, it has to wait until this transaction has ended.

The current thread is first used as a key to lookup the parent transaction, then to register the current transaction (overriding the binding), and finally, upon commit or abort, the parent binding is restored. Also, the code adds the current transaction to the group of children of the parent transaction and states that if a nested transaction finishes (by commit or abort), it terminates the group of its child transactions.

Enforced Restrictions

The language only allows for specific kinds of transactional semantics to be declared at specific life-cycle moments of the transaction. However, expressions used in naming statements run unchecked: any Java expression can be evaluated here. Although these expressions do not have any access to KALA internal state, they can break the program by throwing an exception.

Implementation description

The first implementation of KALA was done in an ad-hoc way, by performing source-code transformation. A second implementation, called ReLAx, was performed as a case study for the capabilities of DSAL infrastructure of the Reflex AOP kernel, and is described in the footnote3). In summary: the syntax of KALA is described in SDF, as we have shown above. This specification is used to generates a parser that produces an object representation of the parsed KALA program. The KALA signature determines where to weave the KALA implementation logic, which is generic. The objectified version of the KALA body is treated as configuration parameters by the implementation logic, resulting in the specified properties being ensured at runtime.

“A formalism for extended transaction models” P. K. Chrysanthis and K. Ramamritham, In Proceedings of the 17th International Conference on Very Large Data Bases, P103 – 112, 1991.
2) , 3)
“Infrastructure for Domain-Specific Aspect Languages: The ReLAx Case Study” Johan Fabry, Eric Tanter, Theo D’Hondt, In IET Software, To Appear