Supporting Promotable Transactions and Phase 0

If you are providing support for promotable transactions for your resource manager using PSPE then you need to remember to "support" Phase 0.

In general, a resource manager doesn't need to do anything special about Phase 0; this phase will be handled solely by the transaction manager. But, because in the case of promotable transactions using the PSPE mechanism, the resource manager acts as a special "transaction manager", your resource manager needs to be aware of Phase 0. Why? Because in this case, the resource manager "owns" the distributed transaction and System.Transaction will call Commit on the PSPE interface asking the resource manager to call Commit on the distributed transaction. The resource manager needs to be aware that even after it will call Commit on the distributed transaction it owns, there is a possibility that requests to enlist and do work as part of the same transaction are still possible, based on the Phase 0 rules. And these requests are supposed to be accepted. Don't worry, there will be no data corruption. MSDTC guarantees that Phase 0 happens before Phase 1 starts delivering its "prepare" messages.

What exactly you need to do to ensure Phase 0 support? Let's create the list:

  1. when you receive the "commit" request through the PSPE interface, call Commit on the distributed transaction but do not start the commit process on your data yet; wait for the Prepare message on the distributed transaction from MSDTC before doing any work (this assumes you are enlisted with that transaction - you should be!); in other words, when you receive the IPromotableSinglePhaseNotification::SinglePhaseCommit simply "pass" along the Commit to the distributed trasaction you own and don't do anything else
  2. don't get confused by the name of IPromotableSinglePhaseNotification::SinglePhaseCommit; it is not the same as the classic single phase commit from MSDTC; there might be phase 0 enlistments out there that might enlist other durable resource managers in the transaction, and thus a 2-Phase-Commit might be necessary
  3. even after calling Commit on the distributed transaction, you should continue to accept new connections and work on the same transaction; don't worry, phase 1 didn't start yet, these are just phase 0 enlistments "flushing" their data to durable stores
  4. once you received the "prepare" message from MSDTC on the distributed transaction, only then you should start your normal 2PC operation
  5. if any new request is received on the same transaction after "prepare" was received from MSDTC, you should deny it as you do in any 2PC scenario after phase 1 started

Sounds like a lot of steps, but in reality, this can be said in a short summary: "when you receive IPromotableSinglePhaseNotification::SinglePhaseCommit, pass along the Commit to the distributed transaction you own and behave like it didn't happen :), i.e. accept new connection requests in the same transaction until MSDTC delivers you the "prepare" message.

Of course, if Promote was never called, then there isn't any distributed transaction involved and thus you can proceed with commiting the work when IPromotableSinglePhaseNotification::SinglePhaseCommit is called.

Related posts:

Thanks for supporting promotable transactions and Phase 0.