内容简介:Github地址:Gitee地址:本章介绍Derek解读-Bytom源码分析-持久化存储LevelDB
简介
Github地址: https://github.com/Bytom/bytom
Gitee地址: https://gitee.com/BytomBlockc...
本章介绍Derek解读-Bytom源码分析-持久化存储LevelDB
Golang Version: 1.8
LevelDB介绍
比原链默认使用leveldb数据库。Leveldb是一个google实现的非常高效的kv数据库。LevelDB是单进程的服务,性能非常之高,在一台4核Q6600的CPU机器上,每秒钟写数据超过40w,而随机读的性能每秒钟超过10w。
由于Leveldb是单进程服务,不能同时有多个进程进行对一个数据库进行读写。同一时间只能有一个进程,或一个进程多并发的方式进行读写。
比原链在数据存储层上存储所有链上地址、资产交易等信息。
LevelDB的增删改查操作
LevelDB是google开发的一个高性能K/V存储,本节我们介绍下LevelDB如何对LevelDB增删改查。
package main import ( "fmt" dbm "github.com/tendermint/tmlibs/db" ) var ( Key = "TESTKEY" LevelDBDir = "/tmp/data" ) func main() { db := dbm.NewDB("test", "leveldb", LevelDBDir) defer db.Close() db.Set([]byte(Key), []byte("This is a test.")) value := db.Get([]byte(Key)) if value == nil { return } fmt.Printf("key:%v, value:%v\n", Key, string(value)) db.Delete([]byte(Key)) } // Output // key:TESTKEY, value:This is a test.
以上Output是执行该程序得到的输出结果。
该程序对leveld进行了增删改查操作。dbm.NewDB得到db对象,在/tmp/data目录下会生成一个叫test.db的目录。该目录存放该数据库的所有数据。
db.Set 设置key的value值,key不存在则新建,key存在则修改。
db.Get 得到key中value数据。
db.Delete 删除key及value的数据。
比原链的数据库
默认情况下,数据存储目录在--home参数下的data目录。以Darwin平台为例,默认数据库存储在 $HOME/Library/Bytom/data。
-
accesstoken.db token信息(钱包访问控制权限)
core.db 核心数据库,存储主链相关数据。包括块信息、交易信息、资产信息等
discover.db 分布式网络中端到端的节点信息 -
trusthistory.db
txdb.db 存储交易相关信息
txfeeds.db 目前比原链代码版本未使用该功能,暂不介绍
wallet.db 本地钱包数据库。存储用户、资产、交易、utox等信息
以上所有数据库都由database模块管理
比原数据库接口
在比原链中数据持久化存储由database模块管理,但是持久化相关接口在protocol/store.go中
type Store interface { BlockExist(*bc.Hash) bool GetBlock(*bc.Hash) (*types.Block, error) GetStoreStatus() *BlockStoreState GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) LoadBlockIndex() (*state.BlockIndex, error) SaveBlock(*types.Block, *bc.TransactionStatus) error SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint) error }
- BlockExist 根据hash判断区块是否存在
- GetBlock 根据hash获取该区块
- GetStoreStatus 获取store的存储状态
- GetTransactionStatus 根据hash获取该块中所有交易的状态
- GetTransactionsUtxo 缓存与输入txs相关的所有utxo
- GetUtxo(*bc.Hash) 根据hash获取该块内的所有utxo
- LoadBlockIndex 加载块索引,从db中读取所有block header信息并缓存在内存中
- SaveBlock 存储块和交易状态
- SaveChainStatus 设置主链的状态,当节点第一次启动时,节点会根据key为blockStore的内容判断是否初始化主链。
比原链数据库key前缀
database/leveldb/store.go
var ( blockStoreKey = []byte("blockStore") blockPrefix = []byte("B:") blockHeaderPrefix = []byte("BH:") txStatusPrefix = []byte("BTS:") )
- blockStoreKey 主链状态前缀
- blockPrefix 块信息前缀
- blockHeaderPrefix 块头信息前缀
- txStatusPrefix 交易状态前缀
GetBlock查询块过程分析
database/leveldb/store.go
func (s *Store) GetBlock(hash *bc.Hash) (*types.Block, error) { return s.cache.lookup(hash) }
database/leveldb/cache.go
func (c *blockCache) lookup(hash *bc.Hash) (*types.Block, error) { if b, ok := c.get(hash); ok { return b, nil } block, err := c.single.Do(hash.String(), func() (interface{}, error) { b := c.fillFn(hash) if b == nil { return nil, fmt.Errorf("There are no block with given hash %s", hash.String()) } c.add(b) return b, nil }) if err != nil { return nil, err } return block.(*types.Block), nil }
GetBlock函数最终会执行lookup函数。lookup函数总共操作有两步:
- 从缓存中查询hash值,如果查到则返回
- 如果为从缓存中查询到则回调fillFn回调函数。fillFn回调函数会将从磁盘上获得到块信息存储到缓存中并返回该块的信息。
fillFn回调函数实际上调取的是database/leveldb/store.go下的GetBlock,它会从磁盘中获取block信息并返回。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
物联网导论(第2版)
刘云浩 / 科学出版社 / 2013-8 / 45.00元
物联网是一个基于互联网、传统电信网等信息承载体,让所有能够被独立寻址的普通物理对象实现互联互通的网络。它具有普通对象设备化、自治终端互联化和普适服务智能化三个重要特征。 《物联网工程专业系列教材:物联网导论(第2版)》从物联网的感知识别层、网络构建层、管理服务层和综合应用层这四层分别进行阐述,深入浅出地为读者拨开萦绕于物联网这个概念的重重迷雾,引领求知者渐渐步入物联网世界,帮助探索者把握第三......一起来看看 《物联网导论(第2版)》 这本书的介绍吧!