mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 14:52:17 +00:00
libs/db: boltdb: use slice instead of sync.Map (#3633)
for storing batch keys and values in boltDBBatch. NOTE: batch does not have to be safe for concurrent access. Delete may be slow, but given it should not be used often, it's ok. Fixes #3631
This commit is contained in:
parent
a7358bc69f
commit
a076b48202
@ -8,7 +8,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/etcd-io/bbolt"
|
"github.com/etcd-io/bbolt"
|
||||||
)
|
)
|
||||||
@ -150,36 +149,58 @@ func (bdb *BoltDB) Stats() map[string]string {
|
|||||||
// boltDBBatch stores key values in sync.Map and dumps them to the underlying
|
// boltDBBatch stores key values in sync.Map and dumps them to the underlying
|
||||||
// DB upon Write call.
|
// DB upon Write call.
|
||||||
type boltDBBatch struct {
|
type boltDBBatch struct {
|
||||||
buffer *sync.Map
|
buffer []struct {
|
||||||
db *BoltDB
|
k []byte
|
||||||
|
v []byte
|
||||||
|
}
|
||||||
|
db *BoltDB
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBatch returns a new batch.
|
// NewBatch returns a new batch.
|
||||||
func (bdb *BoltDB) NewBatch() Batch {
|
func (bdb *BoltDB) NewBatch() Batch {
|
||||||
return &boltDBBatch{
|
return &boltDBBatch{
|
||||||
buffer: &sync.Map{},
|
buffer: make([]struct {
|
||||||
db: bdb,
|
k []byte
|
||||||
|
v []byte
|
||||||
|
}, 0),
|
||||||
|
db: bdb,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is safe to modify the contents of the argument after Set returns but not
|
||||||
|
// before.
|
||||||
func (bdb *boltDBBatch) Set(key, value []byte) {
|
func (bdb *boltDBBatch) Set(key, value []byte) {
|
||||||
bdb.buffer.Store(string(key), value)
|
bdb.buffer = append(bdb.buffer, struct {
|
||||||
|
k []byte
|
||||||
|
v []byte
|
||||||
|
}{
|
||||||
|
key, value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is safe to modify the contents of the argument after Delete returns but
|
||||||
|
// not before.
|
||||||
func (bdb *boltDBBatch) Delete(key []byte) {
|
func (bdb *boltDBBatch) Delete(key []byte) {
|
||||||
bdb.buffer.Delete(string(key))
|
for i, elem := range bdb.buffer {
|
||||||
|
if bytes.Equal(elem.k, key) {
|
||||||
|
// delete without preserving order
|
||||||
|
bdb.buffer[i] = bdb.buffer[len(bdb.buffer)-1]
|
||||||
|
bdb.buffer = bdb.buffer[:len(bdb.buffer)-1]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: the operation is synchronous (see BoltDB for reasons)
|
// NOTE: the operation is synchronous (see BoltDB for reasons)
|
||||||
func (bdb *boltDBBatch) Write() {
|
func (bdb *boltDBBatch) Write() {
|
||||||
err := bdb.db.db.Batch(func(tx *bbolt.Tx) error {
|
err := bdb.db.db.Batch(func(tx *bbolt.Tx) error {
|
||||||
b := tx.Bucket(bucket)
|
b := tx.Bucket(bucket)
|
||||||
var putErr error
|
for _, elem := range bdb.buffer {
|
||||||
bdb.buffer.Range(func(key, value interface{}) bool {
|
if putErr := b.Put(elem.k, elem.v); putErr != nil {
|
||||||
putErr = b.Put([]byte(key.(string)), value.([]byte))
|
return putErr
|
||||||
return putErr == nil // stop if putErr is not nil
|
}
|
||||||
})
|
}
|
||||||
return putErr
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user