What TM Do I Need?
Now you get to see some code. I'll first show you some pseudo code. What is the easiest way to make anything transactional? Take a look at the code block below.
Do Some Stuff #1;
Do Some Stuff #2;
Do Some Stuff #3;
Do Some Stuff #4;
Mark Transaction Complete;
That seems simple enough. Using System.Transactions is almost as simple as the above pseudo code. Here is a typical usage of System.Transactions.
using (TransactionScope txScope =
// Do Transactional Operations
Where you see the comment, "Do Transactional Operations" is where you simply use the RM. However, when writing the RM, you have to choose between one of three methods in which an RM can choose to enlist itself within a transaction.
A RM that deals with resources that are not permanent in nature, such as an in-memory cache, is generally a good candidate for volatile enlistment. This means that a RM needs to perform the prepare phase, but in case of a rollback issued, the first phase need not be explicitly recovered. Also, in case your RM crashes, it doesn't need to have logic for a recovery contract, or re-enlistment when the RM is instantiated again. Generally such an RM is managed by the LTM, thus you do not pay the extra penalty for MSDTC.
Say you were writing logic to move files between servers and you wanted this logic to behave in a transactional manner. In this scenario, if your RM crashed, you would have to ensure that you both have enough information to perform a graceful recovery, and when another instance of the RM is brought up it can use that information to clean up after its previous incarnation. Also, say in the prepare phase you actually copied over the file, in case of Rollback, you would either have to delete the newly copied file, or you may have to restore a possibly overwritten file. In other words, when you are dealing with a durable resource, you have to deal with such complexity, and you need to hear the appropriate callbacks from the transaction manager. In order to participate in a transaction in such a durable manner, you would enlist your RM to enlist in a durable fashion, and such a transaction would generally be managed by MSDTC.
Do note, however, that file copy is a lot simpler than the transactional file system that could be a part of the upcoming Windows Vista operating system. For starters, the transactional file system may need to operate without MSDTC, because file operations may need to be done when MSDTC hasn't started up yet.
Promotable Single-Phase Enlistment (PSPE)
In certain situations the RM itself has transactional capabilities built into itself. A good example is a database. Or maybe the RM in certain situations doesn't care for a graceful recovery in certain situations. In those situations, it is unfair that those simpler situations should have to pay the heavy price of durable enlistment.
A midway approach would be Promotable Single Phase Enlistment (PSPE). Generally in these scenarios, a durable RM such as a database would take ownership of a transaction, which as conditions change can later be escalated to the appropriate transaction manager. For instance, if you have a single SqlConnection instance connected to SQL Server 2005 in a transaction, your transaction, in spite of durable resources, will still be managed by LTM. This is because the RM itself has taken ownership and responsibility for the transaction. However, as soon as a second open SqlConnection instance enlists itself within the same transaction, your transaction is then promoted to MSDTC.
The SqlConnection object exhibits PSPE only when connected to a SQL Server 2005 database. Previous versions enlist durably even with a single instance of SqlConnection. Also, SqlConnection connected to even a single instance of SQL Server 2005, from within SQLCLR (the CLR inside SQL Server) will always enlist in a durable manner.
Enough of the theory. Let's see a demo.