From ee05bc42304ba9cdadfbe28e5f5bf28c2c36fb0e Mon Sep 17 00:00:00 2001 From: Alvaro Alda Date: Sat, 23 Nov 2019 13:50:35 +0100 Subject: [PATCH] Use prefixes to distingish between conf and logs Closes #3 --- CHANGELOG.md | 4 +++- badger_store.go | 54 +++++++++++++++++++++++++++++--------------- badger_store_test.go | 2 +- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c98ff0..7e3cc62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ -## UNRELEASED +## v0.2.0 (November 23, 2019) IMPROVEMENTS +* Use prefixes to distingish between conf and logs. +* Upgrade Badger version to 1.5.5. * Upgrade Raft version to 1.1.1. ## v0.1.1 (November 19, 2018) diff --git a/badger_store.go b/badger_store.go index ce1be0e..0b3777e 100644 --- a/badger_store.go +++ b/badger_store.go @@ -25,6 +25,10 @@ import ( ) var ( + // Prefix names to distingish between logs and conf + prefixLogs = []byte{0x0} + prefixConf = []byte{0x1} + // ErrKeyNotFound is an error indicating a given key does not exist ErrKeyNotFound = errors.New("not found") ) @@ -175,26 +179,39 @@ func (b *BadgerStore) Close() error { // FirstIndex returns the first known index from the Raft log. func (b *BadgerStore) FirstIndex() (uint64, error) { - return b.firstIndex(false) + var value uint64 + err := b.conn.View(func(txn *badger.Txn) error { + it := txn.NewIterator(badger.IteratorOptions{ + PrefetchValues: false, + Reverse: false, + }) + defer it.Close() + + it.Seek(prefixLogs) + if it.ValidForPrefix(prefixLogs) { + value = bytesToUint64(it.Item().Key()[1:]) + } + return nil + }) + if err != nil { + return 0, err + } + return value, nil } // LastIndex returns the last known index from the Raft log. func (b *BadgerStore) LastIndex() (uint64, error) { - return b.firstIndex(true) -} - -func (b *BadgerStore) firstIndex(reverse bool) (uint64, error) { var value uint64 err := b.conn.View(func(txn *badger.Txn) error { it := txn.NewIterator(badger.IteratorOptions{ PrefetchValues: false, - Reverse: reverse, + Reverse: true, }) defer it.Close() - it.Rewind() - if it.Valid() { - value = bytesToUint64(it.Item().Key()) + it.Seek(append(prefixLogs, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)) + if it.ValidForPrefix(prefixLogs) { + value = bytesToUint64(it.Item().Key()[1:]) } return nil }) @@ -207,7 +224,7 @@ func (b *BadgerStore) firstIndex(reverse bool) (uint64, error) { // GetLog gets a log entry from Badger at a given index. func (b *BadgerStore) GetLog(index uint64, log *raft.Log) error { return b.conn.View(func(txn *badger.Txn) error { - item, err := txn.Get(uint64ToBytes(index)) + item, err := txn.Get(append(prefixLogs, uint64ToBytes(index)...)) if err != nil { switch err { case badger.ErrKeyNotFound: @@ -231,7 +248,7 @@ func (b *BadgerStore) StoreLog(log *raft.Log) error { return err } return b.conn.Update(func(txn *badger.Txn) error { - return txn.Set(uint64ToBytes(log.Index), val.Bytes()) + return txn.Set(append(prefixLogs, uint64ToBytes(log.Index)...), val.Bytes()) }) } @@ -239,7 +256,7 @@ func (b *BadgerStore) StoreLog(log *raft.Log) error { func (b *BadgerStore) StoreLogs(logs []*raft.Log) error { return b.conn.Update(func(txn *badger.Txn) error { for _, log := range logs { - key := uint64ToBytes(log.Index) + key := append(prefixLogs, uint64ToBytes(log.Index)...) val, err := encodeMsgPack(log) if err != nil { return err @@ -261,11 +278,12 @@ func (b *BadgerStore) DeleteRange(min, max uint64) error { Reverse: false, }) - for it.Seek(uint64ToBytes(min)); it.Valid(); it.Next() { - key := make([]byte, 8) + start := append(prefixLogs, uint64ToBytes(min)...) + for it.Seek(start); it.Valid(); it.Next() { + key := make([]byte, 9) it.Item().KeyCopy(key) // Handle out-of-range log index - if bytesToUint64(key) > max { + if bytesToUint64(key[1:]) > max { break } // Delete in-range log index @@ -276,7 +294,7 @@ func (b *BadgerStore) DeleteRange(min, max uint64) error { if err != nil { return err } - return b.DeleteRange(bytesToUint64(key), max) + return b.DeleteRange(bytesToUint64(key[1:]), max) } return err } @@ -292,7 +310,7 @@ func (b *BadgerStore) DeleteRange(min, max uint64) error { // Set is used to set a key/value set outside of the raft log. func (b *BadgerStore) Set(key []byte, val []byte) error { return b.conn.Update(func(txn *badger.Txn) error { - return txn.Set(key, val) + return txn.Set(append(prefixConf, key...), val) }) } @@ -300,7 +318,7 @@ func (b *BadgerStore) Set(key []byte, val []byte) error { func (b *BadgerStore) Get(key []byte) ([]byte, error) { var value []byte err := b.conn.View(func(txn *badger.Txn) error { - item, err := txn.Get(key) + item, err := txn.Get(append(prefixConf, key...)) if err != nil { switch err { case badger.ErrKeyNotFound: diff --git a/badger_store_test.go b/badger_store_test.go index a27a07d..845c6e1 100644 --- a/badger_store_test.go +++ b/badger_store_test.go @@ -35,7 +35,7 @@ func testBadgerStore(t testing.TB) (*BadgerStore, string) { os.RemoveAll(path) // Successfully creates and returns a store - store, err := NewBadgerStore(path) + store, err := New(Options{Path: path, NoSync: true}) if err != nil { t.Fatalf("err: %s", err) }