Mark Jen [ex-MSFT]

Indigo/xES Transactions [tx.Rollback() strikes again...]

July 2004 - Posts

enlistment anyone?

So, you know you need a transaction and you've created a transaction object. Next, you most likely want to do some transacted work. At this point, there are two possibilities:

1.      you need to use a resource that understands transactions

2.      you need to create a resource that understands transactions

First of all, don’t let the term “resource” scare you; it simply means creating a piece of code that wishes to be informed when a transaction is going through its commit process. Any components you are building that want to know the outcome of a transaction, want to vote during the preparation of the transaction, or want to do durable work in the scope of a transaction all fall into the second category.

For today’s blog, I’ll be focusing on getting started developing a component in the second category. To get stuff rolling, you’ll need to decide whether or not your transacted functionality needs to be durable. Normally, you need to be durable if you have a resource for which you need to protect data integrity. If you don’t have anything that requires you to be able to guarantee data integrity in the face of system failures, then your resource is volatile.

Two main examples of durable resources are databases and file systems. For these resources, data integrity is paramount. Also, things that are built on top of these resources are also typically durable since they are backed by durable storage. In contrast,  a few examples of volatile resources include dialog boxes, diagnostic logging tools and in-memory caches. For the most part, these components are ok if they don’t receive the outcome of the transaction or if they crash and don’t maintain data integrity.

So let’s say you need to protect data integrity. That means you are creating a durable resource and you need to implement an IResourceManager object. This interface gives you a way to expose an identifier to System.Transactions; - it uses this identifier to track entities that require their notifications to be guaranteed. Think of it as a tracking number for your component so that in the event of a crash, the TMs and System.Transactions can make sure you still get notifications for your transactions.

The most basic IResourceManager looks like this:

    class MyResourceManager : IResourceManager

    {

        Guid myGuid;

 

        public MyResourceManager()

        {

            // ... grab myGuid from a durable store (file, databsae, etc) ...

        }

 

        #region IResourceManager Members

        Guid IResourceManager.Identifier

        {

            get { myGuid; }

        }

        #endregion

    }

 

You’ll notice that the identifier Guid doesn’t change. This is very important because if you change your identifier, System.Transactions will think you are a new and different resource and your notifications are no longer guaranteed.

Next, regardless of whether you are creating a volatile or durable resource, you'll need to create an object that implements IEnlistmentNotification. IEnlistmentNotification is an interface that defines how the Transaction Manager (TM) talks to you through System.Transactions. For those that are familiar with the 2 Phase Commit (2PC) protocol, you'll see methods that have familiar names. Here's a sample object that implements IEnlistmentNotificaiton:

    class MyEnlistmentNotification : IEnlistmentNotification

    {

        #region IEnlistmentNotification Members

 

        void IEnlistmentNotification.Prepare(IPreparingEnlistment preparingEnlistment, byte[] recoveryInformation)

        {

            // ... prepare unit of work for durable storage ...

            // ... save recoveryInformation ...

            preparingEnlistment.Prepared();

        }

 

        void IEnlistmentNotification.Commit(IEnlistment enlistment)

        {

            // ... log that unit of work is committed ...

            enlistment.EnlistmentDone();

        }

 

        void IEnlistmentNotification.Rollback(IEnlistment enlistment)

        {

            // ... log that unit of work has rolled back ...

            enlistment.EnlistmentDone();

        }

 

        void IEnlistmentNotification.InDoubt()

        {

            // ... log that unit of work is in doubt

        }

 

        #endregion

    }

What is happening here is you are implementing an interface so that System.Transactions can contact you during each phase in a transaction's commit protocol. This gives you a chance to do whatever work you need to do. When you are finished, you use the callback object passed to you to tell System.Transactions that you are done.

Finally, once you have an object that does what you need it to do, you'll want to enlist it in a transaction. Essentially, what you are doing here is registering your IEnlistmentNotification object with System.Transactions so that it knows to notify you when the transaction is committing. The syntax for doing this is:

    ITransaction tx = Transaction.Create();

    IResourceManager myRM = new MyResourceManager();

    IEnlistmentNotification myEN = new MyEnlistmentNotification();

 

    tx.VolatileEnlist(myEN, false);

    tx.DurableEnlist(myRM, myEN, false);

Confused yet? Let’s review.

·        You have a transaction and you want to do transacted work

·        You need to decide whether the work you are about to do is durable or volatile

·        If your work is durable, you need to create an object implementing IResourceManager

·        Either way, you’ll need an object implementing IEnlistmentNotificaiton

·        Use the DurableEnlist and VolatileEnlist methods on the ITransaction object to inform System.Transactions that you want to receive notifications when a transaction is committing

·        When the transaction commits, your object implementing IEnlistmentNotificaiton will get its corresponding methods called

Ta-da! That’s all there is to it. If you have specific questions or need more detail on a step, please visit the newsgroups and post up your requests.

Before I sign off for today, those of you who are really paying attention will have noticed that the DurableEnlist and VolatileEnlist functions have a Boolean parameter at the end called “enlistDuringPrepareRequired.” You may also be wondering what is in the recoveryInformation byte array passed to you when IEnlistmentNotification.Prepare is called. This info and more will be covered in later blog entries so stay tuned!

Whidbey newsgroups are available

It looks like there are newsgroups available for people with specific questions about Whidbey and related technologies. It's slightly hidden becuase it's not in the normal Microsoft.public.* newsgroup space, but there's web access (and instructions on how to use your favorite news reader if you prefer) at:

http://communities.microsoft.com/newsgroups/default.asp?icp=whidbey&slcid=us

So if you're having trouble with Whidbey features, fire away in the newsgroups! MSFT employees are encouraged to check them regularly and will respond to specific inquiries if they can :)

System.Transactions is ready to change the way you write distributed code!

Hi everyone! It's been a while since I started up this blog and for the most part, it's been dormant. This is because the product I work on, System.Transactions, had never been shipped so there were concerns about us talking about it publicly. However, now that Whidbey Beta 1 is available for download, the cat is out of the bag, and it's time to get rockin'!

First order of business is: What is System.Transactions? The answer: System.Transactions is a new framework library that helps you write distributed, transacted applications in .NET. System.Transactions seeks to be fast, lightweight and easy to use.

So, let's jump right in! To get started, you'll need to add “using System.Transactions“ to the top of your source code file (and reference System.Transactions.dll when building your assemblies). Then, to create a transaction, simply do:

ICommittableTransaction myTx = Transaction.Create();

Let's take a few seconds to check out what is going on here. First, you'll notice that instead of using a constructor, I'm calling a static factory method on the Transaction class. This is because System.Transactions implements a layer of abstraction between the user program and the underlying transaction infrastructure. It allows us to update, enhance and extend the underlying implementation in the future without changing any of your code on top.

Next, you'll notice that I am getting back an object that implements the ICommittableTransaction interface. This interface has many of the standard properties and methods you'd expect on a transaction (and probably a few that you're unfamiliar with). The most important one that we'll look at today is the Commit() method. As the initiator of the transaction, your code has control of when the transaction commit will be requested of the transaction manager. Thus, you get an ICommittableTransaction. Other components that you pass your transaction to will naturally want to do work in the transaction, but you will not want them to have commit ability on your transaction. To this end, they are given an ITransaction object; ICommittableTransaction and ITransaction look identical except for one major difference: ICommittableTransaction has the Commit() method.

Now that you have a transaction, you'll most likely want to pass it to other components so that they can do work on it. We have made the objects backing your ICommittableTransaction serializable. This means you can directly pass your transactions through .NET Remoting and your transaction will be automatically marshaled to the other side. No more playing with whereabouts, transaction cookies and/or propagation tokens; everything happens through the magic of the ISerializable interface!

Congratulations, you've just had your first 30 second intro to playing with System.Transactions. I know what you're all thinking: “thanks Mark, this is all well and good, but how do I get some work done in this transaction?” To that, I say: stay tuned for my next installment, where I'll cover the details on how to enlist in the transaction and we'll get down to business - business logic that is :-p

More Posts