Dan H&#228&#59;ndevik

Hi,

I have written a simple ! resource manager that keeps track of dataobjects and their state on the server.
The resource manager is used like below (pseudo code)

using(TransactionScope s = new TransactionScope)

{
myResourceManager.AddItemToManager(myItem);
myItem.Id = GetNewIdFromDb();

if(SaveMyItemToDb(myItem))

{
s.Complete();
}
}

The purpose of the resource manager is to record the original state of the items added to the manager and when
the transaction ends, commit the changes or rollback the original state of the items. In this case the items
original state is restored if the save to the db was unsuccessful.

This works quite well until the SaveMyItemToDb method escalates the transaction to a distributed transaction
(in some cases multiple connections exists). I tried to solve this by letting the MyResourceManager implement the IPromotableSinglePhaseNotification interface and implementing the Promote method.

byte[] ITransactionPromoter.Promote()
{
tx = new CommittableTransaction();
return TransactionInterop.GetTransmitterPropagationToken(tx);
}

The promote method creates a new Transaction that should be added to the DTC (as far as I understand) and then
gets the DTC token for the registered transaction. (Then the resource manager should be enlisted in the created transaction). The problem is that when the Promote method returns its caller (TransactionStatePSPEOperation.PSPEPromote(InternalTransaction)) throws an exception.

System.InvalidOperationException: The transaction returned from Promote already exists as a distributed transaction.
at System.Transactions.TransactionStatePSPEOperation.PSPEPromote(InternalTransaction tx)
at System.Transactions.TransactionStateDelegatedBase.EnterState(InternalTransaction tx)
at System.Transactions.EnlistableStates.Promote(InternalTransaction tx)
at System.Transactions.Transaction.Promote()
at System.Transactions.TransactionInterop.ConvertToOletxTransaction(Transaction transaction)
at System.Transactions.TransactionInterop.GetTransmitterPropagationToken(Transaction transaction)

...

Why is this Is the created CommittableTransaction already promoted or what
Should I solve the problem another way

Any Ideas




Re: Transactions Programming Promoting a resource manager

Jim Carley

I need a little bit more information.

There isn't any information on how your resource manager enlists in the transaction in the first place. VolatileEnlist vs. DurableEnlist EnlistDuringPrepareRequired From what I have seen, I am guessing it is VolatileEnlist, but I am not sure.

Can you give more details on how it doesn't work when the transaction promotes as part of SaveMyItemToDb If your resource manager is enlisted, the fact that the transaction promoted shouldn't affect your resource manager. It should still get its Prepare and Commit/Rollback notifications.

Implementing a resource manager that uses IPromotableSinglePhaseEnlist and implements IPromotableSinglePhaseNotification can be tricky. The exception stack you provided was truncated and there is more interesting data to be obtained by seeing the entire stack. If you could provide the entire stack it would be helpful.

I look forward to seeing what you have. You are attempting to do something that not too many folks are doing - writing a resource manager.

Jim





Re: Transactions Programming Promoting a resource manager

Florin Lazar - MSFT

I'm not sure you need to use IPromotobleSinglePhaseNotification. That is for scenarios where you want to talk to a remote resource manager without causing transaction promotion. Was that your intent

Can you provide more details on the usage of the custom resource manager you are building
What is this resource manager intended to do during Commit
Also, what didn't work in the case of distributed transactions (before you started using IPromotobleSinglePhaseNotification)






Re: Transactions Programming Promoting a resource manager

Dan Handevik

Hi and thanks for your reply.

Some backround.

I started with a resource manager that implemented ISinglePhaseNotification and enlisted it as a voilate rm, but I couldn't get it to commit when I enlisted a durable rm later on in the transaction scope (when the transaction escalated to a distributed one).

(I posted a question about that before http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=1692039&SiteID=1 and got great help.)

Then I thought, maybe use the IPromotableSinglePhaseNotification interface as well to fix the escalations.

I enlisted this one with EnlistPromotableSinglePhase and if that failed, enlisted it using EnlistDurable.

This went well until another rm escalated the transaction to a distributed one.

When the Promote call arrived I created a new CommittableTransaction, and tried to register it in the DTC using the

tx = new CommittableTransaction();

byte[] txToken = TransactionInterop.GetTransmitterPropagationToken(tx);

It was here it failed stating that the CommittableTransaction is already a distributed transaction.

I guessed that the IPromotableSinglePhaseNotification interface is designed to be used in a remote scenario (client/server), since all examples for the interface has been in such a setup, but all my resource managers are running in the same process (server) so I might be a bit off course here.

When I got back to the original implementation (skipping the promotable part) I tested to wait a bit until I was sure that the Commit/Rollback of the rm had done their part (needed to create a method that blocked until the rm was completed and call this mthd before checking the rm status) and this seemed to work, so I might have been to hasty to swith to the IPromotableSinglePhaseNotification interface. I will do some more tests.

Another thought:

Since I'm running in the same process I could perhaps create a class that does the work for me without registering it in the transaction (and perhanps in the MTC (in case of a distributed transaction !)). Is there much overhead in using a rm compared to keeping track of the classes by my self (especially when it comes to utilizing a MTC)

Ps. I think I'm beginning to grasp the concepts of the resource manager and transactions...it's rather complex ynow.

Thanks for your patience with the illiterate newbies.

Ds.






Re: Transactions Programming Promoting a resource manager

Florin Lazar - MSFT

Indeed, it looks that you don't need to use ISinglePhaseNotification.

Good to hear that your app is working now. Commit requests to RMs show up after the "transaction is committed" and transaction scopes are finished (i.e. Disposed). Once the first phase of the transaction (Prepare) is passed with success, Transaction.Commit returns. It is the responsibility of the transaction manager to follow up with the resource managers and deliver the Commit.

I don't know what you refer as MTC. Volatile resource manager add very little overhead, and if you want to work with data that is modified under transactions, you might need to participate in the Prepare/Commit/Abort phases anyway.

Cheers!






Re: Transactions Programming Promoting a resource manager

Dan Handevik

Doesn't distributed transactions use the MTC (Microsoft Transaction Coordinator or it is perhaps called DTC (Distributed Transaction Coordinator). Does this affect a volatile resource manager or is that is transparent to the resource manager and only affects the performance of the transaction






Re: Transactions Programming Promoting a resource manager

Florin Lazar - MSFT

I see, you are referring to MSDTC (Microsoft Distributed Transaction Coordinator).

It is indeed transparent to the resource manager what transaction manager or coordinator is handling the transaction. The resource manager will always receive notifications through the same interface: IEnlistmentNotification.