Vista KTM:Vista 及更高版本中的事务管理...






4.73/5 (15投票s)
Vista 内核事务管理器(KTM、TxF、TxR)来自 C++,用于事务性文件和注册表操作,并为 XP 及更早版本提供回滚支持
引言
Windows Vista 中的新型内核事务管理器 (KTM) 允许您执行一系列文件和/或注册表操作,并以一种不可分割的(“全有或全无”)方式生效,称为“事务”。
虽然对最终用户来说是不可见的,但为 Windows 注册表和文件系统添加事务支持是提高健壮性的重要一步,尤其是在极端情况下(例如,停电)。如果您甚至无法“想象”使用不支持事务的数据库,或者不愿意使用 NTFS 而不是 FAT 来格式化磁盘,那么 KTM 就是为您准备的……
文章目录
本文分为以下几个部分
- 新术语定义
- 事务概述
- 您应该使用事务吗?
- Windows Vista 中提供的事务功能
- 资源管理器
- Vista 上事务支持的历史
- 隔离 - 附带示例
- 代码 - 用于使用事务函数 C++ 类,并支持以前版本的 Windows
- 其他 KTM 文章链接
- 文章历史
新术语定义
没有一项新技术是不添加一些新缩略语到词汇表中的。
- TxF (Transactional NTFS) - TxF 允许在 NTFS 文件系统内进行事务性文件系统操作。
- TxR (Transactional Registry) - TxR 允许事务性注册表操作。
- KTM (Kernel Transaction Manager) - “KTM 使应用程序能够使用事务。事务引擎本身位于内核中,但事务可以为内核模式或用户模式事务开发,并且可以在单个主机内或跨分布式主机进行开发……KTM 用于实现 TxF 和 TxR”。
- RM (Resource Manager) - 在 Windows 事务的上下文中,资源管理器可以看作是确保事务按承诺执行的系统(例如,负责在断电时回滚)。TxF、TxR 和 SQL Server 都是资源管理器。
- DTC (Distributed Transaction Coordinator) - 一个协调资源管理器以使您可以在单个事务中使用多个资源管理器(例如,更新 SQL Server 中的表并使用 TxF 进行文件写入)。
- ACID (Atomicity, Consistency, Isolation, and Durability) - 不是新术语,但与事务主题相关。
事务概述
使用事务带来的根本好处是,将您需要考虑的可能结果数量减少到两种(即,完全成功或完全失败);同时让事务资源管理器 (RM) 来处理确保您的操作以“全有或全无”方式执行的繁重任务。
简要的事务历史...
事务的使用起源于数据库。随着时间的推移,事务的使用已缓慢传播到计算机科学领域。
- 1970 年代 数据库 - 数据库已经使用了几十年的事务,并且是计算机系统中事务的最初广泛应用。
- 1993 年 NTFS 文件系统 - NTFS 在 Windows NT 3.1 中引入,相较于 DOS 和 Windows 9x 使用的 FAT 文件系统,NTFS 在可靠性方面有了巨大的改进。
- 2007 年 KTM (请参阅本文其余部分)
- 2007 年事务性 Web 服务 - 随着系统可靠性的降低,使用事务的价值就越大。由于计算机间通信的可靠性较低(与单台计算机上的操作相比),因此事务在此领域非常重要。Windows Communication Foundation (WCF,以前称为“Indigo”) 为您的 Web 服务应用程序和 Windows 带来了分布式事务。
- 20?? 年 事务性内存 - 如果您的数据库、注册表、文件系统和 Web 服务都支持事务,那么为什么不在内存操作上也使用事务呢?虽然仍处于研究阶段,但事务性内存操作是当今备受关注的领域,因为它有望带来的好处之一是缓解使多线程编程如此困难和容易出错的同步问题。这也是 2006 年 1 月的 MSDN Magazine 文章的重点。
您应该使用事务吗?
事务听起来很有趣,但我应该使用它们吗?
在几乎所有情况下,使用事务都能提高软件的健壮性。即使您的软件完全没有错误(请假装),您的应用程序在执行任何一行代码时仍可能失败(例如,停电或一个编写糟糕的驱动程序使整个系统崩溃)。以下是一些将从事务中大大受益的常见场景:
- Windows Update 和 Vista 上的系统保护使用事务。这尤其重要,因为系统组件的局部安装会使整个操作系统不稳定。
- 使用 KTM 功能的安装程序将极大地提升用户体验的质量,因为部分安装的应用程序是最糟糕的用户体验之一。应用程序通常会启动,但之后您可能会遇到奇怪的问题。
- 全部保存 - 想象一下您正在编写 Visual Studio 的 MFC 部分。当用户点击“全部保存”按钮时,您希望同时写入 .rc 文件和 *resource.h* 文件(因为 .rc 文件引用了 *resource.h* 文件中的内容)。这适用于任何具有交叉引用项的文档管理系统。
总而言之,当您执行多个注册表或文件操作时,事务就非常合适,特别是当这些文件或注册表项相互引用时。本质上,事务可以确保在出现问题时,您的应用程序所处理的数据(即注册表项、文件等)都处于一致状态。
Windows Vista 中提供的事务功能
Windows Vista 引入了事务性文件系统和事务性注册表,允许您在一个原子操作中提交对文件系统和/或注册表的更改。如果在事务进行中(即,事务已创建但尚未提交)任何事情中断了事务(例如,您的应用程序崩溃或退出、停电、Windows 崩溃),事务将被回滚。您可以自行决定在代码中回滚事务。您还应该注意,事务随时可能被系统取消(例如,如果系统资源不足)。
本质上,事务执行过程如下面的伪代码所示:
HANDLE hTrans = ::CreateTransaction(...)
// create the transaction
::MoveFileTransacted(oldPath, newPath, ..., hTrans);
// (...and other file and registry function calls)
::CommitTransaction(hTrans);
// OR
::RollbackTransaction(hTrans);
一个MSDN 文章列出了所有新的事务性文件函数。它还列出了一些函数,它们的签名相同,但行为因事务而改变(例如,如果您的文件查找操作是从调用 FindFirstFileTransacted
开始的,那么 FindNextFile
将在文件系统的事务视图上工作)。
资源管理器
在 Windows 事务的上下文中,资源管理器是一个提供事务支持的“系统”。资源管理器负责在出现问题时进行回滚,并确保所有提交都原子化。TxF、TxR 和 SQL Server 都是资源管理器的示例。
编写资源管理器是一个非常高级的主题,超出了本文的范围。有关更多信息,请参阅 MSDN 文章 Writing a Resource Manager 和 Programming Considerations For Writing Resource Managers。
Vista 上事务支持的历史
您是否还记得那些时候,您有一个“绝妙”的想法;您充满热情地开始编码,然后在编码一个小时后意识到,尽管您的想法在简单的情况下非常优雅,但它有可能导致大问题 - 于是您按下“撤销签出”……
Vista 上事务的最初实现(即,在开发期间,当时称为 Longhorn)遵循“隐式”模型。本质上,您创建一个事务,调用所有需要的文件和注册表函数,然后提交(或回滚)事务,如以下伪代码所示:
::CreateTransaction // same as in the explicit model
::SetCurrentTransaction // bind this thread to the transaction
// (so the file and registry calls in the next step know whether to be
// transacted or not (in the case of a multi-threaded app)
// NOTE: SetCurrentTransaction is NOT present in the explicit model
::MoveFile(oldPath, newPath);
// (...and other file and registry function calls)
// call the original file and registry functions
// ALL calls to the various file and registry functions
// will form part of the transaction
::CommitTransaction // same as in explicit model
// OR
::RollbackTransaction // same as in explicit model
大约在 1996 年第三季度,微软决定(字面上)回滚其事务支持的实现,并转向当前的“显式”模型。在显式模型中,您像以前一样调用创建和(提交或回滚)函数。显著的区别在于,显式模型引入了一整套新函数,它们本质上是文件和注册表函数的副本,只是它们还接受一个事务句柄作为参数。
为何改变?
根据 Surendra Verma(Vista 内核团队开发经理,在 2006 年 10 月 27 日的 Channel 9 论坛帖子中)的说法:“……以前,您可以有一个环境事务,并且您所有的 NTFS 和注册表操作都将是事务的一部分。这是一种非常容易上手和开始编程的模型!它的问题在于,也很容易意外地包含您并不真正打算包含在事务中的操作。这在编程的较高层面(COM+ 和 .Net)尤其如此,因为许多这些组件本身就使用 Windows 注册表,而程序员很难知道何时/是否包含了较低级别的注册表操作。因此,我们决定采用显式模型……”
作者还要补充一点,隐式模型不允许您同时打开两个事务(当您调用某些库代码时,这种情况肯定会发生)。
由于这一更改发生在开发周期的相对后期,因此不幸的副作用是,互联网上充斥着大量过时的文章。(例如,2006 年 7 月的MSDN 文章,“因为我们可以”博客等)。故事的寓意是?请认真对待 MSDN 文章顶部的“本文基于 Windows Vista 的预发布版本。本文档中的所有信息均可能发生变更”警告横幅。
隔离 - 附带示例
就像在数据库领域一样,当只有一个进程修改事务涵盖的项目时,事务的效果很容易理解。当有多个进程尝试访问事务涵盖的对象时,规则就会变得稍微复杂一些。
就交互而言,将事务视为一种高级形式的共享权限可能有助于理解。就像您打开文件的方式(例如,使用 FILE_SHARE_READ
和/或 FILE_SHARE_WRITE
)会影响其他进程如何访问该文件一样,事务也是如此。看看例子可能有助于澄清情况……
在下图中,我们可以看到我们的事务在我们的程序内部以及与外部进程的交互效果……
以下是创建图像的操作顺序:
- 在拍摄图像之前,文件名为 *File0000*。
- 在 KTM 演示程序中,我们创建了一个事务。
- 在 KTM 演示程序中,我们重命名了文件。请注意,即使在我们的应用程序内部,文件夹的事务视图也包含了重命名的文件,而未进行事务处理的视图仍然包含原始文件名。我们使用传统的函数名(即
FindFirstFileEx
)检索未进行事务处理的视图,并使用事务性函数名(即FindFirstFileTransacted
,传入我们在上一步调用CreateTransaction
时收到的事务句柄)检索事务性视图。 - 我们在记事本中打开了文件。请注意,此操作成功了。文件的内容是在事务发生之前的 *file0000* 的内容(即,我们看不到在事务范围内发生的文件重命名)。如果我们修改了事务范围内的文件内容,我们也不会看到这些更改。
- 我们尝试在记事本中保存文件。当我们尝试保存时,此操作失败(因为文件 *File0000* 已被事务锁定)。如果我们尝试保存到另一个文件名(例如 *file0001*),则操作会成功。
- 在 Windows 资源管理器中,我们尝试将 *File0000* 重命名为 *FileTryToRenameInExplorer*。此操作失败,资源管理器会显示一个带有原因的错误对话框(即,该文件已被事务锁定)。
代码...
新的 API 总是面临鸡生蛋还是蛋生鸡的问题。由于 Windows Vista 的安装量还不够大,为大多数人单独制作一个“Vista 版本”并不值得,因此新功能在很长一段时间内都不会被广泛使用。提供的代码包含一个 C++ 类 KTMTransaction
(在文件 *KTM.h* 和 *KTM.cpp* 中)。该类的目标是实现两种模式的最佳组合。您的应用程序将在以前版本的 Windows 上运行,但在 Windows Vista 上运行得“更好”。无需更改您的代码,当应用程序在 Windows Vista 上运行时,此类中的函数调用将构成一个事务,而在早期版本的 Windows 上运行时则不会进行事务处理(这也不是什么大问题 - 它现在也是您的代码的工作方式)。
该类封装了所有新的事务性函数,并提供了一个与您熟悉的现有 Win32 函数完全相同的接口。类中的所有函数都接受与同名常规 Win32 函数完全相同的参数(按相同顺序),因此您可以仅使用 MSDN 帮助来了解参数的详细信息。(例如,您只需调用类的 DeleteFile
函数,该类将根据需要调用 ::DeleteFileTransacted
或 ::DeleteFile
)。
该类没有 #include
依赖项,并且所有对事务性函数的函数调用都通过 LoadLibrary
和 GetProcAddress
完成,因此:
- 您不需要 Vista 即可运行您的应用程序,并且
- 您可以在不需要最新 SDK 的情况下构建您的应用程序。
该代码支持 UNICODE
和 ANSI
构建。
相关类的公共部分在此列出。
class KTMTransaction
{
public:
KTMTransaction();
~KTMTransaction();
// causes rollback if you do not call Commit
bool RollBack(); // returns true for success
bool Commit(); // returns true for success
// handle to current transaction
HANDLE GetTransaction();
/////////////////////////////////////////////
// NOTE: The transacted functions take the
// exact same parameters (in the same order) as
// the regular Win32 functions of the same name.
/////////////////////////////////////////////
// File Functions
BOOL CopyFile( ... );
BOOL CopyFileEx( ... );
BOOL CreateDirectoryEx( ... );
BOOL CreateHardLink( ... );
HANDLE CreateFile( ... );
BOOL DeleteFile( ... );
HANDLE FindFirstFileEx( ... );
DWORD GetCompressedFileSize( ... );
BOOL GetFileAttributesEx( ... );
DWORD GetFullPathName( ... );
DWORD GetLongPathName( ... );
BOOL MoveFileEx( ... );
BOOL MoveFileWithProgress( ... );
BOOL RemoveDirectory( ... );
BOOL SetFileAttributes( ... );
// Registry Functions
LONG RegCreateKeyEx( ... );
LONG RegDeleteKey( ... );
LONG RegOpenKeyEx( ... );
};
以下是如何使用该类的示例:
// imagine you have 3 files (a.txt, b.txt, c.txt)
// sitting in a folder
KTMTransaction trans();
trans.DeleteFile( "a.txt" );
trans.DeleteFile( "b.txt" );
// pretend the electricity fails here
trans.DeleteFile( "c.txt" );
trans.Commit();
当电力恢复时会发生什么?在 Windows XP(及更早版本)上,文件 *a.txt* 和 *b.txt* 将被删除,而 *c.txt* 仍将保留。在 Windows Vista 上,所有文件都不会被删除(KTM 将在启动时回滚事务)。
提供了一个示例应用程序(以 Visual Studio 2005 项目构建)。该应用程序应该可以在 Vista 之前的 Windows 版本(例如 2000 或 XP)上运行,但事务按钮在这些操作系统上不起作用。
其他 KTM 相关文章链接
这里有一些关于事务的更多信息的精彩链接:
- Channel 9 视频“Surendra Verma:Vista 事务性文件系统”:必看采访,采访了 KTM 开发人员之一。
- Jason Olson 的“Managed World”博客。尤其是文章:事务资源列表(包含指向十几个其他 KTM 资源的链接)和TxF 的状态(关于托管代码的评论)
- Jim Johnson 的博客:Vista 更新:System.Transactions 与事务性文件系统和注册表的集成
文章历史
- 2007-03-07,版本 1.0,首次发布