ATL support for Transaction File System

Hello,

 

My name is Weidong Huang, and I am an SDET on the Visual C++ team. Today, I would like to talk a little about ATL support for Transaction File System in Visual Studio 2010.

 

What is Transactional File System?

 

Transactional File System is a new technology first introduced in Windows Vista. It enables you to roll back operations made on the file system and registry.  It is helpful in improving application reliability and data consistency without having to add your own tooling.  By using transactional file systems in VC++ you can treat a set of operations to files and registry as a transaction which can either be completed as a whole or reversed.

 

One example that could use Transactional File System:  A developer creates several new files, writes some information into them, deletes one existing file and wishes to either complete all the operations or do nothing at all.  He could use the Transactional File System to create a transaction, add all the steps into this transaction, commit it when everything works fine, or rollback if there is anything wrong with a step.  

 

 

What is implemented in Visual Studio 2010?

 

1.      Added a new ATL class “CAtlTransactionalManager”:  CAtlTransactionManager is a new class wrapping Transaction File System Windows APIs and provides most of Transactional File System functionalities that are implemented in VC++, including:

·         File Operations: CreateFile, DeleteFile, FindFirstFile, GetFileAttributes, SetFileAttributes, MoveFile.

·         Registry Operations: RegCreateKeyEx, RegDeleteKey, RegOpenKeyEx

 

2.      Added transaction support to Existing Classes and APIs, including:

·         Classes: CFile, CStdioFile, CAtlFile, CFileFind by adding a constructor with TransactionManager as following format:

CFile(CAtlTransactionManager *);

CStdioFile(CAtlTransactionManager *);

CAtlFile(CAtlTransactionManager *);

CFileFind(CAtlTransactionManager *);

·         APIs: AfxRegCreateKey, AfxRegOpenKey, AfxRegDeleteKey by adding a parameter TransactionManager to the API.

 

How to use Transaction File System?

1.      With CAtlTransactionManager:

(1)   Create a CAtlTransactionManager;

(2)   Call functions in CAtlTransationManager to do operations on File or registry

(3)   Call Transaction Manager Commit() to submit the change or RollBack() to reverse the change.

Note: Please refer to Walkthrough Step 2, 3, 4 and 5 for code example.

 

2.      With CFile, CStdioFile, CAtlFile, CFileFind:

(1)   Create a CAtlTransactionManager;

(2)   Create class with the Transaction Manager created in the first step;

(3)   Call class member functions to do operations on File;

(4)   Call Transaction Manager Commit() to submit the change or RollBack() to reverse the change.

Note: Please refer to Walkthrough Step6 for code example.

3.      With Registry APIs:

(1)   Create a CAtlTransactionManager;

(2)   Call API functions with the Transaction Manager created in the first step to do operations on File;

(3)   Call Transaction Manager Commit() to submit the change or RollBack() to reverse the change.

What will happen in operating systems prior to Windows Vista?

 

Transactional File System is only supported in Windows Vista or up level OSes and not available on operating systems prior Vista such as Windows XP and Windows 2003.  Will the application crash if it uses Transactional System Functionality in an operating system that doesn’t support it?  The answer is no.  When creating CAtlTransactionManager, there is an option called “Fallback” which is use to control the behavior in operating systems prior to Vista.  By default, the fallback is TRUE which means you will get the same behavior just as that of non-transactional version if Transaction File System is not supported.  If you set the fallback to FALSE, then the operation will fail when it is not supported. 

 

Walkthrough to use Transaction File System:

 

Here is the walkthrough to help you understand the usage of Transaction File System:

Step1: Create project

1.      Create a default Dialog Type MFC Application call “TransactionalFileSystemDemo”.

2.       Double click the OK button in default dialog (not file dialog) and create the default event handler “void CTransactionalFileSystemDemoDlg::OnBnClickedOk()”. All codes in following steps will be added to this function.

Step2: Use CAtlTransactionManager to Commit File Transaction

 

Add codes

(1)   Add following code to CTransactionalFileSystemDemoDlg::OnBnClickedOk()

                        CAtlTransactionManager tmFileCommit1;

                        HANDLE hFile;

                        hFile = tmFileCommit1.CreateFile(_T(“c:\TransactionFileSystemDemo\file1.txt”), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);

                        CloseHandle(hFile);

                        hFile = tmFileCommit1.CreateFile(_T(“c:\TransactionFileSystemDemo\file2.txt”), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);

                        CloseHandle(hFile);

                        hFile = tmFileCommit1.CreateFile(_T(“c:\TransactionFileSystemDemo\file3.txt”), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);

                        CloseHandle(hFile);

                        WIN32_FIND_DATA nextFile;

                        tmFileCommit1.FindFirstFile(_T(“c:\TransactionFileSystemDemo\file1.txt”), &nextFile);

                        tmFileCommit1.SetFileAttributes(_T(“c:\TransactionFileSystemDemo\file1.txt”), FILE_ATTRIBUTE_READONLY);

                        DWORD dwAttributes = tmFileCommit1.GetFileAttributes(_T(“c:\TransactionFileSystemDemo\file1.txt”));

                        tmFileCommit1.Commit();

Result

                        CAtlTransactionManager tmFileCommit2;

                        tmFileCommit2.DeleteFile(_T(“c:\TransactionFileSystemDemo\file2.txt”));

                        tmFileCommit2.MoveFile(_T(“c:\TransactionFileSystemDemo\file3.txt”), _T(“c:\TransactionFileSystemDemo\file4.txt”));

                        tmFileCommit2.Commit();

                        tmFileCommit2.Close();

Experience:

1.      Create new folder “c:\TransactionFileSystemDemo”;

2.      Build the project, set break point at “tmFileCommit1.Commit()” and “tmFileCommit2.Commit()”.

3.      Debug the application, click the default “OK” button and stop at the first break point;

a.       Watch the value of nextFile and dwAttributes, they should have expected values.

b.      Open Explorer and check folder “c:\TransactionFileSystemDemo”: no file should be created.

4.      Continue debug and go one more step, stop just after “tmFileCommit1.Commit()”

a.       Check folder “c:\TransactionFileSystemDemo”: file1.txt, file2.txt and file3.txt should be created in this folder.

5.      Continue debug and stop at the second break point;

a.       Check folder “c:\TransactionFileSystemDemo”: file1.txt, file2.txt and file3.txt are still there.

6.      Continue debug and go one more step, stop just after “tmFileCommit1.Commit()”

a.        Check folder “c:\TransactionFileSystemDemo”: file1.txt should be deleted and file3.txt should be renamed to file4.txt.