Transactional MSC Prototype
This project provides a prototype implementation of how ArjunaCore could be used for Transactional MSC. For the high-level documentation of this code: https://community.jboss.org/message/828391.
Running the tests and examples
The JUnit tests only cover the normal operation. They don’t yet cover recovery or orphan detection. This is because some complex setup is required to simulate crash-recovery. This can be done when we are further down the road of proving these techniques work.
To run them:
There are two recovery examples. The first covers a transaction with just a Root Transaction. The second covers a Root Transaction with an enlisted Subordinate Transaction. They are both pretty similar, so only the one with an enlisted Subordinate Transaction is described here.
This example runs a Root Transaction with an enlisted subordinate transaction. It simulates a crash during commit of a participant of the Subordinate Transaction. During recovery, the transactions is recovered and committed. To run:
mvn install exec:java -Dexec.mainClass="io.narayana.txmsc.SubordinateRecoveryExample" -Dexec.classpathScope="test" -DskipTests
In particular, observe that the Subordinate Transaction was told to commit, but crashed during this operation:
... SubordinateParticipantStub:topLevelCommit ConfigParticipant:childConfigService:CRASH:topLevelCommit Server simulated a crash, as expected
You can take a look at the object store to see the transaction logs for the Root and Subordinate Transactions:
tree target/object-store target/object-store └── ShadowNoFileLockStore └── defaultStore └── StateManager ├── RootTransaction │ └── 0_ffffac118223_df05_522dda69_0 └── SubordinateTransaction └── 0_ffffac118223_df05_522dda69_3
Now run the example in recovery mode:
mvn install exec:java -Dexec.mainClass="io.narayana.txmsc.SubordinateRecoveryExample" -Dexec.classpathScope="test" -DskipTests -Dexec.args=--recover
In particular, observe that the commit is called on the two participants and that the application state change was made:
... ConfigParticipant:recovery:topLevelCommit:newValue:child-config=newChildConfigValue ConfigParticipant:recovery:topLevelCommit:newValue:parent-config=newParentConfigValue 'child-config' value = newChildConfigValue 'parent-config' value = newParentConfigValue
Orphan Detection Example
SubordinateOrphanExample.java demonstrates how an orphaned Subordinate Transaction can occur. Essentially, this happens if a failure occurs after the Subordinate Transaction is prepared (and thus logged), but before the Root Transaction prepares (and thus not logged).
Create an orphaned transaction by running:
mvn install exec:java -Dexec.mainClass="io.narayana.txmsc.SubordinateOrphanExample" -Dexec.classpathScope="test" -DskipTests
Observe a single recovery record, for the Subordinate Transaction in the object store:
tree ./target/object-store ./target/object-store └── ShadowNoFileLockStore └── defaultStore └── StateManager ├── RootTransaction └── SubordinateTransaction └── 0_ffffac118223_de90_522dd75d_3
Then run recovery to have the orpahn be detected and then rolled back:
mvn install exec:java -Dexec.mainClass="io.narayana.txmsc.SubordinateOrphanExample" -Dexec.classpathScope="test" -DskipTests -DskipTests -Dexec.args=--recover
Observe that the outputed values of the parent and child config values is still 'null', as it was before the transaction was begun. You will also notice that the transaction log has been removed.