tendermint 跟tikv结合

本文介绍了一个使用TiKV作为存储层与Tendermint区块链平台集成的实现方案。通过详细展示代码片段,阐述了如何在Tendermint中初始化TiKV存储、执行事务操作、获取快照以及实现数据库的基本功能,如Get、Set、Delete等。此外,还涵盖了批处理、迭代器等功能的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import (
    "fmt"
    "github.com/allegro/bigcache"
    "github.com/kooksee/usmint/cmn"
    "github.com/pingcap/tidb/store/tikv"
    "github.com/tendermint/tendermint/libs/log"
    "os"
    "time"
)

var Name = "txs"

var tdb *TikvStore

func Init(logger log.Logger) {
    tikv.MaxConnectionCount = 256

    url := os.Getenv("TIKV")
    if url == "" {
        panic("please init tikv url")
    }

    store, err := tikv.Driver{}.Open(fmt.Sprintf("tikv://%s/pd", url))
    cmn.MustNotErr("TikvStore Init Error", err)

    cache, err := bigcache.NewBigCache(bigcache.DefaultConfig(30 * time.Minute))
    if err != nil {
        panic(fmt.Sprintf("init cache error: %s ", err.Error()))
    }

    tdb = &TikvStore{
        name:  []byte(Name),
        c:     store,
        cache: cache,
    }
}

func GetDb() *TikvStore {
    if tdb == nil {
        panic("please init usdb")
    }
    return tdb
}


import (
    "bytes"
    "context"
    "fmt"
    "github.com/allegro/bigcache"
    "github.com/kooksee/usmint/cmn"
    "github.com/pingcap/tidb/kv"
    "github.com/pingcap/tidb/store/tikv"
    "github.com/tendermint/tendermint/libs/db"
)

type TikvStore struct {
    db.DB
    name  []byte
    c     kv.Storage
    cache *bigcache.BigCache
}

func NewTikvStore(name, url string) *TikvStore {
    tikv.MaxConnectionCount = 256

    // tikv://etcd-node1:port,etcd-node2:port?cluster=1&disableGC=false
    store, err := tikv.Driver{}.Open(fmt.Sprintf("tikv://%s/pd", url))
    cmn.MustNotErr("NewTikvStore Error", err)
    return &TikvStore{
        name: []byte(name),
        c:    store,
    }
}

func (db *TikvStore) withPrefix(key []byte) []byte {
    return append(db.name, key...)
}

func (db *TikvStore) withTxn(fn func(txn kv.Transaction) error) {
    txn, err := db.c.Begin()
    cmn.MustNotErr("tikv store open tx error", err)
    if err := fn(txn); err != nil && !kv.IsErrNotFound(fn(txn)) {
        cmn.MustNotErr("tikv store exec tx error", err)
    }

    cmn.MustNotErr("tikv store exec tx error", fn(txn))
    defer txn.Rollback()
    cmn.MustNotErr("tikv store commit tx error", txn.Commit(context.TODO()))
}

func (db *TikvStore) getSnapshot() kv.Snapshot {
    ss, err := db.c.GetSnapshot(kv.MaxVersion)
    cmn.MustNotErr("tikv store GetSnapshot error", err)
    return ss
}

// Implements DB.
func (db *TikvStore) Get(key []byte) []byte {
    k := db.withPrefix(key)

    rt, err := db.cache.Get(string(k))
    if err == nil && len(rt) != 0 {
        return rt
    }

    ret, err := db.getSnapshot().Get(k)
    if !kv.IsErrNotFound(err) {
        cmn.MustNotErr("tikv store Get error", err)
    }

    if err := db.cache.Set(string(k), ret); err != nil {
        cmn.Log().Error("cache set error", "err", err)
    }

    return ret
}

// Implements DB.
func (db *TikvStore) Has(key []byte) bool {
    ret, err := db.getSnapshot().Get(db.withPrefix(key))
    return (!kv.IsErrNotFound(err)) && (len(ret) != 0)
}

// Implements DB.
func (db *TikvStore) Set(key []byte, value []byte) {
    k := db.withPrefix(key)

    db.withTxn(func(txn kv.Transaction) (err error) {
        if err := db.cache.Set(string(k), value); err != nil {
            cmn.Log().Error("cache error", "err", err)
        }
        return txn.Set(k, value)
    })
}

// Implements DB.
func (db *TikvStore) SetSync(key []byte, value []byte) {
    db.Set(key, value)
}

// Implements DB.
func (db *TikvStore) Delete(key []byte) {
    db.withTxn(func(txn kv.Transaction) (err error) {
        return txn.Delete(db.withPrefix(key))
    })
}

// Implements DB.
func (db *TikvStore) DeleteSync(key []byte) {
    db.Delete(key)
}

// Implements DB.
func (db *TikvStore) Close() {
    cmn.MustNotErr("TikvStore Close Error", db.c.Close())
}

// Implements DB.
func (db *TikvStore) Print() {
}

// Implements DB.
func (db *TikvStore) Stats() map[string]string {
    //keys := []string{
    //  "leveldb.num-files-at-level{n}",
    //  "leveldb.stats",
    //  "leveldb.sstables",
    //  "leveldb.blockpool",
    //  "leveldb.cachedblock",
    //  "leveldb.openedtables",
    //  "leveldb.alivesnaps",
    //  "leveldb.aliveiters",
    //}

    return make(map[string]string)
}

//----------------------------------------
// Batch

// Implements DB.
func (db *TikvStore) NewBatch() db.Batch {
    return &tikvStoreBatch{data: make(map[string][]byte), db: db}
}

type tikvStoreBatch struct {
    db   *TikvStore
    data map[string][]byte
}

// Implements Batch.
func (m *tikvStoreBatch) Set(key, value []byte) {
    m.data[string(key)] = value
}

// Implements Batch.
func (m *tikvStoreBatch) Delete(key []byte) {
    delete(m.data, string(key))
}

// Implements Batch.
func (m *tikvStoreBatch) Write() {
    m.db.withTxn(func(txn kv.Transaction) error {
        for k, v := range m.data {
            if err := txn.Set([]byte(k), v); err != nil {
                return err
            }
        }
        return nil
    })
}

// Implements Batch.
func (m *tikvStoreBatch) WriteSync() {
    m.Write()
}

//----------------------------------------
// Iterator
// NOTE This is almost identical to db/c_level_db.Iterator
// Before creating a third version, refactor.

// Implements DB.
func (db *TikvStore) Iterator(start, end []byte) db.Iterator {
    it, err := db.getSnapshot().Seek(db.withPrefix(start))
    cmn.MustNotErr("TikvStore Iterator Error", err)
    return newTikvStoreIterator(db.name, false, it, db.withPrefix(start), db.withPrefix(end))
}

// Implements DB.
func (db *TikvStore) ReverseIterator(start, end []byte) db.Iterator {
    it, err := db.getSnapshot().SeekReverse(db.withPrefix(start))
    cmn.MustNotErr("TikvStore ReverseIterator Error", err)
    return newTikvStoreIterator(db.name, true, it, db.withPrefix(start), db.withPrefix(end))
}

type tikvStoreIterator struct {
    db.Iterator

    name    []byte
    r       kv.Iterator
    reverse bool
    start   []byte
    end     []byte
}

func newTikvStoreIterator(name []byte, reverse bool, r kv.Iterator, start, end []byte) *tikvStoreIterator {
    return &tikvStoreIterator{
        name:    name,
        r:       r,
        reverse: reverse,
        start:   start,
        end:     end,
    }
}

// Implements Iterator.
func (itr *tikvStoreIterator) Domain() ([]byte, []byte) {
    return itr.start, itr.end
}

// Implements Iterator.
func (itr *tikvStoreIterator) Valid() bool {
    if !itr.r.Valid() {
        return false
    }

    if !itr.reverse {
        if bytes.Compare(itr.r.Key(), itr.end) > 0 {
            return false
        }
    } else {
        if bytes.Compare(itr.r.Key(), itr.start) < 0 {
            return false
        }
    }

    return true
}

// Implements Iterator.
func (itr *tikvStoreIterator) Key() []byte {
    return bytes.TrimPrefix(itr.r.Key(), itr.name)
}

// Implements Iterator.
func (itr *tikvStoreIterator) Value() []byte {
    return itr.r.Value()
}

// Implements Iterator.
func (itr *tikvStoreIterator) Next() {
    cmn.MustNotErr("tikvStoreIterator next error", itr.r.Next())
}

// Implements Iterator.
func (itr *tikvStoreIterator) Close() {
    itr.r.Close()
}

转载于:https://www.cnblogs.com/bergus/p/tendermint-gentikv-jie-he.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值