原子性:实现资源管理器



我正在努力理解以下文档:

  • 实现资源管理器

我发现文档很难阅读和理解,尤其是它给人一种在应用程序级别支持事务的错误感觉。让我们考虑以下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阶段中保留的信息,我们可以重试文件移动操作

相关内容

最新更新