Derek解读Bytom源码-持久化存储LevelDB
作者:Derek
简介
Github地址:https://github.com/Bytom/bytom
Gitee地址:https://gitee.com/BytomBlockchain/bytom
本章介绍Derek解读-Bytom源码分析-持久化存储LevelDB
作者使用MacOS操作系统,其他平台也大同小异
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信息并返回。
Derek解读Bytom源码-持久化存储LevelDB的更多相关文章
- Derek解读Bytom源码-创世区块
作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom ...
- Derek解读Bytom源码-孤块管理
作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom ...
- Derek解读Bytom源码-Api Server接口服务
作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom ...
- Derek解读Bytom源码-启动与停止
作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom ...
- Derek解读Bytom源码-P2P网络 地址簿
作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom ...
- Derek解读Bytom源码-protobuf生成比原核心代码
作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom ...
- Derek解读Bytom源码-P2P网络 upnp端口映射
作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom ...
- 鸿蒙OS的系统调用是如何实现的? | 解读鸿蒙源码
本文将首先带您回顾"系统调用"的概念以及它的作用,然后从经典的Hello World开始,逐行代码层层分析--鸿蒙OS的系统调用是如何实现的. 写在前面 9月10号 华为开发者大会 ...
- RxJava系列6(从微观角度解读RxJava源码)
RxJava系列1(简介) RxJava系列2(基本概念及使用介绍) RxJava系列3(转换操作符) RxJava系列4(过滤操作符) RxJava系列5(组合操作符) RxJava系列6(从微观角 ...
随机推荐
- 课程四(Convolutional Neural Networks),第四 周(Special applications: Face recognition & Neural style transfer) —— 1.Practice quentions
[解释] This allows us to learn to predict a person’s identity using a softmax output unit, where the n ...
- vue脚手架构
我们是用Eclipse开发的,所以用vue开始时,要进行代理,不然访问不到服务器,所以就需要配置一下 dev context 里面写的是代理的接口,就是以这些接口开头的,如果没有就往里写一下,pro ...
- Kafka实战-实时日志统计流程
1.概述 在<Kafka实战-简单示例>一文中给大家介绍来Kafka的简单示例,演示了如何编写Kafka的代码去生产数据和消费数据,今天给大家介绍如何去整合一个完整的项目,本篇博客我打算为 ...
- Spring的Java配置方式—@Configuration和@Bean实现Java配置
Java配置是Spring4.x推荐的配置方式,可以完全替代xml配置. 1.@Configuration 和 @BeanSpring的Java配置方式是通过 @Configuration 和 @Be ...
- MongoDB的aggregate聚合
聚合框架中常用的几个操作: $project:修改输入文档的结构.可以用来重命名.增加或删除域,也可以用于创建计算结果以及嵌套文档.(显示的列,相当遇sql 的) $match:用于过滤数据,只输出符 ...
- Mongodb 命令清单
一.数据库常用命令 # 切换/创建数据库 PRIMARY> use yourDB; #当创建一个集合(table)的时候会自动创建当前数据库# 查询所有数据库 PRIMARY> show ...
- jQuery 获取对象 根据属性、内容匹配, 还有表单元素匹配
指定元素中包含 id 属性的, 如: $("span[id]") 代码如下: <span id="span1" name="S1"&g ...
- MSSQL存储过程应用
1.原始表inoutinfo 2.现在想输入时间范围和操作类型输出对应的结果 2.1创建存储过程 create proc selecttype@type nvarchar(10),@starttime ...
- (转)Linux企业运维人员最常用150个命令汇总
目录 线上查询及帮助命令(2个) 文件和目录操作命令(18个) 查看文件及内容处理命令(21个) 文件压缩及解压缩命令(4个) 信息显示命令(11个) 搜索文件命令(4个) 用户管理命令(10个) 基 ...
- session持久化到sqlserver
每次想使用都会忘记单词,所幸记录下来.简单步骤记录. 第一步:找到cmd目录 输入:cd C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727 进入该目录. 第二 ...