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(从微观角 ...
随机推荐
- python之排序算法
排序是每个语言都需要学会的,不管是c++.java还是python,套路都是类似的 python中也有自带的排序函数sort,直接使用也可 闲来无事写了几个排序算法,各不相同 1.每次遇到最小的数都交 ...
- WebSocket connection to 'ws://xx:9502/' failed:Error in connection establishment:net::ERR_CONNECTION_TIMED_OUT
1.首先看能否ping通服务器 2.telnet xx 9502之后能不能连通 3.如果连不通有可能是防火墙的问题 可以试试清空防火墙规则,或者关闭防火墙 iptables -F
- SpringBoot一站式启动流程源码分析
一.前言 由上篇文章我们得知,SpringBoot启动时,就是有很简单的一行代码.那我们可以很清楚的看到这行代码的主角便是SpringApplication了,本文我们就来聊一聊这货,来探寻Sprin ...
- Visual Studio 2012 智能提示功能消失解决办法
安装为Visual Studio 2012且更新到了Update3,但是发现智能提示功能用不了,查了一下,网上各种资料,重装VS,连重装系统的都有.不过有很多朋友都是使用命令行重置VS的方法解决了这个 ...
- 《深入理解Java虚拟机》(四)虚拟机性能监控与故障处理工具
虚拟机性能监控与故障处理工具 详解 4.1 概述 本文参考的是周志明的 <深入理解Java虚拟机> 第四章 ,为了整理思路,简单记录一下,方便后期查阅. JDK本身提供了很多方便的JVM性 ...
- asp.net mvc之自定义WebViewPage
采用Razor引擎的View文件最终都会编译成一个WebViewPage类型, 通过自定义WebViewPage,添加相应的属性和方法,你可以很方便的在View里调用, 自定义WebViewPage只 ...
- 【RabbitMQ】3、win7下安装RabbitMQ
RabbitMQ依赖erlang,所以先安装erlang,然后再安装RabbitMQ; erlang,下载地址:http://www.erlang.org/download RabbitMQ,下载地址 ...
- What are the differences between struct and class in C++?
Question: This question was already asked in the context of C#/.Net. Now I'd like to learn the diffe ...
- Java集合之LinkedList源码分析
概述 LinkedLIst和ArrayLIst一样, 都实现了List接口, 但其内部的数据结构不同, LinkedList是基于链表实现的(从名字也能看出来), 随机访问效率要比ArrayList差 ...
- Linux常用基本命令:三剑客命令之-awk格式化动作
我们之前说过,awk是一个超强的文本格式化工具,而本文的printf动作就是经常用来做格式化文本的.使用方式跟c语言的printf差不多. 1,printf默认不会回车换行 ghostwu@dev:~ ...