我正在努力理解以下文档:
- 实现资源管理器
我发现文档很难阅读和理解,尤其是它给人一种在应用程序级别支持事务的错误感觉。让我们考虑以下SO参考,其中海报请求在交易中支持File.Move
:
- 如何编写事务来覆盖在数据库中移动文件和插入记录
截至今天,公认的答案是(截断(:
TxFileManager fileMgr = new TxFileManager();
using (TransactionScope scope1 = new TransactionScope())
{
fileMgr.Copy(srcFileName, destFileName);
scope1.Complete();
}
第一件突出的事情是,被接受的答案略微修改了最初的海报请求,在这个答案中更改了行:
fileMgr.Move(srcFileName, destFileName);
进入:
fileMgr.Copy(srcFileName, destFileName);
重要的一点是,底层系统(实际的文件系统(可能不提供原子File.Move
操作(例如,当跨越文件系统边界时(。
我应该如何阅读上述文档,以了解在实施资源管理器时的实际需求是什么?特别是,当底层系统不提供true原子操作时,是否可以实现资源管理器(我们可以以跨文件系统边界的File.Move
操作为例(?
首先,我认为您应该使资源管理器持久化:
https://learn.microsoft.com/en-us/dotnet/api/system.transactions.transaction.enlistdurable?redirectedfrom=MSDN&view=net-5.0#过载
然后,您可以用Prepare
方法(两阶段提交协议的第1阶段(将文件移动操作保存到持久存储(文件、数据库表等(中,格式类似于(Operation:FileMove, SrcFile, DesFile)
,这也有助于以后在进程崩溃时进行恢复:
https://learn.microsoft.com/en-us/dotnet/api/system.transactions.preparingenlistment?view=net-5.0.
public void Prepare(PreparingEnlistment preparingEnlistment)
{
Console.WriteLine("Prepare notification received");
//Validate if the File.Move is valid if it's executed later, then save your file moving operation to a temporary durable storage
//If work finished correctly, reply prepared
preparingEnlistment.Prepared();
// otherwise, do a ForceRollback
preparingEnlistment.ForceRollback();
}
在第2阶段(Commit
(,您可以从持久存储加载操作以实际移动文件(使用重试以确保true
原子操作(
public void Commit(Enlistment enlistment)
{
Console.WriteLine("Commit notification received");
//Read to file moving operation from phase 1 to move the file and retry if the failure is transient
//Declare done on the enlistment when the files have been moved
enlistment.Done();
}
在第1阶段保存文件移动操作的目的是确保:
- 如果在
Commit
阶段发生任何故障(由于跨文件系统边界的File.Move
操作(=>enlistment.Done()
是而不是调用的,因此Commit
方法可以稍后执行,我们仍有阶段1中的信息要重试 - 由于我们的资源管理器是持久的,如果进程在
Commit
方法中崩溃,在恢复过程中,由于Prepare
阶段中保留的信息,我们可以重试文件移动操作