Atomic write, 揭开你的面纱

论坛 期权论坛     
选择匿名的用户   2021-5-22 18:37   642   0
<div style="top:0px">

</div>
<em>2016-04-25 晶格思维</em>
<a class="rich_media_meta rich_media_meta_link rich_media_meta_nickname" href="" id="post-user" rel="noopener noreferrer" target="_blank"> 晶格思维</a>
<span class="rich_media_meta rich_media_meta_text rich_media_meta_nickname"> 晶格思维</span>
<div class="profile_container" id="js_profile_qrcode" style="">
<div class="profile_inner">
  <strong class="profile_nickname">晶格思维</strong>
  <img alt="" class="profile_avatar" id="js_profile_qrcode_img" src="">
  <p class="profile_meta"><label class="profile_meta_label">微信号</label> <span class="profile_meta_value"> crystalwit</span></p>
  <p class="profile_meta"><label class="profile_meta_label">功能介绍</label> <span class="profile_meta_value"> 从行业视角介绍IT领域特别是存储领域的新技术、新趋势,强调刨根问底和联想类比。</span></p>
</div>
<span class="profile_arrow_wrp" id="js_profile_arrow_wrp"><em class="profile_arrow arrow_out"></em></span>
</div>
<div class="rich_media_content" id="js_content">
<p>最早听到Atomic write这个功能是从Fusion-io的DFS文件系统对于数据库的性能优化上。从字面意义上来说,它的意思是IO写入操作相对于其他操作来说,是一个单步的动作。实际上,对于一个IO操作来说,在SSD内部的实现是一个复杂的过程,需要牵涉到很多步骤,因此通常的IO操作并不是一个单步的动作。为了支持原子写,SSD需要通过一个特殊的设计,保证从用户的角度来看,好像这个动作是单步的。</p>
<p>为了说明这个问题,先看一个多线程程序设计中常见的多线程同步问题。在这个例子中,设置了32个线程对同一个变量进行设置。</p>
<p><br> </p>
<p>unsigned int bitmap &#61; 0;</p>
<p><br> </p>
<p>void *setbit_thread(void *opt)</p>
<p>{<!-- --></p>
<p>    bitmap |&#61; 1UL &lt;&lt; pos;</p>
<p>    return NULL;</p>
<p>}</p>
<p><br> </p>
<p>int main(int argc, void **argv)</p>
<p>{<!-- --></p>
<p>    pthread_t thread[32];</p>
<p>    for (int i &#61; 0; i !&#61; 32; i&#43;&#43;)</p>
<p>    {<!-- --></p>
<p>        pthread_create(&amp;thread[i], NULL, &amp;setbit_thread, (void *)i);</p>
<p>    }</p>
<p>    for (int i &#61; 0; i !&#61; 32; i&#43;&#43;)</p>
<p>    {<!-- --></p>
<p>        void *ret;</p>
<p>        pthread_join(&amp;thread[i], &amp;ret);</p>
<p>    }</p>
<p>    printf(&#34;bitmap &#61; %08x\n&#34;, bitmap);</p>
<p>    return 0;</p>
<p>}</p>
<p>关键的一步是bitmap |&#61; 1UL &lt;&lt; pos。这一步在CPU实际运行时是分成了几步来做。因为多线程同时操作这个变量,并且该操作不是原子的,所以最后的运行结果并不一定是FFFFFFFF。为了解决这个问题,可以引用GCC __sync_fetch_and_or来实现对于bitmap的原子操作。该操作在不同的体系结构下(例如x86,ARM)的实现方式不相同,但是GCC屏蔽了底层实现的细节,通过这样的内建函数来完成支持对内存原子操作的语义。</p>
<p>再回过头来看原子写。由于设备中实际操作原子写IO并不是真正原子的,所以原子写并不是在所有的意义上都是保持原子含义的。那么到底原子写是针对哪些操作而言保持了原子性?</p>
<p>在NVMe1.0标准中,详细规定了控制器操作原子性的精确含义。在NVMe 1.2标准中,又补充增加了对于Namespace名字空间的原子写操作。此外,在NVMe组织内部,对于IO操作和其他操作的原子性的精确定义也正在逐步落地,期望会在未来的NVMe 1.2后续版本中体现出来。</p>
<p>通俗的说,如果设备支持原子写能力,那么一次写入的IO相对于其他的IO(不管是其他的写请求还是读请求)都是原子的,不允许读出一半新写入的数据,另外一半是旧的数据。当然,为了简化设备端支持原子写的实现难度,在协议中约定,只有IO请求满足一定条件时才是原子的。NVMe中,对于控制器的原子操作能力定义包括了3个方面的内容:</p>
<p>1、Atomic Write Unit Normal (AWUN)</p>
<p>2、Atomic Write Unit Power Fail (AWUPF)</p>
<p>3、Atomic Compare and Write Unit (ACWU)</p>
<p>AWUN是通常意义的原子写中IO的最大允许粒度,如果IO请求长度小于等于该值所对应的长度,那么这个IO请求相对于其他同样满足该约束的请求是原子的。在NVMe上保存的数据和IO读请求读到的数据必须是齐整的。</p>
<p>在协议中剧了这样一个例子,两个写请求同时发给设备(同时的意思并不是说这两个请求在填入NVMe发送队列时是同时的。对每个命令来说,从写入到NVMe发送队列到从NVMe接收队列收到指令完成这段时间称为该指令的生命周期,那么同时指的是两个指令的生命周期有重叠)。请求A写入的范围是0~3,B的范围是1~4。那么下面的表中列出了最终结
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP