Sunday, March 29, 2009
JBossTS offsite
We had another good offsite meeting earlier this week. As usual Jonathan was spot-on with the selection of venue (the Black Swan Hotel): good food and a great atmosphere for discussions and planning. We had the JBossTS and Blacktie teams together in one place, so were able to cover a lot of things from TOAST through RESTful transactions and OSGi. Jonathan was able to plan out the next 6 months or so for the team and it's a good mix of definite current needs and beliefs on future requirements. I can't wait for the next meeting!
Wednesday, March 25, 2009
Compiled Configurable TOAST
In between completing fully functional crash recovery for the Web Services Transactions (XTS) code and writing a comprehensive test suite for it I've been able to squeeze in a couple of nice extensions to the functionality of TOAST, the code injection tool I have been using to automate XTS crash recovery testing.
Attentive readers may recall that TOAST is a nifty, easy to use tool for injecting side-effects into Java code. I have been using TOAST to test XTS recovery by injecting code which crashes the JVM in the middle of a transaction commit. I also use TOAST to inject further faults during recovery in order to delay or drop messages exchanged between the transaction coordinator and the web service participants it is trying to corral into a successful commit. Finally, I inject trace statements at suitable locations in the code which track the progress of the test and allow the test client to identify successful or failed execution.
None of this requires any modifications to or recompilation of the deliverable application being tested. TOAST just needs to be supplied with a script identifying the trigger points, locations in the application code which need to be tweaked, and the Java expressions which are to be (conditionally) executed at those trigger points. Point your JVM at the TOAST jar and the script when you start your Java application and TOAST makes sure all the required side effects get executed.
For those who have not yet had a look at TOAST I'll recap a little. Scripts comprise a sequence of Event Condition Action (ECA) rules. The Event part is the specification of the trigger point, a class name, a method located in that class and some location in the method code. Locations identify a point in the source code through reference to the code structure. Examples might be: the start of the method (AT ENTRY) when a return occurs (AT EXIT), before the first read of an instance field (AT READ myField), after the 2nd call to a method (AFTER CALL getMyField() 2) and so on. The event specifies WHEN the side-effects coded in the rule are are considered for execution by describing a trigger point. Whenever a thread reaches this trigger point it enters the rule engine to decide whether to fire the associated rule.
The Condition part is a Java expression specifying WHETHER to fire the rule. If this evaluates to true then the rule fires and executes its Action. If the condition is false then control returns to the trigger method and execution continues as normal.
The Action part specifies WHAT side-effects need to occur. It is a sequence of Java expressions to be evaluated one after another. The last expression may be a return or a throw action. These cause an immediate abnormal return of control from the triggering method bypassing normal execution of the rest of the method code. If the method is non-void then the return action must include an expression evaluated to compute the return value. A throw action must include an exception type and arguments for the exception constructor.
In order to simplify testing of multi-threaded code TOAST's rule language also includes built-in methods for use in conditions and actions. These are a variety of operations which simplify the development of multi-threaded tests. For example, one rule might include a call to waitFor() in its action list, suspending any thread which fires the rule. Another rule might include call to signalWake() in its action. If a second thread fires this rule then the call to signalWake() wakes up the suspended thread. This can be used to ensure that the first thread is only allowed to progress once the second thread has reached a suitable point during its execution.
So, what are the two updates which I have sneaked in? Well, the first one is to compile the rule code to bytecode. Up until now the rule execution engine has worked by interpreting the rule parse tree. Method and builtin calls were executed using reflection. Java operations were executed by evaluating their arguments and then combining them based on the operation type. Well, the latest version of TOAST now compiles the rule code into Java bytecode attached to a helper class associated with the rule. This bytecode is handed to the JIT compiler which means it can be compiled to native machine code and optimized like any other Java method. This will not make a lot of difference for rules which are only executed once or twice but it will make a big difference to the usability of TOAST in cases where rules are triggered many times.
The second update is a very nice generalization of the built-in functionality. The rule parser, type-checker and compiler don't actually care much about the presence of builtin methods. As far as they are concerned a call is a call is a call. The type checker, in particular, attempts to resolve calls by looking at the method name and signature i.e. the types of the call arguments. Any calls whose name and signature matches a public instance method of a class called Helper are treated as built-in calls. When the rule is triggered an instance of Helper is created to store the list of event bindings. A built-in call can be executed by calling the matching method with this instance as the method target. The compiler actually generates a subclass of Helper whose execute() method comprises the compiled rule bytecode. So, built-in calls are actually just invocations of methods on this.
Now, this mechanism is completely independent of the details of how class Helper is defined. Any public POJO class could actually be used to define the rule language built-ins. So, a simple declaration in the rule source specifying the name of an alternative class will allow the rules to use a different helper more appropriate to the application in question. A domain-specific helper class makes scripting of side-effects simpler and tidier by encoding complex, application-specific actions as single operations. If you like you can keep the current built-ins and add some more of your own by extending class Helper and adding extra public methods. If you don't like how one of the default built-in operations works you can override the version Helper provides to re-implement it.
These upgrades are described more fully in the TOAST documentation. Please download TOAST, take a look and give it a test run.
Attentive readers may recall that TOAST is a nifty, easy to use tool for injecting side-effects into Java code. I have been using TOAST to test XTS recovery by injecting code which crashes the JVM in the middle of a transaction commit. I also use TOAST to inject further faults during recovery in order to delay or drop messages exchanged between the transaction coordinator and the web service participants it is trying to corral into a successful commit. Finally, I inject trace statements at suitable locations in the code which track the progress of the test and allow the test client to identify successful or failed execution.
None of this requires any modifications to or recompilation of the deliverable application being tested. TOAST just needs to be supplied with a script identifying the trigger points, locations in the application code which need to be tweaked, and the Java expressions which are to be (conditionally) executed at those trigger points. Point your JVM at the TOAST jar and the script when you start your Java application and TOAST makes sure all the required side effects get executed.
For those who have not yet had a look at TOAST I'll recap a little. Scripts comprise a sequence of Event Condition Action (ECA) rules. The Event part is the specification of the trigger point, a class name, a method located in that class and some location in the method code. Locations identify a point in the source code through reference to the code structure. Examples might be: the start of the method (AT ENTRY) when a return occurs (AT EXIT), before the first read of an instance field (AT READ myField), after the 2nd call to a method (AFTER CALL getMyField() 2) and so on. The event specifies WHEN the side-effects coded in the rule are are considered for execution by describing a trigger point. Whenever a thread reaches this trigger point it enters the rule engine to decide whether to fire the associated rule.
The Condition part is a Java expression specifying WHETHER to fire the rule. If this evaluates to true then the rule fires and executes its Action. If the condition is false then control returns to the trigger method and execution continues as normal.
The Action part specifies WHAT side-effects need to occur. It is a sequence of Java expressions to be evaluated one after another. The last expression may be a return or a throw action. These cause an immediate abnormal return of control from the triggering method bypassing normal execution of the rest of the method code. If the method is non-void then the return action must include an expression evaluated to compute the return value. A throw action must include an exception type and arguments for the exception constructor.
In order to simplify testing of multi-threaded code TOAST's rule language also includes built-in methods for use in conditions and actions. These are a variety of operations which simplify the development of multi-threaded tests. For example, one rule might include a call to waitFor() in its action list, suspending any thread which fires the rule. Another rule might include call to signalWake() in its action. If a second thread fires this rule then the call to signalWake() wakes up the suspended thread. This can be used to ensure that the first thread is only allowed to progress once the second thread has reached a suitable point during its execution.
So, what are the two updates which I have sneaked in? Well, the first one is to compile the rule code to bytecode. Up until now the rule execution engine has worked by interpreting the rule parse tree. Method and builtin calls were executed using reflection. Java operations were executed by evaluating their arguments and then combining them based on the operation type. Well, the latest version of TOAST now compiles the rule code into Java bytecode attached to a helper class associated with the rule. This bytecode is handed to the JIT compiler which means it can be compiled to native machine code and optimized like any other Java method. This will not make a lot of difference for rules which are only executed once or twice but it will make a big difference to the usability of TOAST in cases where rules are triggered many times.
The second update is a very nice generalization of the built-in functionality. The rule parser, type-checker and compiler don't actually care much about the presence of builtin methods. As far as they are concerned a call is a call is a call. The type checker, in particular, attempts to resolve calls by looking at the method name and signature i.e. the types of the call arguments. Any calls whose name and signature matches a public instance method of a class called Helper are treated as built-in calls. When the rule is triggered an instance of Helper is created to store the list of event bindings. A built-in call can be executed by calling the matching method with this instance as the method target. The compiler actually generates a subclass of Helper whose execute() method comprises the compiled rule bytecode. So, built-in calls are actually just invocations of methods on this.
Now, this mechanism is completely independent of the details of how class Helper is defined. Any public POJO class could actually be used to define the rule language built-ins. So, a simple declaration in the rule source specifying the name of an alternative class will allow the rules to use a different helper more appropriate to the application in question. A domain-specific helper class makes scripting of side-effects simpler and tidier by encoding complex, application-specific actions as single operations. If you like you can keep the current built-ins and add some more of your own by extending class Helper and adding extra public methods. If you don't like how one of the default built-in operations works you can override the version Helper provides to re-implement it.
These upgrades are described more fully in the TOAST documentation. Please download TOAST, take a look and give it a test run.
Monday, March 16, 2009
Nested transaction support
For well over 20 years we've been saying that JBossTS (aka ArjunaTS aka Arjuna) supports nested transactions. If you check out most of the papers, documents or presentations that have been written on the subject over the years they'll all tell you that nested transactions (subtransactions) are good because:
Now nested transactions have been around for a while (since the early 80's) but they have had limited adoption outside of academia. We did manage to get them adopted within the OTS, even if in a fairly brain-dead/limited approach. But other standards either ignored them (e.g., XA) or made such vague statements about them as to be useless (e.g., JTA). The reason for this is mainly because database vendors have not traditionally supported nested transactions and is primarily why I'm writing this blog entry: I've noticed a few new transaction manager implementations that say they support nested transactions. But what does that actually mean?
If you look at either the JBossTS architecture or even the OTS interfaces, there's not a lot you have to do to the coordinator in order for it to support a parent-child relationship. That's the easy part! (In fact it's easier for the coordinator to support nested transactions because there's no requirement for durability.) But as with a top-level transaction implementation, you need participants (e.g., databases) to be able to do anything useful. The semantics of nested transactions (relaxing ACID properties) mean that a top-level aware participant can't be used for a nested transactions (e.g., your database is going to write the state changes to disk when the XAResource is driven through 2PC and what about lock inheritance?)
Thus whenever we said "JBossTS supports nested transactions" we meant that the coordinator had the parent-child relationship, but we also provided nested transaction-aware resources. Rather than doing very little to the coordinator and pushing most of the real effort on to the application developer or resource implementer, we provide a complete toolkit for developing transactional applications. As a developer you don't have to worry about whether or not a transaction is nested and whether or not you've got nested transaction-aware resources in the mix somehow. All of that is taken care of by JBossTS. So be careful if you come across a transaction manager that says it "supports" nested transactions: it's a meaningless statement unless this covers the coordinator and participants (state and concurrency control). And of course you want to do this in a distributed environment as well as in a flexible manner! (Yes, we do that too!)
- fault-isolation: if subtransaction rolls back (e.g., because an object it was using fails) then this does not require the enclosing transaction to rollback, thus undoing all of the work performed so far.
- modularity: if there is already a transaction associated with a call when a new transaction is begun, then the transaction will be nested within it. Therefore, a programmer who knows that an object require transactions can use them within the object: if the object’s methods are invoked without a client transaction, then the object’s transactions will simply be top-level; otherwise, they will be nested within the scope of the client’s transactions. Likewise, a client need not know that the object is transactional, and can begin its own transaction.
Now nested transactions have been around for a while (since the early 80's) but they have had limited adoption outside of academia. We did manage to get them adopted within the OTS, even if in a fairly brain-dead/limited approach. But other standards either ignored them (e.g., XA) or made such vague statements about them as to be useless (e.g., JTA). The reason for this is mainly because database vendors have not traditionally supported nested transactions and is primarily why I'm writing this blog entry: I've noticed a few new transaction manager implementations that say they support nested transactions. But what does that actually mean?
If you look at either the JBossTS architecture or even the OTS interfaces, there's not a lot you have to do to the coordinator in order for it to support a parent-child relationship. That's the easy part! (In fact it's easier for the coordinator to support nested transactions because there's no requirement for durability.) But as with a top-level transaction implementation, you need participants (e.g., databases) to be able to do anything useful. The semantics of nested transactions (relaxing ACID properties) mean that a top-level aware participant can't be used for a nested transactions (e.g., your database is going to write the state changes to disk when the XAResource is driven through 2PC and what about lock inheritance?)
Thus whenever we said "JBossTS supports nested transactions" we meant that the coordinator had the parent-child relationship, but we also provided nested transaction-aware resources. Rather than doing very little to the coordinator and pushing most of the real effort on to the application developer or resource implementer, we provide a complete toolkit for developing transactional applications. As a developer you don't have to worry about whether or not a transaction is nested and whether or not you've got nested transaction-aware resources in the mix somehow. All of that is taken care of by JBossTS. So be careful if you come across a transaction manager that says it "supports" nested transactions: it's a meaningless statement unless this covers the coordinator and participants (state and concurrency control). And of course you want to do this in a distributed environment as well as in a flexible manner! (Yes, we do that too!)
Wednesday, March 11, 2009
RESTful transactions reborn
I've mentioned a few times about work we did almost 10 years ago on transactional REST services. This was when JBossTS was part of the HP Netaction suite, we were working on BTP, as well as the precursor to WS-TX/WS-CAF and the world's first Web Services transactions product HP-WST.
Without reminiscing too much, in those days I was participating in the W3C Web Services Architecture working group and the topic of REST came up there quite regularly. So we decided to give it a try as far as transactions were concerned and 'hey presto' RESTful transactions were born. This was way before JAX-RS so we were hand crafting the interactions ourselves, but we demonstrated it could work with the involvement of several companies. And there is remained once HP divested themselves of their middleware division.
But having transactional REST-based services has been a pet project for a long time, so it was bound to rear its head. Especially as some people (rightly) push the Web as an integration platform (shouldn't really be news to people since the WWW has always been about integrating data). Of course there are those who say you don't need transactions in the Web or can (somehow) program around them, but they miss the point. It's a bit like saying you don't need an airbag in your car but can use a pillow (and quick reflexes) yourself to save money. Yes, transactions aren't right for all situations and some bespoke approaches may be more efficient, but if you think about what you get from a transaction system and what you'd have to do in order to obtain the same guarantees, it's more often than not worth using them.
So we originally created a student project to dust off the old REST transactions protocol(s) and implement them today. This started life before JAX-RS (again) but by the time something really happened JAX-RS (and RESTeasy) was around. Michael from the JBossTS team took this work on and did a great job. It's not finished (only the atomic outcome protocol has been implemented so far, for example). Plus the protocols haven't been changed at all since they were created back in 2000/2001. So there are still some things we need to look at and more interesting work ahead.
Is this something you should be looking at for your projects? Should you believe those people who say transactions and REST don't go together? Well as I'm fond of saying "One size does not fit all." Transactions have played a critical part in all distributed systems for over four decades and for very good reasons. Of course we have XTS and Web Services Transactions support if you're using SOAP. But maybe SOAP isn't "your thing" and HTTP is all you can use. Well in that case take a look at this. In just the same way that you wouldn't want to be using a tank in the ocean and a submarine on land, use the right software tool for the right job!
Without reminiscing too much, in those days I was participating in the W3C Web Services Architecture working group and the topic of REST came up there quite regularly. So we decided to give it a try as far as transactions were concerned and 'hey presto' RESTful transactions were born. This was way before JAX-RS so we were hand crafting the interactions ourselves, but we demonstrated it could work with the involvement of several companies. And there is remained once HP divested themselves of their middleware division.
But having transactional REST-based services has been a pet project for a long time, so it was bound to rear its head. Especially as some people (rightly) push the Web as an integration platform (shouldn't really be news to people since the WWW has always been about integrating data). Of course there are those who say you don't need transactions in the Web or can (somehow) program around them, but they miss the point. It's a bit like saying you don't need an airbag in your car but can use a pillow (and quick reflexes) yourself to save money. Yes, transactions aren't right for all situations and some bespoke approaches may be more efficient, but if you think about what you get from a transaction system and what you'd have to do in order to obtain the same guarantees, it's more often than not worth using them.
So we originally created a student project to dust off the old REST transactions protocol(s) and implement them today. This started life before JAX-RS (again) but by the time something really happened JAX-RS (and RESTeasy) was around. Michael from the JBossTS team took this work on and did a great job. It's not finished (only the atomic outcome protocol has been implemented so far, for example). Plus the protocols haven't been changed at all since they were created back in 2000/2001. So there are still some things we need to look at and more interesting work ahead.
Is this something you should be looking at for your projects? Should you believe those people who say transactions and REST don't go together? Well as I'm fond of saying "One size does not fit all." Transactions have played a critical part in all distributed systems for over four decades and for very good reasons. Of course we have XTS and Web Services Transactions support if you're using SOAP. But maybe SOAP isn't "your thing" and HTTP is all you can use. Well in that case take a look at this. In just the same way that you wouldn't want to be using a tank in the ocean and a submarine on land, use the right software tool for the right job!
Subscribe to:
Posts (Atom)