回顾-雪橇-第三部分

对我来说不同寻常的是,我在复习Sled时有一点停顿。 提醒一下,Sled是一个用Rust编写的嵌入式数据库引擎。 我最后一次停止查看缓冲区管理,但我仍然不太清楚到底发生了什么。 您可以在这里找到第1部分,在这里找到第2部分。

下一个文件是迭代器。 它看起来像是在段和这些段中的消息之间转换。 结构如下:

回顾-雪橇-第三部分

如您所见,日志迭代器保存了一个段的迭代器,对它进行迭代看起来像是要按顺序遍历段中的所有消息。 是的,这是正在做的实际工作:

回顾-雪橇-第三部分

下一个() 我发现方法相当简单。 但是我必须指出:

回顾-雪橇-第三部分

首先是 将需要 电话真的很有趣。 主要是因为你有一个非常明显的方法来进行条件编译,这并不糟糕。 #如果 在代码中通常更不和谐。

其次,我认为将非常重要的函数放在if中的风格会导致代码非常密集。 尤其是如果只在出错时才输入。 我宁愿把它作为一个独立的变量,然后检查它是否失败。

我不明白的是 read_segment 打电话。 在这个方法中,我们有:

回顾-雪橇-第三部分

在分段预告片上也有类似的呼叫。 看起来我们有一个单独的数据文件,但是太大的数据保存在blob文件的外部。

然后我们找到这个家伙,我发现这是一个处理所有不同状态的非常好的方法。

回顾-雪橇-第三部分

迭代器中有趣的部分到此为止。 下一个有趣的部分是日志。 我不得不承认我不喜欢术语日志。 很容易将其与调试日志混淆。

回顾-雪橇-第三部分

事实上,你需要弄清楚在哪里可以得到你将要写的数据的偏移量,这非常有趣。 这是完成大部分工作的方法:

回顾-雪橇-第三部分

请注意,它刚刚保留并完成了操作。 这也是 将数据刷新到磁盘。 由冲洗器或显式调用处理的。 这 准备金() 方法调用 reserve_internal(), 在那里我们发现了这颗宝石:

回顾-雪橇-第三部分

我知道它做什么(条件编译),但是我发现它真的很难理解。 尤其是因为它 相貌 像一个错误 buf 被定义了两次。 这实际上是一个例子 #如果 我认为陈述会更好。

这里的大部分代码是用来管理对iobuf的调用的,我已经回顾过了。 因此,我将跳过前面,看看更有趣的东西,页面缓存。 Sled有一个有趣的行为,它可以将一个页面分割到多个位置,需要一些逻辑来将它们重新组合在一起。 我希望这会很有趣。

文件以此开头:

回顾-雪橇-第三部分

这…需要一段时间来打开包装。 请记住,epoch是一种手动垃圾收集模式,用于没有垃圾收集的并发数据结构。

缓存的ptr) 值是指向节点(在无锁堆栈中)的共享指针,该节点保存具有静态生存期和线程安全的缓存条目,指向必须具有静态生存期和线程安全的一般参数。 还有一个未签名的长音符。

还不知道发生了什么。 但是这是这个结构上的第一个方法:

回顾-雪橇-第三部分
数据同步

那太多了。 缓存条目是具有以下选项的可区分的联合:

回顾-雪橇-第三部分

这里有一些很棒的文档注释,包括一个完整的示例代码,它真正帮助我理解代码中发生了什么。

这里似乎涉及到几个关键方法:

  • 分配(val) —创建一个新页面并写入初始值,获取一个页面id。
  • 链接(id,val) —写入页面id。 简单地写出一个值。
  • get(id) —读取页面id的所有值,并使用实体化器将它们合并为一个值。
  • replace(id,val) —将页面id设置为新值,删除它所具有的所有其他值。

据我所知,这里的想法。 是允许顺序写入数据,但允许快速读取,主要是通过利用固态硬盘的随机读取功能。

我试着遵循代码,但是有点复杂。 特别是,我们有:

回顾-雪橇-第三部分

这将尝试分配一个空闲页面或分配一个新页面。 这里真正让我困惑的一件事是术语“页面”的使用。 我使用的是b+树,其中一个页面实际上是内存的一部分。 这里,它指的是更模糊的东西。 这里的关键点是我不知道 大小 指定了。 但是考虑到你可以把项目链接到页面,这就有意义了。 我只是需要习惯页面!=存储。

所有这些都是一般性的,这一事实也让我们很难了解到底发生了什么。 我在这里迷路了,所以我想我现在就停下来。 敬请期待下一部分!