<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Spectrum Scale on Hellokitty&#39;s Blog</title>
    <link>https://yangyang233333.github.io/tags/spectrum-scale/</link>
    <description>Recent content in Spectrum Scale on Hellokitty&#39;s Blog</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Thu, 03 Sep 2026 15:53:00 +0800</lastBuildDate>
    <atom:link href="https://yangyang233333.github.io/tags/spectrum-scale/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>分布式文件系统中的 rename 为什么会冲突：从文件到目录</title>
      <link>https://yangyang233333.github.io/posts/distributed-filesystem-rename-conflicts/</link>
      <pubDate>Thu, 03 Sep 2026 15:53:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/distributed-filesystem-rename-conflicts/</guid>
      <description>&lt;p&gt;在本地文件系统里，&lt;code&gt;rename(old, new)&lt;/code&gt; 看起来只是“换个名字”；到了 GPFS（IBM Storage Scale）这类分布式文件系统中，它却是一笔需要跨节点协调的元数据事务。&lt;/p&gt;
&lt;p&gt;核心原因是：&lt;strong&gt;rename 改变的不是文件内容，而是命名空间中的可达关系。&lt;/strong&gt; 一次操作可能同时读写源目录、目标目录、被移动对象以及被覆盖对象。多个客户端若触及同一批元数据，就必须串行化，否则可能出现重名、对象丢失、目录环、错误覆盖，甚至节点间看到不同命名空间。&lt;/p&gt;
&lt;p&gt;本文不讨论某个版本的内部锁名，而从通用实现原理出发，分别分析普通文件和目录的 rename 为什么冲突。&lt;/p&gt;
&lt;h2 id=&#34;一先把-rename-看成一笔事务&#34;&gt;一、先把 rename 看成一笔事务&lt;/h2&gt;
&lt;p&gt;假设执行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rename(&amp;#34;/A/x&amp;#34;, &amp;#34;/B/y&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;抽象到目录项，操作近似为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1. 在目录 A 中查找 x，得到对象 inode X
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2. 在目录 B 中查找 y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3. 若 y 已存在，校验并处理被覆盖对象 Y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4. 从 A 删除目录项 x -&amp;gt; X
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;5. 在 B 创建目录项 y -&amp;gt; X
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6. 更新相关 inode 的时间、链接数或父目录信息
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7. 提交日志，使整个变化原子可恢复
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;POSIX 语义要求其他进程不能看到“源名字已消失、目标名字尚未出现”的中间状态。系统崩溃后，也不能只完成其中一半。因此，分布式文件系统需要把这些修改组织成一个原子事务，并协调所有可能缓存相关元数据的节点。&lt;/p&gt;
&lt;p&gt;可以把参与者概括为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;源父目录 Psrc ─┐
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;源对象     X   ├── rename 元数据事务
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;目标父目录 Pdst ┤
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;目标对象   Y? ─┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;冲突并不等于两个请求使用了相同路径字符串。只要它们需要修改同一个目录、同一个 inode，或需要做相互影响的命名空间判断，就可能冲突。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
