Programming the Windows Transactional File System (TxF)

One of the most obvious uses of the The Transactional File System (TxF) is to write to a single file within the scope of a transaction, eliminating the possibility of the file becoming physically corrupt if the write operation does not complete successfully. However, TxF is not limited to operations on single files, and it is possible to complete transactions that span many files and directories. One of the activities that is notoriously difficult to complete with guaranteed correctness is operations that span multiple files - it is possible to get a long way into a multi-file operation only to have the operation blocked by another process that has an open handle to a file, and the manual rollback can be similarly blocked by other processes that have subsequently opened file handles (virus scanners often open handles on new and modified files for scanning operations), disk space issues and process crashes.

The TxF provides a simple and elegant solution to the problem of operations that span multiple files and directories by providing transaction-aware directory and file enumeration functions and transaction-aware functions for moving and deleting files. File and directory enumeration use a similar handle-based approach to file read and write operations, allowing a simple transition to a transactional model in which only the initial enumeration function that returns the handle needs to have a new Transacted function added. Other existing functions that take the enumeration handle can be used as-is, with the handle storing all relevant transaction information.

The code sample below demonstrates the enumeration of a directory that involves the renaming of all files found being carried out within the scope of the same transaction. After creating a transaction handle, FindFirstFileTransacted is used to begin the directory enumeration in a transacted manner and then the standard FindNextFile and FindClose functions are used with the transaction-aware handle. As the sample code is modifying files within the scope of a transaction to support simple roll-back in the event of an error, it is important that the enumeration is transactional as well so that changes made are visible by the enumeration functions. If the standard FindFirstFile function was used, the transacted operations on the files would not be visible until the transaction is committed.

//create transaction
HANDLE hTransaction = CreateTransaction(NULL, 0, 0, 0, 0, 
 INFINITE, L"Directory Transaction");
 
TCHAR* pDirectoryName = _T("c:TestDir");
 
//add wild-card search character
TCHAR pDirectoryNameSearch[MAX_PATH];
_stprintf_s (pDirectoryNameSearch, MAX_PATH, _T("%s*"), pDirectoryName);
 
//begin enumeration of directory
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFileTransacted(pDirectoryNameSearch, FindExInfoStandard, &ffd, FindExSearchNameMatch, NULL, 0, hTransaction);
 
do
{
 if (hFind != INVALID_HANDLE_VALUE && !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
 {
  TCHAR newFileNameWithPath[MAX_PATH];
 TCHAR originalFileNameWithPath[MAX_PATH];
 
 //get the full name of the file that was found
 if (_stprintf_s (newFileNameWithPath, MAX_PATH, 
  _T("%sTransacatedRename_%s"), pDirectoryName, ffd.cFileName) == -1){
  RollbackTransaction(hTransaction);
  FindClose(hFind);
  CloseHandle(hTransaction);
  return;
 }
 
 //get the name of the new file
 if (_stprintf_s (originalFileNameWithPath, MAX_PATH,
  _T("%s%s"), pDirectoryName, ffd.cFileName) == -1){
  RollbackTransaction(hTransaction);
  FindClose(hFind); 
  CloseHandle(hTransaction);
  return;
 }
 
 //rename the file using MoveFileTransacted
 if (!MoveFileTransacted(originalFileNameWithPath, newFileNameWithPath, NULL, NULL, 0, hTransaction)){
  RollbackTransaction(hTransaction);
  FindClose(hFind); 
  CloseHandle(hTransaction);
  return;
 }
 }
}
while (FindNextFile(hFind, &ffd) != 0);
 
//close the Find handle before committing the transaction
FindClose(hFind);
 
//no errors - commit the transaction
BOOL transCommitResult = CommitTransaction(hTransaction);
 
//close and cleanup
CloseHandle(hTransaction);
hTransaction = NULL;

One of the more interesting aspects of the code sample is that transaction rollback can be used to deal with a wide range of error conditions - everything from the file rename failing to problems with string concatenation operations.

The TxF provides transactional support for a wide range of operations on the file system that span well beyond the ability to write to a single file. As well as guaranteeing data consistency, transactions can dramatically simplify error handling code by simply rolling back all pending operations if errors are detected. When conducting file operations on local NTFS drives in Windows Vista and above, the TxF can be used to great effect to achieve elegant and reliable applications.



Related Articles

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

  • On-demand Event Event Date: October 29, 2014 It's well understood how critical version control is for code. However, its importance to DevOps isn't always recognized. The 2014 DevOps Survey of Practice shows that one of the key predictors of DevOps success is putting all production environment artifacts into version control. In this webcast, Gene Kim discusses these survey findings and shares woeful tales of artifact management gone wrong! Gene also shares examples of how high-performing DevOps …

Most Popular Programming Stories

More for Developers

RSS Feeds