herald.go/db/db.go

360 lines
7.5 KiB
Go
Raw Normal View History

package db
import (
2021-12-11 23:22:45 +01:00
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"log"
2021-12-24 13:17:53 +01:00
"os"
2021-12-11 23:22:45 +01:00
"github.com/lbryio/hub/db/prefixes"
"github.com/linxGnu/grocksdb"
)
2021-12-11 23:22:45 +01:00
type IterOptions struct {
2021-12-13 00:35:16 +01:00
FillCache bool
Prefix []byte
2021-12-13 00:35:16 +01:00
Start []byte //interface{}
Stop []byte //interface{}
IncludeStart bool
IncludeStop bool
IncludeKey bool
IncludeValue bool
RawKey bool
RawValue bool
2021-12-11 23:22:45 +01:00
}
2021-12-13 00:35:16 +01:00
// NewIterateOptions creates a defualt options structure for a db iterator.
2021-12-11 23:22:45 +01:00
func NewIterateOptions() *IterOptions {
return &IterOptions{
2021-12-13 00:35:16 +01:00
FillCache: false,
2021-12-15 00:40:04 +01:00
Prefix: []byte{},
2021-12-13 00:35:16 +01:00
Start: nil,
Stop: nil,
IncludeStart: true,
IncludeStop: false,
IncludeKey: true,
IncludeValue: false,
RawKey: false,
RawValue: false,
2021-12-11 23:22:45 +01:00
}
}
func (o *IterOptions) WithFillCache(fillCache bool) *IterOptions {
o.FillCache = fillCache
return o
}
2021-12-15 00:40:04 +01:00
func (o *IterOptions) WithPrefix(prefix []byte) *IterOptions {
o.Prefix = prefix
return o
}
2021-12-11 23:22:45 +01:00
func (o *IterOptions) WithStart(start []byte) *IterOptions {
o.Start = start
return o
}
func (o *IterOptions) WithStop(stop []byte) *IterOptions {
o.Stop = stop
return o
}
2021-12-13 00:35:16 +01:00
func (o *IterOptions) WithIncludeStart(includeStart bool) *IterOptions {
o.IncludeStart = includeStart
return o
}
func (o *IterOptions) WithIncludeStop(includeStop bool) *IterOptions {
o.IncludeStop = includeStop
return o
}
func (o *IterOptions) WithIncludeKey(includeKey bool) *IterOptions {
o.IncludeKey = includeKey
return o
}
func (o *IterOptions) WithIncludeValue(includeValue bool) *IterOptions {
o.IncludeValue = includeValue
return o
}
2021-12-15 00:40:04 +01:00
func (o *IterOptions) WithRawKey(rawKey bool) *IterOptions {
o.RawKey = rawKey
return o
}
func (o *IterOptions) WithRawValue(rawValue bool) *IterOptions {
o.RawValue = rawValue
return o
}
2021-12-24 13:17:53 +01:00
func Iter(db *grocksdb.DB, opts *IterOptions) <-chan *prefixes.PrefixRowKV {
ch := make(chan *prefixes.PrefixRowKV)
2021-12-14 14:14:42 +01:00
ro := grocksdb.NewDefaultReadOptions()
ro.SetFillCache(opts.FillCache)
it := db.NewIterator(ro)
it.Seek(opts.Prefix)
if opts.Start != nil {
it.Seek(opts.Start)
2021-12-14 14:14:42 +01:00
}
stopIteration := func(key []byte) bool {
if key == nil {
return false
}
if opts.Stop != nil &&
(bytes.HasPrefix(key, opts.Stop) || bytes.Compare(opts.Stop, key[:len(opts.Stop)]) < 0) {
2021-12-14 14:14:42 +01:00
return true
} else if opts.Start != nil &&
bytes.Compare(opts.Start, key[:len(opts.Start)]) > 0 {
2021-12-14 14:14:42 +01:00
return true
} else if opts.Prefix != nil && !bytes.HasPrefix(key, opts.Prefix) {
2021-12-14 14:14:42 +01:00
return true
}
return false
}
go func() {
defer it.Close()
defer close(ch)
if !opts.IncludeStart {
2021-12-14 14:14:42 +01:00
it.Next()
}
var prevKey []byte = nil
for ; !stopIteration(prevKey) && it.Valid(); it.Next() {
2021-12-14 14:14:42 +01:00
key := it.Key()
keyData := key.Data()
keyLen := len(keyData)
value := it.Value()
valueData := value.Data()
valueLen := len(valueData)
var outKey interface{} = nil
var outValue interface{} = nil
var err error = nil
2021-12-14 14:14:42 +01:00
// We need to check the current key is we're not including the stop
// key.
if !opts.IncludeStop && stopIteration(keyData) {
2021-12-14 14:14:42 +01:00
return
}
// We have to copy the key no matter what because we need to check
// it on the next iterations to see if we're going to stop.
newKeyData := make([]byte, keyLen)
copy(newKeyData, keyData)
if opts.IncludeKey && !opts.RawKey {
//unpackKeyFnValue := reflect.ValueOf(KeyUnpackFunc)
//keyArgs := []reflect.Value{reflect.ValueOf(newKeyData)}
//unpackKeyFnResult := unpackKeyFnValue.Call(keyArgs)
//outKey = unpackKeyFnResult[0].Interface()
2021-12-24 13:17:53 +01:00
_, outKey, err = prefixes.UnpackGenericKey(newKeyData)
if err != nil {
log.Println(err)
}
} else if opts.IncludeKey {
outKey = newKeyData
2021-12-14 14:14:42 +01:00
}
// Value could be quite large, so this setting could be important
// for performance in some cases.
if opts.IncludeValue {
2021-12-14 14:14:42 +01:00
newValueData := make([]byte, valueLen)
copy(newValueData, valueData)
//unpackValueFnValue := reflect.ValueOf(ValueUnpackFunc)
//valueArgs := []reflect.Value{reflect.ValueOf(newValueData)}
//unpackValueFnResult := unpackValueFnValue.Call(valueArgs)
//outValue = unpackValueFnResult[0].Interface()
if !opts.RawValue {
2021-12-24 13:17:53 +01:00
_, outValue, err = prefixes.UnpackGenericValue(newKeyData, newValueData)
if err != nil {
log.Println(err)
}
} else {
outValue = newValueData
}
2021-12-14 14:14:42 +01:00
}
key.Free()
value.Free()
2021-12-24 13:17:53 +01:00
ch <- &prefixes.PrefixRowKV{
Key: outKey,
Value: outValue,
2021-12-13 00:35:16 +01:00
}
prevKey = newKeyData
2021-12-11 23:22:45 +01:00
}
}()
return ch
}
func GetDB(name string) (*grocksdb.DB, error) {
opts := grocksdb.NewDefaultOptions()
2021-12-13 00:35:16 +01:00
// db, err := grocksdb.OpenDb(opts, name)
db, err := grocksdb.OpenDbAsSecondary(opts, name, "asdf")
2021-12-11 23:22:45 +01:00
if err != nil {
return nil, err
}
return db, nil
}
2021-12-24 13:17:53 +01:00
func ReadPrefixN(db *grocksdb.DB, prefix []byte, n int) []*prefixes.PrefixRowKV {
2021-12-11 23:22:45 +01:00
ro := grocksdb.NewDefaultReadOptions()
ro.SetFillCache(false)
it := db.NewIterator(ro)
defer it.Close()
2021-12-24 13:17:53 +01:00
res := make([]*prefixes.PrefixRowKV, n)
2021-12-11 23:22:45 +01:00
var i = 0
it.Seek(prefix)
for ; it.Valid(); it.Next() {
key := it.Key()
value := it.Value()
2021-12-24 13:17:53 +01:00
res[i] = &prefixes.PrefixRowKV{
2021-12-11 23:22:45 +01:00
Key: key.Data(),
Value: value.Data(),
}
key.Free()
value.Free()
i++
if i >= n {
break
}
}
return res
}
2021-12-12 18:40:51 +01:00
func OpenDB(name string, start string) int {
2021-12-07 12:45:18 +01:00
// Read db
opts := grocksdb.NewDefaultOptions()
db, err := grocksdb.OpenDb(opts, name)
if err != nil {
log.Println(err)
}
2021-12-12 01:24:37 +01:00
defer db.Close()
ro := grocksdb.NewDefaultReadOptions()
ro.SetFillCache(false)
2021-12-07 12:45:18 +01:00
log.Println(db.Name())
2021-12-07 12:45:18 +01:00
it := db.NewIterator(ro)
defer it.Close()
var i = 0
2021-12-12 18:40:51 +01:00
it.Seek([]byte(start))
2021-12-11 23:22:45 +01:00
for ; it.Valid(); it.Next() {
2021-12-07 12:45:18 +01:00
key := it.Key()
value := it.Value()
2021-12-12 01:24:37 +01:00
fmt.Printf("Key: %v Value: %v\n", hex.EncodeToString(key.Data()), hex.EncodeToString(value.Data()))
2021-12-07 12:45:18 +01:00
key.Free()
value.Free()
i++
}
if err := it.Err(); err != nil {
log.Println(err)
}
return i
}
2021-12-16 17:42:36 +01:00
func OpenAndWriteDB(db *grocksdb.DB, options *IterOptions, out string) {
2021-12-16 17:42:36 +01:00
ch := Iter(db, options)
var i = 0
2021-12-12 18:40:51 +01:00
for kv := range ch {
2021-12-24 13:17:53 +01:00
key := kv.Key.(*prefixes.UTXOKey)
value := kv.Value.(*prefixes.UTXOValue)
keyMarshal, err := json.Marshal(key)
if err != nil {
log.Println(err)
2021-12-13 00:35:16 +01:00
}
valMarshal, err := json.Marshal(value)
if err != nil {
log.Println(err)
2021-12-13 00:35:16 +01:00
}
log.Println(string(keyMarshal), string(valMarshal))
2021-12-13 00:35:16 +01:00
i++
}
}
2021-12-24 13:17:53 +01:00
func ReadWriteRawN(db *grocksdb.DB, options *IterOptions, out string, n int) {
options.RawKey = true
options.RawValue = true
ch := Iter(db, options)
file, err := os.Create(out)
if err != nil {
log.Println(err)
return
}
defer file.Close()
var i = 0
for kv := range ch {
log.Println(i)
if i >= n {
return
}
key := kv.Key.([]byte)
value := kv.Value.([]byte)
keyHex := hex.EncodeToString(key)
valueHex := hex.EncodeToString(value)
log.Println(keyHex)
log.Println(valueHex)
file.WriteString(keyHex)
file.WriteString(",")
file.WriteString(valueHex)
file.WriteString("\n")
i++
}
}
func GenerateTestData() {
dbVal, err := GetDB("/mnt/d/data/wallet/lbry-rocksdb/")
if err != nil {
log.Fatalln(err)
}
// options := &IterOptions{
// FillCache: false,
// Prefix: []byte{prefixes.HashXUTXO},
// Start: nil,
// Stop: nil,
// IncludeStart: true,
// IncludeStop: false,
// IncludeKey: true,
// IncludeValue: true,
// RawKey: true,
// RawValue: true,
// }
options := NewIterateOptions()
options.WithRawKey(true).WithRawValue(true)
options.WithPrefix([]byte{prefixes.HashXUTXO})
ReadWriteRawN(dbVal, options, "./resources/hashx_utxo.csv", 10)
}