如何访问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
}
网友评论