Invasive Patterns

Invasive patterns reconcile architecture and implementation in distributed applications.

Motivation

Even tough distributed applications present architectures based in communication patterns, current implementations do not represent such patterns at the code level.

For example in JBoss Cache we can represent the architecture of replication and data gravitation nicely by means of composition of three patterns:



However the implementation of such architecture does not result into patern-based entities at the code level. Instead of that the resulting implementation is entangled and scattered all over the source code. For example we can see how the code is entangled by analyzing a piece of code found in the class DataGravitation:
//----- excerpt of code in the invoke method of
//----- class DataGravitation
...
try
{
 switch (m.getMethodId())
  {
    case MethodDeclarations.prepareMethod_id:
    case MethodDeclarations.optimisticPrepareMethod_id:
         Object o = super.invoke(m);
         doPrepare(getInvocationContext().getGlobalTransaction());
         return o;
    case MethodDeclarations.rollbackMethod_id:
         transactionMods.remove(
                 getInvocationContext().getGlobalTransaction());
         return super.invoke(m);
    case MethodDeclarations.commitMethod_id:
         doCommit(getInvocationContext().getGlobalTransaction());
         transactionMods.remove(
                   getInvocationContext().getGlobalTransaction());
         return super.invoke(m);
  }
}
...
This code shows a switch statement that implements the two phase commit protocol. Note that such code is only called when data gravitation is active, and is found in the invoke method of the class DataGravitation (entangling). We can see in the code above (see highlighted code) that such implementation takes full control of the protocol replicating actual data by analyzing the doCommit method implementation:
//---- The docommit method in DataGravitation class
private void doCommit(GlobalTransaction gtx) throws Throwable
   {
      if (transactionMods.containsKey(gtx))
      {
         if (log.isTraceEnabled())
               log.trace("Broadcasting commit for gtx " + gtx);
         replicateCall(getMembersOutsideBuddyGroup(),
            MethodCallFactory.create(
                  MethodDeclarations.commitMethod,
                  new Object[]{gtx}),
                  syncCommunications);
      }
      else
      {
         if (log.isTraceEnabled())
             log.trace(
              "Nothing to broadcast in commit phase for gtx " + gtx);
      }
   }
Here the doCommit method decides to which hosts the commit method is broad casted. In this case, to all members outside the "BuddyGroup"(see highlighted code).

This kind of situation is very frequent in JBoss Cache. In particular the switch statement for the two phase commit protocol is a kind of idiom in the implementation that is used frequently in the code. The consequence of such coding style is that the transactions and replication code gets entangled and scattered over the application source code. The following figure shows graphically such situation:
The figure above shows the TreeCache class (main class in Jboss Cache implementation) and the package for interceptor filters. The replication code (blue), transaction code (black) and interceptor calls (yellow, green) are heavily scattered and tangled [Benavides et al., AOSD'06]. As we can see no (overall) pattern-based architecture on the code level is found.

Approach: invasive distributed patterns

For example an invasive gather pattern will be represented as shown bellow:





In order to map such representation to code we propose a pattern language.

Pattern language and compositions

 P    ::=     patternSeq G1 A1 G2 A2 . . . Gn
 G    ::=     H G |P G |ǫ
 A    ::=     aspect { around((H, Id*)*): PCD SourceAdvice    [sync] TargetAdvice }
 PCD  ::=     call(MSig ) | target(Id) | args(Id+)
        |     PCD && PCD | PCD || PCD | !PCD
        |     Seq

Pattern-based definition of JBoss Cache

    gCaches = {h1, h2, h3}
    pipe([h], // h is current host
         Atransac,
           farm(
             gather(
               farm([h], Aprepare, sync gCaches-[h]),
             Apresp,
             [h]),
           Acommit,
           gCaches-[h])
        );

Implementation

Implemented using Aspects with Explicit Distribution (AWED):

Publications

  1. Luis Daniel Benavides Navarro, Mario Südholt, Remi Douence and Jean-Marc Menaud. Invasive patterns for distributed programs. Proc. of the 9th International Symposium on Distributed Objects, Middleware, and Applications (DOA'07), Nov 2007.
    PDF BIBTEX