Managed World

Techno-babble from yet another babbler RSS 2.0
# Monday, June 25, 2007

Do you want to have a great job where you get paid to have fun? Well, there is a job opening on the team I work for here at Microsoft.

So, if you want to work for the greatest team in Developer & Platform Evangelism here at Microsoft, check it out. You'll get lots of opportunities to not only drive adoption of Windows Server Virtualization in the community, but you get to work directly with the product team as well. If that sounds exciting, make sure to apply.

Posted in Personal
 #       Comments [0]
# Wednesday, June 20, 2007

The more I work with TxF, the more I realize that our (Microsoft's) coverage of certain KTM topics is sorely lacking. One of those areas is around documentation and samples of managing resource managers (important if you are wanting to investigate programatically the running status of a resource manager).

Sometimes, being an evangelist can be quite fun (or frustrating) because the documentation leaves something to be desired and you can't run to the internet because the only results you get back or to the documentation on MSDN. And of course, since you're on the cutting searching for the control codes online provides you with two results, both pointing back to MSDN. It becomes doubly "interesting" if you are a managed developer because a large number of management-oriented information for KTM is all done through DeviceIoControl (an API that is NOT fun to try to P/Invoke into, especially using certain control codes).

Anyways, that's all beside the point... moving right along.

If you are writing an application to monitor TxF (or even building it into your own application), there are some core "things" that you need to do. One of the first ones (and the one I will cover in this post) is to get a list of transactions in a given resource manager. This is done using the FSCTL_TXFS_LIST_TRANSACTIONS control code.

What structure is DeviceIoControl passing back to us in this instance? A TXFS_LIST_TRANSACTIONS structure. Looking at this structure, we see two fields: NumberOfTransactions and BufferSizeRequired.
That's nice and all, but where is the information about those transactions? The information is stored in a TXFS_LIST_TRANSACTIONS_ENTRY structure.

The trick is that the TXFS_LIST_TRANSACTIONS_ENTRY structure is mentioned nowhere in the documentation for FSCTL_TXFS_LIST_TRANSACTIONS. So how do you get to it? An array of TXFS_LIST_TRANSACTIONS_ENTRY structures are stored in memory after your TXFS_LIST_TRANSACTIONS structure. So assuming you have two running transactions in the given resource manager, you would pass in a pointer to the TXFS_LIST_TRANSACTIONS structure, and here is what the memory would actually look like coming back from DeviceIoControl:

The impact of this is that you need to allocate enough memory for not only your TXFS_LIST_TRANSACTIONS structure, but the array of TXFS_LIST_TRANSACTIONS_ENTRY structures as well. You might notice a little bit of a "chicken and egg" problem here. If I'm using FSCTL_TXFS_LIST_TRANSACTIONS to retrieve the transactions, how could I know how many entry structures to allocate when I don't know how many transactions there are yet?

Well, assuming there are one or more running transactions in the resource manager, you have to call DeviceIoControl with FSCTL_TXFS_LIST_TRANSACTIONS at least twice: once to find out how big of a buffer you need to allocate (read: to calculate how many ENTRY structures to accomodate for), and then another time after allocating the extra memory to have it fill the actual ENTRY structures.

Why do I say "at least" twice? Because, between the time we make our first call and the time we make our second call, more transactions could have appeared and we will have to allocate even more memory. A little bit of a "cat and mouse game," I must say.

If you are a managed developer, this may sound a bit scary. Don't be scared though, it's not too bad (and I know I at least have fun writing this kind of lower-level code :P).

So let's dive right in and look at the code to make this work!

In pseudo-code, this is what we have to do:

------------------------
while (true)
{
     // Deallocate memory from last loop through this

     // Allocate memory for transaction list buffer

     // Call DeviceIoControl with FSCTL_TXFS_LIST_TRANSACTIONS

     // If DeviceIoControl Succeeded

          // Get list of transaction entries after TXFS_LIST_TRANSACTIONS structure
}

// Deallocate any remaining memory
------------------------

Not that bad really. So here it is implemented in native code:

 

    1 #include <windows.h>

    2 #include <tchar.h>

    3 #include <stdio.h>

    4 #include "Winioctl.h"

    5 

    6 int _tmain(int argc, LPTSTR argv)

    7 {

    8     DWORD lastError, bytesReturned;

    9     HANDLE rmDirectory;

   10     TXFS_LIST_TRANSACTIONS *txList = NULL;

   11 

   12     // Get handle to directory where resource manager resides

   13     rmDirectory = CreateFile(TEXT("C:\\"),

   14         GENERIC_READ,

   15         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,

   16         NULL,

   17         OPEN_EXISTING,

   18         FILE_FLAG_BACKUP_SEMANTICS,

   19         NULL);

   20 

   21     if (rmDirectory != INVALID_HANDLE_VALUE)

   22     {

   23         // Get a list of transactions within the given

   24         // resource manager

   25         DWORD neededBufferSize = sizeof(TXFS_LIST_TRANSACTIONS);

   26         while (true)

   27         {

   28             // Deallocate previously allocated memory if we are back

   29             // here after getting back ERROR_MORE_DATA

   30             if (NULL != txList)

   31             {

   32                 delete[] (char*)txList;

   33                 txList = NULL;

   34             }

   35 

   36             // Get the list of running transactions in the RM

   37             txList = (TXFS_LIST_TRANSACTIONS*)new char[neededBufferSize];

   38             if (!DeviceIoControl(rmDirectory,

   39                     FSCTL_TXFS_LIST_TRANSACTIONS,

   40                     NULL,

   41                     0,

   42                     txList,

   43                     neededBufferSize,

   44                     &bytesReturned,

   45                     NULL))

   46             {

   47                 // How did we fail?

   48                 lastError = GetLastError();

   49                 if (lastError == ERROR_MORE_DATA)

   50                 {

   51                     // We need to enlarge the buffer and try again

   52                     neededBufferSize = txList->BufferSizeRequired;

   53                     continue;

   54                 }

   55                 else

   56                 {

   57                     _tprintf(TEXT("Unhandled exception: %u\n"), lastError);

   58                     break;

   59                 }

   60             }

   61             else

   62             {

   63                 _tprintf(TEXT("Transaction Count: %u\n\n"), txList->NumberOfTransactions);

   64 

   65                 // List Tx details

   66                 TXFS_LIST_TRANSACTIONS_ENTRY *txEntry;

   67                 txEntry = (TXFS_LIST_TRANSACTIONS_ENTRY *)((char *)txList + sizeof(TXFS_LIST_TRANSACTIONS));

   68                 for (DWORD i = 0; i < txList->NumberOfTransactions; i++)

   69                 {

   70                     txEntry += i;

   71 

   72                     // Get GUID string

   73                     WCHAR szGuid[40];

   74                     StringFromGUID2(txEntry->TransactionId, (WCHAR *)&szGuid, 40);

   75 

   76                     // Print Tx info

   77                     _tprintf(TEXT("TX %s: %u\n"),

   78                         szGuid,

   79                         txEntry->TransactionState);

   80                 }

   81 

   82                 break;

   83             }

   84         }

   85 

   86         // Any memory left to deallocate?

   87         if (NULL != txList)

   88         {

   89             delete[] (char*)txList;

   90             txList = NULL;

   91         }

   92     }

   93     else

   94     {

   95         _tprintf(TEXT("Unable to get valid handle to Resource Manager\n"));

   96         return 1;

   97     }

   98 

   99     _tprintf(TEXT("\nPress any key to exit...\n"));

  100     getchar();

  101 

  102     return 0;

  103 }

And that's how you do it. It's not the most fun getting in to DeviceIoControl (unless you're a geek like me and enjoying this kind of stuff), but hopefully with this post out there to help it will be easier to find out how to do this since there is a lack of documentation around this area.

In closing, there is some work that needs to be done around making management of kernel-level transactions a lot easier than it is now. In some ways, it is pretty clear that this is still a "1.0" technology. So while you could use the KTM directly for your transaction coordination, I would highly recommend sticking with using DTC for your transaction coordination as it is much more mature from a management perspective (and there are quite a few enhancements with DTC in Vista and Windows Server 2008).

Posted in
 #       Comments [0]
# Friday, June 08, 2007

Well, it's official, again, for now. I just went and canceled my WoW account. With the birth of my first child, I have come to the realization that I don't have enough time for WoW (or, better put, what time I do have should be spent either with my son, or doing a hobby that's creative and produces results I can show off).

What's funny is that I don't miss it in the least bit. At first, I made the decision to stop playing WoW because I simply had to play games where I could pause at a moment's notice to help out with Baby Xander. Then, after several weeks of not playing WoW, I realized I didn't miss it at all and have really enjoyed spending time either with music, or in doing Windows system programming in C (yeah, I'm a geek, I know it).

So, I say farewell to World of Warcraft for the third time in my life. Hopefully this is for good (or until the _next_ expansion pack comes out :P).

P.S. Back to reading my current book, Windows Internals.

Posted in Personal
 #       Comments [4]

Contact

Email Me Send mail to the author(s)

Calendar

<July 2008>
SunMonTueWedThuFriSat
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

About this site

Jason Olson's thoughts on Programming, Games, Music and Life in General

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2008
Jason Olson

Sign In
All Content © 2008, Jason Olson
Theme based on 'Business' created by Christoph De Baene (delarou)