本页目录

内容寻址存储(Content Addressed Store, CAS)

对比维度 位置寻址存储(Location Addressed Store) 内容寻址存储(Content Addressed Store)
地址 可以是逻辑位置,也可以是物理位置:文件路径、页号、key、数组下标…… 地址由内容计算得出,通常是内容哈希
核心接口 read(location)write(location, blob) put(blob) -> hashget(hash) -> blob
地址来源 外部分配、与内容无关,可复用 内部派生:hash(blob),地址与内容绑定
可变性 位置通常可被覆盖或复用,内容可变,地址可不变 不可变:改内容必须换地址,旧地址永远指向旧内容
更新语义 原地覆盖,或更新目录项、页号映射、指针等 写新 blob,产生新 hash;旧内容仍由旧 hash 可达
并发读 通常需要锁、MVCC、事务隔离来避免读到中间态 并发读友好:读某个 hash 总是完整、一致的旧内容
结构组织 路径树、inode 表、页表、B+ 树、数组、普通 KV 映射等 Merkle DAG:块可以引用其他块的哈希,形成DAG;根哈希代表整个数据集状态
版本共享 通常靠复制、快照、日志、MVCC,共享粒度粗或需额外实现 结构化共享:两个版本之间未修改的子树哈希相同,物理上只存一份
Diff 通常逐文件、逐页、逐行、逐块比较,或依赖日志 快速 Diff:比较两个版本时,从根往下走,遇到相同哈希就停止,差异范围与改动大小相关
去重 通常不天然去重,需要额外索引或机制 天然去重:相同内容哈希相同,重复写入不会产生重复数据
完整性校验 地址不含内容信息,需额外校验和 地址即哈希,读取时可重算校验,天然可验证
删除 / GC 删除位置即可释放,地址可复用 GC 复杂:删除不能直接释放,必须从根遍历,标记所有可达块,再清理不可达块
缓存语义 位置缓存,内容更新后需失效 内容哈希缓存可长期有效;只有引用或根哈希变化才需失效
历史版本 通常只维护“当前状态”,旧版本靠日志、快照、备份恢复 旧 hash / 旧根仍可达,天然保留历史版本
典型场景 文件系统、块设备、数据库页/行存储、内存数组、普通 KV Git、Dolt、IPFS、备份去重、容器镜像、数据版本化

Dolt Noms Block Store1

一切皆chunk。

address: 内容的 SHA512 checksum,取前20字节。

单个文件格式

单个文件格式: noms-block-store-file-structure

  • Footer: Fixed size end of the file which tells us primarily how many Chunks there are stored in the entire file.
  • Index: A deterministically sized (based on the footer) block of the file which contains all address information.
  • ChunkRecords: zero-addressed Chunk Data.

索引格式: noms-block-store-index-structure

  • Prefix Map: This is the first 8 bytes of the Chunk addresses, coupled with an ordinal. The Prefixes are sorted so that we can do a binary search on the map to find a set of addresses which are in the file which have the given prefix. This binary search greatly reduces the search space needed to find the location the chunk requested. The ordinal is used to indicate the offset into Lengths and Suffixes.
  • Lengths: This tracks the length of the Chunk at each ordinal.
  • Address Suffixes: The address at that ordinal, minus the 8 bytes of the prefix which are redundant.

两个主要接口:

  • Contains:文件是否包含了chunk
  • Retrieve:取出chunk

示例:ABC, LMN, and TUV三个keys,chunk length分别为1、4、3

noms-block-store-contains-example1
noms-block-store-contains-example1

contains: 通过prefix map和address suffixes拼接地址。 noms-block-store-contains-example2

retrieve: 计算起始下标,根据长度读取 noms-block-store-retrieve-example1 noms-block-store-retrieve-example2

跨文件读取

理论上最坏要遍历所有文件的索引。

缓解手段

  • memtable缓存
  • GetMany批量查询
  • compaction/conjoin合并文件

Footnotes

  1. https://www.dolthub.com/docs/architecture/storage-engine/block-store/