【问题标题】:Atomicity: Implementing a Resource Manager原子性:实现资源管理器
【发布时间】:2021-06-23 08:02:36
【问题描述】:

我正在尝试理解以下文档:

我发现文档难以阅读和理解,特别是它给人一种在应用程序级别支持事务的错误感觉。让我们考虑以下 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操作为例)时,是否可以实现资源管理器?

【问题讨论】:

  • 当然你可以实现一个没有任何底层事务文件系统的RM。这正是大多数数据库系统(如 SQL Server)所做的,它们不依赖于任何其他东西,只依赖于它们的代码。但这并不意味着成就自己是一项简单的工作。在 Windows 上,最简单的方法是使用 Compensating Resource Manager 重用 DTC 基础结构:docs.microsoft.com/en-us/windows/win32/cossdk/…

标签: c# transactions filesystems atomic


【解决方案1】:

首先,我认为你应该让你的资源管理器持久化:

https://docs.microsoft.com/en-us/dotnet/api/system.transactions.transaction.enlistdurable?redirectedfrom=MSDN&view=net-5.0#overloads

然后您可以使用Prepare 方法(两阶段提交协议的第1 阶段)将您的文件移动操作保存到持久存储(文件、数据库表等),格式为(Operation:FileMove, SrcFile, DesFile),这也如果进程崩溃,有助于稍后恢复:

https://docs.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 方法,我们仍有第一阶段的信息可以重试。
  • 由于我们的资源管理器是持久的,如果在Commit方法中进程崩溃,在恢复过程中我们可以重试文件移动操作,这要归功于Prepare阶段持久化的信息

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-10
    • 1970-01-01
    • 1970-01-01
    • 2016-04-10
    • 1970-01-01
    相关资源
    最近更新 更多