重点关注
本次学习的主要的工具集是 IPLD\DB\FILE 模块,具体如下:
Files
- go-unixfs : the core ‘filesystem’ logic
- go-mfs : a mutable filesystem editor for unixfs
- go-ipfs-posinfo : helper datatypes for the filestore
- go-ipfs-chunker : file chunkers
Datastores
- go-datastore : datastore interfaces, adapters, and basic implementations
- go-ipfs-ds-help : datastore utility functions
- go-ds-flatfs : a filesystem-based datastore
- go-ds-measure : a metric-collecting database adapter
- go-ds-leveldb : a leveldb based datastore
- go-ds-badger : a badgerdb based datastore
IPLD
- go-block-format : block interfaces and implementations
- go-ipfs-blockstore : blockstore interfaces and implementations
- go-ipld-format : IPLD interfaces
- go-ipld-cbor : IPLD-CBOR implementation
- go-ipld-git : IPLD-Git implementation
- go-merkledag : IPLD-Merkledag implementation (and then some)
学习入口
- core/commands/add.go
添加文件也就是ipfs add
的关键调用栈如下:
Run() -> //core/commands/add.go
UnixfsAPI.Add() -> // core/coreapi/unixfs.go
Adder.AddAllAndPin() -> //core/coreunix/add.go
Adder.addFileNode() ->
Adder.addFile() ->
Adder.addNode() ->
主要完成了三个工作
- 通过
Layout
函数拆散并组成一个符合IPLD
规范的DAG
对象; - 通过
mfs
库生成模拟的目录对象来存放于代表文件的nd
对象的关系; - 把以上两个工作的结果放入
db
;
文件是通过 DAGService.Add
保存到 db
中的,这个调用发生在 Adder.addNode()
中,文件和目录的关系是单独存储的,通过 root.Flush
函数存储 db
,这个调用发生在 Adder.AddAllAndPin
中
// 目录入库的代码片段
func (adder *Adder) AddAllAndPin(file files.Node) (ipld.Node, error) {
...
// get root
mr, err := adder.mfsRoot()
...
var root mfs.FSNode
rootdir := mr.GetDirectory()
root = rootdir
err = root.Flush()
...
TODO LIST
- Layout 的实现原理
- IPLD Node 数据的存储方案
Layout 的实现原理
数据先进行分块,然后把块组合成一棵树,当然也可以称作 DAG,有想无环图本身就是一棵树,这棵树的叶子节点是数据块,默认是 256k 一个块,么一层默认是 174 个节点,树是自上而下填充的,用最终的树根 ID 来代表这个资源;
chunks
关于 chunker.FromString
返回的 Splitter
接口有如下描述:
// A Splitter reads bytes from a Reader and creates "chunks" (byte slices)
// that can be used to build DAG nodes.
type Splitter interface {
Reader() io.Reader
NextBytes() ([]byte, error)
}
这个接口有好几个实现,默认使用的是基于 size
的实现 sizeSplitterv2
//构造函数
func NewSizeSplitter(r io.Reader, size int64) Splitter {
return &sizeSplitterv2{
r: r,
size: uint32(size),
}
}
// 切分函数
func (ss *sizeSplitterv2) NextBytes()