A peek at Longhorn: how TxF integrates

I've written before about the underlying principles behind our transaction management work:

  • our aim is to provide a ubiquitous transaction service, that makes the use of transactions a natural fit for applications seeking reliability or improved concurrency.

In order to accomplish that, we produce transaction services:

  • that provide a simple, trivial to use, transaction demarcation interface;
  • that offer as little overhead as possible; and
  • that do not change the developer experience as either the type of resource or the complexity of the transaction grows.

We've put a lot of effort into these, with the first obvious signs showing up in System.Transactions, available in the current .Net 2.0 betas.

Now, Longhorn is adding support for a transacted file system (TxF), and it would be instructive to take a look at how we approached incorporating suppport into our overall transaction model.  Our goal is that it is just another first class resource -- it should 'just work', to whatever extent possible.

With the upcoming beta you should be able to take an existing application that uses COM+ or System.EnterpriseServices application, or in .Net 2.0, one using System.Transactions, and add transacted file system operations without any great changes to the code.

Here is a sample System.Transactions application (put together by Mike Clark of the video fame):

using System;
using System.IO;
using System.Transactions;

public class TextToFile
{
    [System.Runtime.InteropServices.DllImport("kernel32"),
     System.Security.SuppressUnmanagedCodeSecurityAttribute()]
     internal static extern bool EnterTransactionScope();

    [System.Runtime.InteropServices.DllImport("kernel32"),
     System.Security.SuppressUnmanagedCodeSecurityAttribute()]
     internal static extern bool ExitTransactionScope();

    private const string FILE_NAME_ABORT  = "AbortFile.txt";
    private const string FILE_NAME_COMMIT = "CommitFile.txt";

    public static void Main(String[] args)
    {
        if (File.Exists(FILE_NAME_ABORT))
        {
            Console.WriteLine("{0} already exists.", FILE_NAME_ABORT);
            return;
        }

        Console.WriteLine("Creating TransactionScope");
        try
        {
            using(TransactionScope s = new TransactionScope(
                  TransactionScopeOption.Required, new TransactionOptions(), 
                  EnterpriseServicesInteropOption.Full))
            {
                Console.WriteLine("Calling KTM EnterTransactionScope");           
                EnterTransactionScope();

                Console.WriteLine("Doing File IO");
                StreamWriter sr = File.CreateText(FILE_NAME_ABORT);
                sr.WriteLine ("This is my file.");
                sr.WriteLine ("I can write ints {0} or floats {1}, and so on.",
                    1, 4.2);
                sr.Close();

                Console.WriteLine("Calling KTM ExitTransactionScope");
                ExitTransactionScope();

                // note that the s.Complete is not called so the transaction
                // will roll back.

            }

            using(TransactionScope s = new TransactionScope(
                  TransactionScopeOption.Required, new TransactionOptions(), 
                  EnterpriseServicesInteropOption.Full))
            {
                Console.WriteLine("Calling KTM EnterTransactionScope");           
                EnterTransactionScope();

                Console.WriteLine("Doing File IO");
                StreamWriter sr = File.CreateText(FILE_NAME_COMMIT);
                sr.WriteLine ("This is my file.");
                sr.WriteLine ("I can write ints {0} or floats {1}, and so on.",
                    1, 4.2);
                sr.Close();

                Console.WriteLine("Calling KTM ExitTransactionScope");
                ExitTransactionScope();
 
                s.Complete();
            }
        }
        catch(Exception e)
        {
            Console.WriteLine("UHANDLED EXCEPTION");
            Console.WriteLine(e);
        }
    }
}

Let me point out some things about this sample:

EnterTransactionScope/ExitTransactionScope: These are two new system calls that establish a kernel ambient transaction that is used by file system calls.  Since the file system calls are not specific to transaction behavior, it is important that you establish a kernel ambient transaction around as small a region as possible.  Note that the cost of entering and exiting transaction scopes multiple times is very low -- the only significant work is done on the first one.

EnterpriseServiceInteropOption.Full: This is used as a simple way to establish the internal connections necessary to connect a user mode transaction to a potential kernel ambient transaction.  Internally, this uses COM+ Services Without Components to establish the correct running context.  There are mechanisms that do not end up using COM+, but they do require some extra coding.

Aside from these points, this is just a normal System.Transactions application.  All the features that are otherwise available, from distribution, mutiple thread support, database integration, and so on, continue to work just as they have.

There is equivalent support in COM+/System.EnterpriseServices, and the underlying support is built into the MSDTC interfaces.  Therefore, there's a very equivalent example that can be written in any of those systems.  I'll try to post those examples in the coming days.

 

UPDATE: This approach is no longer appropriate as of the Vista RC update.  See http://pluralsight.com/blogs/jimjohn/archive/2006/08/31/36819.aspx for more information.


Posted Apr 27 2005, 08:41 PM by jim-johnson

Comments

Don Box's Spoutlet wrote JimJohn on Kernel-mode Transactions and TxNTFS
on 04-30-2005 3:42 PM
Sam Gentile's Blog wrote New and Notable 72
on 05-01-2005 3:09 AM
Buddhike de Silva wrote re: A peek at Longhorn: how TxF integrates
on 05-01-2005 5:48 AM
Whew! This mighty cooool! I love this one ;-)
BTW: Could you please explain why we should limit the transaction to a small region? Is it because of the facts like file locks etc...?
Jim Johnson wrote re: A peek at Longhorn: how TxF integrates
on 05-01-2005 8:07 AM
Buddhike,

Glad you like it!

The reason the scope should be around a small region is because the file system calls themselves don't change. Any file system calls that occur within an active kernel transaction scope end up participating in the transaction (or failing if they can't). If you make the region of the scope too big, for instance by including calls to outside functions, you run into the dilemma described in the next article http://pluralsight.com/blogs/jimjohn/archive/2005/04/27/7814.aspx.
On the road to Indigo wrote Transaction-mania!
on 05-02-2005 3:03 PM
Jim Johnson has posted a great article on how to use Longhorn's Kernel Mode Transactions and Transacted...
Eric Fleischman's WebLog wrote I had no idea Jim was blogging
on 05-03-2005 2:11 AM
I just learned that Jim Johnson is blogging. Very cool indeed. I'm a fan of that team's work.I had the...
Randy Holloway Unfiltered wrote Longhorn: How TxF Integrates
on 05-03-2005 2:49 PM
Jim Johnson: "Now, Longhorn is adding support for a transacted file system (TxF), and it would be instructive to take a look at how we approached incorporating suppport into our overall transaction model. Our goal is that it is just...
Antimail wrote Kernel-mode ambient transactions, TxF and System.Transaction
on 05-04-2005 4:43 PM
One really think I love in Longhorn is the new TxF file system (I blogged about it a while back). Jim...
Rui Quintino wrote Links da semana...
on 05-05-2005 8:11 PM
Query wrote re: A peek at Longhorn: how TxF integrates
on 05-11-2005 7:29 AM
Will the Enter/Exit TransactionScope calls get integrated into the managed TransactionScope class at some point? It seems like there's 2 calls to set up the scope and 2 to tear it down in the sample here.
Jim Johnson wrote re: A peek at Longhorn: how TxF integrates
on 05-11-2005 2:37 PM
Speaking for myself, I would expect Enter/ExitTransactionScope should get integrated into the base classes at some point. They would most likely get integrated into the file operation classes (e.g. System.IO) rather than TransactionScope.

I hold this view, because the purpose for the Enter/Exit calls is to change the transaction behavior of the file system operations they surround. They should therefore be tightly bound around the intended file system operations. That leads to an expectation that they'd fit best as part of a transaction-aware file access object model.
Bogdan Nedelcu - my blog wrote Jihm Johnson talks about file system transactions in .NET
on 05-23-2005 3:11 PM
Go read here
Jelle Druyts wrote When ASP.NET 2.0 throws 404's at you...
on 05-23-2005 5:04 PM
Jim Johnson's Blog wrote A simple class to help hooking up System.Transactions and the transacted file system in Longhorn
on 09-13-2005 10:46 PM

Add a Comment

(required)  
(optional)
(required)  
Remember Me?