Fabric操作用例Go

如何查看leveldb的数据库内容

2018-08-20  本文已影响909人  CodingCode

如何访问leveldb的数据库内容

当fabric的状态数据库设置为leveldb的时候(也是缺省设置),那么状态数据是存储在leveldb里面的;本文给出一个简单go语言例子,直接读取leveldb的内容。

在peer容器里面leveldb的缺省存着路径是

/var/hyperledger/production/ledgersData/stateLeveldb

包含下面类似内容:

$ ls -l
-rw-r--r-- 1 root root 5122 Aug 20 15:03 000006.log
-rw-r--r-- 1 root root   16 Aug 20 14:56 CURRENT
-rw-r--r-- 1 root root    0 Aug 20 14:45 LOCK
-rw-r--r-- 1 root root 1842 Aug 20 14:56 LOG
-rw-r--r-- 1 root root   41 Aug 20 14:56 MANIFEST-000007

第一步:准备leveldb第三方库
可以直接从官网下载

$ go get github.com/syndtr/goleveldb/leveldb

或者不下载直接引用fabric里面的库也可以,因为fabric包里面已经嵌入了。
路径在:fabric/vendor/github.com/syndtr/goleveldb/leveldb

第二步,编写测试程序如下

$ cat main.go 
package main

import (
    "fmt"
    "flag"
    "bytes"
    "strings"

    "github.com/syndtr/goleveldb/leveldb"
)

var (
    channel     string
    chaincode   string
    key         string

    dbpath      string
)

func init() {
    flag.StringVar(&channel,   "channel",   "mychannel",    "Channel name")
    flag.StringVar(&chaincode, "chaincode", "mychaincode",  "Chaincode name")
    flag.StringVar(&key,       "key",       "",             "Key to query; empty query all keys")

    flag.StringVar(&dbpath,    "dbpath",   "",              "Path to LevelDB")
}

func readKey(db *leveldb.DB, key string) {
    var b bytes.Buffer
    b.WriteString(channel)
    b.WriteByte(0)
    b.WriteString(chaincode)
    b.WriteByte(0)
    b.WriteString(key)

    value, err := db.Get(b.Bytes(), nil)
    if err != nil {
        fmt.Printf("ERROR: cannot read key[%s], error=[%v]\n", key, err)
        return
    }
    fmt.Printf("Key[%s]=[%s]\n", key, string(value))
}

func readAll(db *leveldb.DB) {
    var b bytes.Buffer
    b.WriteString(channel)
    b.WriteByte(0)
    b.WriteString(chaincode)
    prefix := b.String()

    iter := db.NewIterator(nil, nil)
    for iter.Next() {
        key   := string(iter.Key())
        if strings.HasPrefix(key, prefix) {
            value := string(iter.Value())
            fmt.Printf("Key[%s]=[%s]\n", key, value);
        }
    }
    iter.Release()
    //err := iter.Error()
}

func main() {
    flag.Parse()
    if channel == "" || chaincode== "" || dbpath  == "" {
        fmt.Printf("ERROR: Neither of channel, chaincode, key nor dbpath could be empty\n")
        return
    }

    db, err := leveldb.OpenFile(dbpath, nil)
    if err != nil {
        fmt.Printf("ERROR: Cannot open LevelDB from [%s], with error=[%v]\n", dbpath, err);
    }
    defer db.Close()

    if key == "" {
        readAll(db)
    } else {
        readKey(db, key)
    }
}

这个代码例子给出了一个读取单个key,和遍历所有key的例子:
以sample02为例子,如果输入key=a,那么返回a的值,如果没有输入key,那么返回所有的key,在我们例子中只有有a和b两个key。

$  ./testleveldb -key a -dbpath /var/hyperledger/production/ledgersData/stateLeveldb
Key[a]=[��1001]

$ ./testleveldb -dbpath /var/hyperledger/production/ledgersData/stateLeveldb
Key[mychannelmychaincodea]=[��1001]
Key[mychannelmychaincodeb]=[��1999]

多说两句:
我们看到value的值有乱码"��1001",其中1001是值,前面的乱码用在其他用处,例如版本信息等;因为我们使用leveldb的原始工具查询出来的是原始值,而fabric内部是有完整的数据结构类型定义来描述value或者key字段的每一个字节的含义。
从代码里我们也看到key的值实际是由channel+'\0'+chaincode+'\0'+key组成。

另外整个数据库还有其他的信息,不止是用户数据,还有metadata数据。我们遍历的时候,如果打印出所有的key,会看到:

key=[mychannel]
key=[mychannelresourcesconfigtx.CHANNEL_CONFIG_KEY]
key=[mychannellsccmychaincode]
key=[mychannelmychaincodea]
key=[mychannelmychaincodeb]

有包含channel的metadata信息,以及chaincode的metadata信息。(注意虽然我们看到的都是字符串,实际上他们都包含不可显示的字符的)

附录:LevelDB的修改和删除


func DBPutKey(db *leveldb.DB, key string, value []byte) error {
    var k bytes.Buffer
    k.WriteString(key)

    err := db.Put(k.Bytes(), value, nil)
    if err != nil {
        return err
    }
    return nil
}

func DBDelKey(db *leveldb.DB, key string) error {
    var k bytes.Buffer
    k.WriteString(key)

    err := db.Delete(k.Bytes(), nil)
    if err != nil {
        return err
    }
    return nil
}
上一篇下一篇

猜你喜欢

热点阅读