作者: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的更多相关文章

  1. Derek解读Bytom源码-创世区块

    作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom ...

  2. Derek解读Bytom源码-孤块管理

    作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom ...

  3. Derek解读Bytom源码-Api Server接口服务

    作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom ...

  4. Derek解读Bytom源码-启动与停止

    作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom ...

  5. Derek解读Bytom源码-P2P网络 地址簿

    作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom ...

  6. Derek解读Bytom源码-protobuf生成比原核心代码

    作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom ...

  7. Derek解读Bytom源码-P2P网络 upnp端口映射

    作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom ...

  8. 鸿蒙OS的系统调用是如何实现的? | 解读鸿蒙源码

    本文将首先带您回顾"系统调用"的概念以及它的作用,然后从经典的Hello World开始,逐行代码层层分析--鸿蒙OS的系统调用是如何实现的. 写在前面 9月10号 华为开发者大会 ...

  9. RxJava系列6(从微观角度解读RxJava源码)

    RxJava系列1(简介) RxJava系列2(基本概念及使用介绍) RxJava系列3(转换操作符) RxJava系列4(过滤操作符) RxJava系列5(组合操作符) RxJava系列6(从微观角 ...

随机推荐

  1. JavaScript防篡改对象

    不可扩展对象 默认情况下,所有对象都是可扩展的,使用Object.preventExtensions()方法可以改变这一行为. var person = { name: "Hiram&quo ...

  2. FTP上传心得

    最近出了一个问题就是在本地上传FTP没有一点问题 可是部署到服务器上.上传的时候总是false.解决办法 ftp.enterLocalPassiveMode();boolean storeFile = ...

  3. odoo开发笔记 -- 搜索视图继承扩展

    odoo开发笔记 -- 搜索视图继承扩展

  4. (转)Linux 系统设置 : dmesg 命令详解

    原文:https://blog.csdn.net/yexiangCSDN/article/details/80683246 https://www.cnblogs.com/duanxz/p/34770 ...

  5. oracle使用connect by进行级联查询 树型菜单

    Oracle使用connect by进行级联查询 树型菜单(转) connect by可以用于级联查询,常用于对具有树状结构的记录查询某一节点的所有子孙节点或所有祖辈节点. 来看一个示例,现假设我们拥 ...

  6. Firefox37.0.1+selenium 2.53+python3.6打开浏览器时报错NameError: name 'basestring' is not defined

    环境:Win7      Firefox浏览器版本37.0.1      Python36      Selenium2.53.0 在Pycharm里执行以下3行脚本: from selenium i ...

  7. VM虚拟机扩展硬盘容量

    VM虚拟机扩展硬盘容量 第一步,关闭系统,给虚拟机硬盘增加空间. 第二步,启动系统.查看硬盘大小和分区情况. 第三步,分区. 第四步,格式化分区. 第五步,挂载. 第六步,开机自动挂载. 第一步: 当 ...

  8. centos6.10搭建ELK之elasticsearch6.5.4

    1.环境准备 1.1.安装java环境版本不要低于java8 # java -version java version "1.8.0_191" Java(TM) SE Runtim ...

  9. Maven教程3(依赖管理)

    Maven教程2(Eclipse配置及maven项目) Maven项目,依赖,构建配置,以及构件:所有这些都是要建模和表述的对象.这些对 象通过一个名为项目对象模型(Project Object Mo ...

  10. 如何在github上搭建一个免费的 无限流量的静态网页博客Github pages

    前言: 看到很多相关的教程,但是在实际操作的时候还是遇见了不少问题,这里记录分享一下我的操作流程.免费空间用过很多,博客也用过一些,听说了github后就想试着玩一下这个静态库,感觉挺不错的,操作也比 ...