> For the complete documentation index, see [llms.txt](https://mit-public-courses-cn-translatio.gitbook.io/mit6-824/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mit-public-courses-cn-translatio.gitbook.io/mit6-824/lecture-11-cache-consistency-frangipani/11.5-yuan-zi-xing-atomicity.md).

# 11.5 原子性（Atomicity）

下一个挑战是确保原子性。当我做了一个复杂的操作，比如说创建一个文件，这里涉及到标识一个新的inode、初始化一个inode（inode是用来描述文件的一小份数据）、为文件分配空间、在目录中为新文件增加一个新的名字，这里有很多步骤，很多数据都需要更新。我们不想任何人看到任何中间的状态，我们希望其他的工作站要么发现文件不存在，要么文件完全存在，但是我们绝不希望它看到中间状态。所以我们希望多个步骤的操作具备原子性。

为了实现原子性，为了让多步骤的操作，例如创建文件，重命名文件，删除文件具备原子性，Frangipani在内部实现了一个数据库风格的事务系统，并且是以锁为核心。并且，这是一个分布式事务系统，我们之后会在这门课看到更多有关分布式事务系统的内容，它在分布式系统中是一种非常常见的需求。

简单来说，Frangipani是这样实现分布式事务的：在我完全完成操作之前，Frangipani确保其他的工作站看不到我的修改。首先我的工作站需要获取所有我需要读写数据的锁，在完成操作之前，我的工作站不会释放任何一个锁。并且为了遵循一致性规则（11.3），将所有修改了的数据写回到Petal之后，我的工作站才会释放所有的锁。比如我将文件从一个目录移到另一个目录，这涉及到修改两个目录的内容，我不想让人看到两个目录都没有文件的状态。为了实现这样的结果，Frangipani首先会获取执行操作所需要的所有数据的锁，

![](/files/-MFxEiAoGJfHNoZjddAF)

之后完成所有的步骤，比如完成所有数据的更新，并将更新写入到Petal，最后释放锁。

![](/files/-MFxFlkYIlakspqTVir0)

因为我们有了锁服务器和缓存一致性协议，我们只需要确保我们在整个操作的过程中持有所有的锁，我们就可以无成本的获得这里的不可分割原子事务。

所以为了让操作具备原子性，Frangipani持有了所有的锁。对于锁来说，这里有一件有意思的事情，Frangipani使用锁实现了两个几乎相反的目标。对于缓存一致性，Frangipani使用锁来确保写操作的结果对于任何读操作都是立即可见的，所以对于缓存一致性，这里使用锁来确保写操作可以被看见。但是对于原子性来说，锁确保了人们在操作完成之前看不到任何写操作，因为在所有的写操作完成之前，工作站持有所有的锁。
