ipfs, unixFs & DAG iteration

The way to get all blocks of IPLD

Let’s consider we have an IPLD node and we build a a UnixFs file from it, then how do we read the file content at once:

	node, err := dagRO.Get(ctx, Cid)
	if err != nil {
		return err
	}
	file, err := unixfile.NewUnixfsFile(ctx, dagRO, node)
	if err != nil {
		return err
	}

	r := files.ToFile(file)
	if r == nil {
		return errors.New("file is not regular")
	}
	var buffer [1024000]byte
	var sum int64

	t := time.Now()
	for {
		n, err := r.Read(buffer[:])
		sum += int64(n)
		fmt.Println("read", n, err)
		if err != nil {
			fmt.Println("bad read", err)
			break
		}
	}

As shown above, UnixFs creats a io.reader of our file. Therefore, what happened when we kick reading it?

github.com/ipfs/go-ipld-format.GetNodes at daghelpers.go:47
github.com/ipfs/go-ipld-format.(*NavigableIPLDNode).preload at navipld.go:95
github.com/ipfs/go-ipld-format.(*NavigableIPLDNode).FetchChild at navipld.go:52
github.com/ipfs/go-ipld-format.(*Walker).fetchChild at walker.go:325
github.com/ipfs/go-ipld-format.(*Walker).down at walker.go:299
github.com/ipfs/go-ipld-format.(*Walker).Iterate at walker.go:195
github.com/ipfs/go-unixfs/io.(*dagReader).CtxReadFull at dagreader.go:172
github.com/ipfs/go-unixfs/io.(*dagReader).Read at dagreader.go:144
<autogenerated>:2
main.bs at bs.go:109
main.glob..func1 at stub.go:227
github.com/urfave/cli/v2.(*Command).Run at command.go:161
github.com/urfave/cli/v2.(*App).RunContext at app.go:302
github.com/kingwel-xie/xcli.RunCli at cli.go:259
github.com/kingwel-xie/xcli.RunP2PNodeCLI at commands.go:71
main.main at stub.go:208
runtime.main at proc.go:203
runtime.goexit at asm_amd64.s:1357
 - Async stack trace
runtime.rt0_go at asm_amd64.s:220

The io.reader is actually a dagReader, which will iterate the blocks belonged to this IPLD.

ipld-format.GetNodes will start a routine to get the requested Nodes. Each requested node will be linked to a ‘promise’ channel for further notification of getting result. In the routine, ds.GetMany(ctx, dedupedKeys) will try to get the blcoks from local blockstore, or if failed, from the exchange interface aka. bitswap.


// GetNodes returns an array of 'FutureNode' promises, with each corresponding
// to the key with the same index as the passed in keys
func GetNodes(ctx context.Context, ds NodeGetter, keys []cid.Cid) []*NodePromise {
	// promise has a channel named 'done'
	promises := make([]*NodePromise, len(keys))
	for i := range keys {
		promises[i] = NewNodePromise(ctx)
	}	
	dedupedKeys := dedupeKeys(keys)
	go func() {
		ctx, cancel := context.WithCancel(ctx)
		defer cancel()

		nodechan := ds.GetMany(ctx, dedupedKeys)

		for count := 0; count < len(keys); {
			select {
			case opt, ok := <-nodechan:
				if !ok {
					for _, p := range promises {
						p.Fail(ErrNotFound)
					}
					return
				}
				if opt.Err != nil {
					for _, p := range promises {
						p.Fail(opt.Err)
					}
					return
				}
				nd := opt.Node
				c := nd.Cid()
				for i, lnk_c := range keys {
					if c.Equals(lnk_c) {
						count++
						promises[i].Send(nd)
					}
				}
			case <-ctx.Done():
				return
			}
		}
	}()
	return promises
}

In ipld.FetchChild, it will wait for the ‘promise’ notification:

func (nn *NavigableIPLDNode) FetchChild(ctx context.Context, childIndex uint) (NavigableNode, error) {
	// This function doesn't check that `childIndex` is valid, that's
	// the `Walker` responsibility.

	// If we drop to <= preloadSize/2 preloading nodes, preload the next 10.
	for i := childIndex; i < childIndex+preloadSize/2 && i < uint(len(nn.childPromises)); i++ {
		// TODO: Check if canceled.
		if nn.childPromises[i] == nil {
			nn.preload(ctx, i)
			break
		}
	}
	// Here, waiting for the promise.done channle
	child, err := nn.getPromiseValue(ctx, childIndex)

Done

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IPFS(InterPlanetary File System)是一种分布式文件系统,它的原理基于一些关键概念和技术: 1. 分布式哈希表(DHT):IPFS使用DHT来分布存储和查找文件。DHT是一个分布式的键值存储系统,它将文件的内容的哈希值作为键,将文件的位置信息作为值存储在网络中的不同节点上。这样,文件可以通过哈希值进行查找,而不依赖于中心化的服务器。 2. 哈希链接:IPFS使用内容寻址来确定文件和目录的唯一标识。每个文件和目录都被哈希成一个唯一的标识符,该标识符也被用作文件内容的哈希值。这种方式确保了数据的完整性和不可变性。同时,文件和目录之间可以通过哈希链接进行连接和引用。 3. 分布式存储:IPFS将文件内容进行分块存储,并使用分布式存储的方式将这些块存储在网络中的不同节点上。这样可以实现数据的冗余备份和高可用性。当用户请求文件时,IPFS会根据文件的哈希值查找对应的块,并从最近的节点获取所需的数据。 4. 自我证明:IPFS使用Merkle DAG(有向无环图)来组织和表示文件系统。文件系统中的每个节点都包含了指向其子节点的哈希链接。这种方式不仅支持版本控制和快速增量更新,还可以通过节点之间的哈希链接进行验证和自我证明。 综上所述,IPFS通过使用分布式哈希表、哈希链接、分布式存储和自我证明等技术,实现了去中心化、高可用性、安全性和可扩展性的分布式存储。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值