Skip to content

Commit

Permalink
feat: height limited query with leveldb (#3)
Browse files Browse the repository at this point in the history
* feat: height limited leveldb

* chore: remove redundant interfaces

* fix: reverse iterator creation

* feat: batch write with genesis block

* fix: batch panic in genesis block execution

* feat: override cms

* fix: mutate store's db instance

* feat: append byte for deletion flag into item rather than encode

* feat: optimize key modifying

* feat: separately store real data for sync

* refactor: remove query handling middleware

* refactor: rename function that duplicate hldb with new height

* refactor: remove test function

* refactor: rename key prefixes

* refactor: remove item struct

* refactor: make heleveldb iterator composite tmdb.Iterator

* refactor: shorten key prefix

* feat: add archival cache, flush latest only

* deps: tidy

* refactor: rename branching kvstore function.

* feat: cache last valid key in iterator

* fix: being locked when disable sync

* feat: invert key suffix not to use reverse iterator

* feat: cache last valid value in iterator

* feat: use default store on query without height

* fix: check height from query string. check invalid height.

* refactor: rename prefixing functions

* style: add comments

* feat: remove heleveldb test

Co-authored-by: Jesse Chung <jesse@soob.co>
  • Loading branch information
Jeff Woo and kjessec authored Nov 18, 2021
1 parent 24f0088 commit a2d6343
Show file tree
Hide file tree
Showing 19 changed files with 1,637 additions and 184 deletions.
131 changes: 0 additions & 131 deletions bin/v0.34.x/db/common/types.go

This file was deleted.

7 changes: 7 additions & 0 deletions bin/v0.34.x/db/heleveldb/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package heleveldb

type DriverConfig struct {
Name string
Dir string
Mode int
}
77 changes: 77 additions & 0 deletions bin/v0.34.x/db/heleveldb/leveldb_batch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package heleveldb

import (
"math"

tmdb "github.com/tendermint/tm-db"
"github.com/terra-money/mantlemint-provider-v0.34.x/db/hld"
"github.com/terra-money/mantlemint/lib"
)

var _ hld.HeightLimitEnabledBatch = (*LevelBatch)(nil)

type LevelBatch struct {
height int64
batch tmdb.Batch
mode int
}

func (b *LevelBatch) keyBytesWithHeight(key []byte) []byte {
if b.mode == DriverModeKeySuffixAsc {
return append(prefixDataWithHeightKey(key), lib.UintToBigEndian(uint64(b.height))...)
} else {
return append(prefixDataWithHeightKey(key), lib.UintToBigEndian(math.MaxUint64-uint64(b.height))...)
}

}

func NewLevelDBBatch(atHeight int64, driver *Driver) *LevelBatch {
return &LevelBatch{
height: atHeight,
batch: driver.session.NewBatch(),
mode: driver.mode,
}
}

func (b *LevelBatch) Set(key, value []byte) error {
newKey := b.keyBytesWithHeight(key)

// make fixed size byte slice for performance
buf := make([]byte, 0, len(value)+1)
buf = append(buf, byte(0)) // 0 => not deleted
buf = append(buf, value...)

if err := b.batch.Set(prefixCurrentDataKey(key), buf[1:]); err != nil {
return err
}
if err := b.batch.Set(prefixKeysForIteratorKey(key), []byte{}); err != nil {
return err
}
return b.batch.Set(newKey, buf)
}

func (b *LevelBatch) Delete(key []byte) error {
newKey := b.keyBytesWithHeight(key)

buf := []byte{1}

if err := b.batch.Delete(prefixCurrentDataKey(key)); err != nil {
return err
}
if err := b.batch.Set(prefixKeysForIteratorKey(key), buf); err != nil {
return err
}
return b.batch.Set(newKey, buf)
}

func (b *LevelBatch) Write() error {
return b.batch.Write()
}

func (b *LevelBatch) WriteSync() error {
return b.batch.WriteSync()
}

func (b *LevelBatch) Close() error {
return b.batch.Close()
}
155 changes: 155 additions & 0 deletions bin/v0.34.x/db/heleveldb/leveldb_driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package heleveldb

import (
"fmt"
"math"

tmdb "github.com/tendermint/tm-db"
"github.com/terra-money/mantlemint-provider-v0.34.x/db/hld"
"github.com/terra-money/mantlemint/lib"
)

type Driver struct {
session *tmdb.GoLevelDB
mode int
}

func NewLevelDBDriver(config *DriverConfig) (*Driver, error) {
ldb, err := tmdb.NewGoLevelDB(config.Name, config.Dir)
if err != nil {
return nil, err
}

return &Driver{
session: ldb,
mode: config.Mode,
}, nil
}

func (d *Driver) newInnerIterator(requestHeight int64, pdb *tmdb.PrefixDB) (tmdb.Iterator, error) {
if d.mode == DriverModeKeySuffixAsc {
heightEnd := lib.UintToBigEndian(uint64(requestHeight + 1))
return pdb.ReverseIterator(nil, heightEnd)
} else {
heightStart := lib.UintToBigEndian(math.MaxUint64 - uint64(requestHeight))
return pdb.Iterator(heightStart, nil)
}
}

func (d *Driver) Get(maxHeight int64, key []byte) ([]byte, error) {
if maxHeight == 0 {
return d.session.Get(prefixCurrentDataKey(key))
}
var requestHeight = hld.Height(maxHeight).CurrentOrLatest().ToInt64()
var requestHeightMin = hld.Height(0).CurrentOrNever().ToInt64()

// check if requestHeightMin is
if requestHeightMin > requestHeight {
return nil, fmt.Errorf("invalid height")
}

pdb := tmdb.NewPrefixDB(d.session, prefixDataWithHeightKey(key))

iter, _ := d.newInnerIterator(requestHeight, pdb)
defer iter.Close()

// in tm-db@v0.6.4, key not found is NOT an error
if !iter.Valid() {
return nil, nil
}

value := iter.Value()
deleted := value[0]
if deleted == 1 {
return nil, nil
} else {
if len(value) > 1 {
return value[1:], nil
}
return []byte{}, nil
}
}

func (d *Driver) Has(maxHeight int64, key []byte) (bool, error) {
if maxHeight == 0 {
return d.session.Has(prefixCurrentDataKey(key))
}
var requestHeight = hld.Height(maxHeight).CurrentOrLatest().ToInt64()
var requestHeightMin = hld.Height(0).CurrentOrNever().ToInt64()

// check if requestHeightMin is
if requestHeightMin > requestHeight {
return false, fmt.Errorf("invalid height")
}

pdb := tmdb.NewPrefixDB(d.session, prefixDataWithHeightKey(key))

iter, _ := d.newInnerIterator(requestHeight, pdb)
defer iter.Close()

// in tm-db@v0.6.4, key not found is NOT an error
if !iter.Valid() {
return false, nil
}

deleted := iter.Value()[0]

if deleted == 1 {
return false, nil
} else {
return true, nil
}
}

func (d *Driver) Set(atHeight int64, key, value []byte) error {
// should never reach here, all should be batched in tiered+hld
panic("should never reach here")
}

func (d *Driver) SetSync(atHeight int64, key, value []byte) error {
// should never reach here, all should be batched in tiered+hld
panic("should never reach here")
}

func (d *Driver) Delete(atHeight int64, key []byte) error {
// should never reach here, all should be batched in tiered+hld
panic("should never reach here")
}

func (d *Driver) DeleteSync(atHeight int64, key []byte) error {
return d.Delete(atHeight, key)
}

func (d *Driver) Iterator(maxHeight int64, start, end []byte) (hld.HeightLimitEnabledIterator, error) {
if maxHeight == 0 {
pdb := tmdb.NewPrefixDB(d.session, cCurrentDataPrefix)
return pdb.Iterator(start, end)
}
return NewLevelDBIterator(d, maxHeight, start, end)
}

func (d *Driver) ReverseIterator(maxHeight int64, start, end []byte) (hld.HeightLimitEnabledIterator, error) {
if maxHeight == 0 {
pdb := tmdb.NewPrefixDB(d.session, cCurrentDataPrefix)
return pdb.ReverseIterator(start, end)
}
return NewLevelDBReverseIterator(d, maxHeight, start, end)
}

func (d *Driver) Close() error {
d.session.Close()
return nil
}

func (d *Driver) NewBatch(atHeight int64) hld.HeightLimitEnabledBatch {
return NewLevelDBBatch(atHeight, d)
}

// TODO: Implement me
func (d *Driver) Print() error {
return nil
}

func (d *Driver) Stats() map[string]string {
return nil
}
Loading

0 comments on commit a2d6343

Please sign in to comment.