以太坊系列 - 数据持久化(1) 底层实现 -- 单机数据库LevelDB

LevelDB

LevelDB是google开源的KV(key-value,存储的数据都是kv的形式)单机数据库,官方版本是C++,比特币使用的是c++版本:

https://github.com/google/leveldb

以太坊使用的是go语言版本:

https://github.com/syndtr/goleveldb

go安装leveldb

go get github.com/syndtr/goleveldb/leveldb

LevelDB内的核心数据结构是一个SkipList(跳跃列表是一种随机化数据结构,基于并联的链表,其效率可比拟二叉查找树).

LevelDb整体而言是个高写入系统,SkipList在其中应该也起到了很重要的作用。Redis为了加快插入操作,也使用了SkipList来作为内部实现数据结构。

性能方面:顺序写、随机写速度快,顺序读快,随机读性能一般

缓存

  • memory
  • 只读memory
  • 文件存储

读数据

先在memory里找,再到只读memory里找,最后再到存储文件中找,而且是按层级,按每层的key范围,一层一层地找

写数据

分为写新数据、更新数据和删除数据

leveldb为了效率考虑(如果删除数据和更新数据用传统的方式做的话,需要查找所有数据库找到原始key,效率比较低),此三种情况统统使用插入数据的方式,删除数据是写一个删除标志,更新数据是写一样key带不同的value

为了减少leveldb的交互,写数据的时候一般会以Batch进行,就是先往batch里写一堆数据,然后再统一把这个Batch写到leveldb。

即便是单个kv的写入,leveldb内部也是使用batch来写入的,但是这个batch也会即时写入memory和log

Compaction 归档的过程

compaction是把数据一级一级的往下写,leveldb实现了minor compaction和major compaction

minor compaction,leveldb里面的mCompaction goroutine做的事情,就是把只读memory中的数据写入到level 0文件中

major compaction,leveldb里面的tCompaction goroutine做的事情,就是把低层的level文件合并写入高层的level文件中

单元测试

ethdb/database_test.go //测试经geth封装的leveldb的操作

clique案例

  • Snapshot.loadSnapshot :
    blob, err := db.Get(append([]byte(“clique-”), hash[:]…))
  • Snapshot.store :
    return db.Put(append([]byte(“clique-”), s.Hash[:]…), blob)

你可能感兴趣的:(源码分析,以太坊系列)