资讯专栏INFORMATION COLUMN

Derek解读Bytom源码-持久化存储LevelDB

Eminjannn / 641人阅读

摘要:函数总共操作有两步从缓存中查询值,如果查到则返回如果为从缓存中查询到则回调回调函数。回调函数会将从磁盘上获得到块信息存储到缓存中并返回该块的信息。回调函数实际上调取的是下的,它会从磁盘中获取信息并返回。

作者:Derek

简介

Github地址:https://github.com/Bytom/bytom

Gitee地址:https://gitee.com/BytomBlockc...

本章介绍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
", 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信息并返回。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/24257.html

相关文章

  • Derek解读Bytom源码分析-久化存储LevelDB

    摘要:函数总共操作有两步从缓存中查询值,如果查到则返回如果为从缓存中查询到则回调回调函数。回调函数会将从磁盘上获得到块信息存储到缓存中并返回该块的信息。回调函数实际上调取的是下的,它会从磁盘中获取信息并返回。 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc... 本章介绍Dere...

    GitChat 评论0 收藏0
  • Derek解读Bytom源码-创世区块

    摘要:作者简介地址地址本章介绍解读源码分析创世区块作者使用操作系统,其他平台也大同小异创世区块介绍区块链里的第一个区块创被称为创世区块。在比原链中创世区块被硬编码到中,每一个比原节点都始于同一个创世区块,这能确保创世区块不会被改变。 作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/By...

    王军 评论0 收藏0
  • Derek解读Bytom源码-启动与停止

    摘要:只有当触发了或才能终止进程退出。退出时执行如下操作会将挖矿功能停止,网络停止等操作。 作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc... 本章介绍bytom代码启动、节点初始化、及停止的过程 作者使用MacOS操作系统,其他平台也大同小异Golang V...

    Godtoy 评论0 收藏0
  • Derek解读Bytom源码-Api Server接口服务

    摘要:首先读取请求内容,解析请求,接着匹配相应的路由项,随后调用路由项的回调函数来处理。每一个路由项由请求方法和回调函数组成将监听地址作为参数,最终执行开始服务于外部请求创建对象首先,实例化对象。我们可以看到一条项由和对应的回调函数组成。 作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com...

    GitCafe 评论0 收藏0
  • Derek解读Bytom源码-P2P网络 地址簿

    摘要:作者简介地址地址本章介绍代码网络中地址簿作者使用操作系统,其他平台也大同小异介绍用于存储网络中保留最近的对端节点地址在下,默认的地址簿路径存储在地址簿格式地址类型在中存储的地址有两种标识新地址,不可靠地址未成功连接过。 作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomB...

    Kahn 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<