forked from TrueCloudLab/neoneo-go
storage: add Delete method for Batch and Store
It's gonna be used by Storage and Contract interops, both can delete their data.
This commit is contained in:
parent
add9368e9d
commit
48b6a427cf
6 changed files with 81 additions and 4 deletions
|
@ -71,6 +71,14 @@ func (s *BoltDBStore) Get(key []byte) (val []byte, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete implements the Store interface.
|
||||||
|
func (s *BoltDBStore) Delete(key []byte) error {
|
||||||
|
return s.db.Update(func(tx *bbolt.Tx) error {
|
||||||
|
b := tx.Bucket(Bucket)
|
||||||
|
return b.Delete(key)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// PutBatch implements the Store interface.
|
// PutBatch implements the Store interface.
|
||||||
func (s *BoltDBStore) PutBatch(batch Batch) error {
|
func (s *BoltDBStore) PutBatch(batch Batch) error {
|
||||||
return s.db.Batch(func(tx *bbolt.Tx) error {
|
return s.db.Batch(func(tx *bbolt.Tx) error {
|
||||||
|
@ -81,6 +89,12 @@ func (s *BoltDBStore) PutBatch(batch Batch) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for k := range batch.(*MemoryBatch).del {
|
||||||
|
err := b.Delete([]byte(k))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,11 @@ func (s *LevelDBStore) Get(key []byte) ([]byte, error) {
|
||||||
return value, err
|
return value, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete implements the Store interface.
|
||||||
|
func (s *LevelDBStore) Delete(key []byte) error {
|
||||||
|
return s.db.Delete(key, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// PutBatch implements the Store interface.
|
// PutBatch implements the Store interface.
|
||||||
func (s *LevelDBStore) PutBatch(batch Batch) error {
|
func (s *LevelDBStore) PutBatch(batch Batch) error {
|
||||||
lvldbBatch := batch.(*leveldb.Batch)
|
lvldbBatch := batch.(*leveldb.Batch)
|
||||||
|
|
|
@ -10,11 +10,15 @@ import (
|
||||||
type MemoryStore struct {
|
type MemoryStore struct {
|
||||||
mut sync.RWMutex
|
mut sync.RWMutex
|
||||||
mem map[string][]byte
|
mem map[string][]byte
|
||||||
|
// A map, not a slice, to avoid duplicates.
|
||||||
|
del map[string]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// MemoryBatch a in-memory batch compatible with MemoryStore.
|
// MemoryBatch a in-memory batch compatible with MemoryStore.
|
||||||
type MemoryBatch struct {
|
type MemoryBatch struct {
|
||||||
m map[string][]byte
|
m map[string][]byte
|
||||||
|
// A map, not a slice, to avoid duplicates.
|
||||||
|
del map[string]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put implements the Batch interface.
|
// Put implements the Batch interface.
|
||||||
|
@ -23,6 +27,14 @@ func (b *MemoryBatch) Put(k, v []byte) {
|
||||||
copy(vcopy, v)
|
copy(vcopy, v)
|
||||||
kcopy := string(k)
|
kcopy := string(k)
|
||||||
b.m[kcopy] = vcopy
|
b.m[kcopy] = vcopy
|
||||||
|
delete(b.del, kcopy)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete implements Batch interface.
|
||||||
|
func (b *MemoryBatch) Delete(k []byte) {
|
||||||
|
kcopy := string(k)
|
||||||
|
delete(b.m, kcopy)
|
||||||
|
b.del[kcopy] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Len implements the Batch interface.
|
// Len implements the Batch interface.
|
||||||
|
@ -34,6 +46,7 @@ func (b *MemoryBatch) Len() int {
|
||||||
func NewMemoryStore() *MemoryStore {
|
func NewMemoryStore() *MemoryStore {
|
||||||
return &MemoryStore{
|
return &MemoryStore{
|
||||||
mem: make(map[string][]byte),
|
mem: make(map[string][]byte),
|
||||||
|
del: make(map[string]bool),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +63,19 @@ func (s *MemoryStore) Get(key []byte) ([]byte, error) {
|
||||||
// Put implements the Store interface. Never returns an error.
|
// Put implements the Store interface. Never returns an error.
|
||||||
func (s *MemoryStore) Put(key, value []byte) error {
|
func (s *MemoryStore) Put(key, value []byte) error {
|
||||||
s.mut.Lock()
|
s.mut.Lock()
|
||||||
s.mem[string(key)] = value
|
newKey := string(key)
|
||||||
|
s.mem[newKey] = value
|
||||||
|
delete(s.del, newKey)
|
||||||
|
s.mut.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete implements Store interface. Never returns an error.
|
||||||
|
func (s *MemoryStore) Delete(key []byte) error {
|
||||||
|
s.mut.Lock()
|
||||||
|
newKey := string(key)
|
||||||
|
s.del[newKey] = true
|
||||||
|
delete(s.mem, newKey)
|
||||||
s.mut.Unlock()
|
s.mut.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -58,6 +83,9 @@ func (s *MemoryStore) Put(key, value []byte) error {
|
||||||
// PutBatch implements the Store interface. Never returns an error.
|
// PutBatch implements the Store interface. Never returns an error.
|
||||||
func (s *MemoryStore) PutBatch(batch Batch) error {
|
func (s *MemoryStore) PutBatch(batch Batch) error {
|
||||||
b := batch.(*MemoryBatch)
|
b := batch.(*MemoryBatch)
|
||||||
|
for k := range b.del {
|
||||||
|
_ = s.Delete([]byte(k))
|
||||||
|
}
|
||||||
for k, v := range b.m {
|
for k, v := range b.m {
|
||||||
_ = s.Put([]byte(k), v)
|
_ = s.Put([]byte(k), v)
|
||||||
}
|
}
|
||||||
|
@ -81,7 +109,8 @@ func (s *MemoryStore) Batch() Batch {
|
||||||
// newMemoryBatch returns new memory batch.
|
// newMemoryBatch returns new memory batch.
|
||||||
func newMemoryBatch() *MemoryBatch {
|
func newMemoryBatch() *MemoryBatch {
|
||||||
return &MemoryBatch{
|
return &MemoryBatch{
|
||||||
m: make(map[string][]byte),
|
m: make(map[string][]byte),
|
||||||
|
del: make(map[string]bool),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,17 +120,22 @@ func (s *MemoryStore) Persist(ps Store) (int, error) {
|
||||||
s.mut.Lock()
|
s.mut.Lock()
|
||||||
defer s.mut.Unlock()
|
defer s.mut.Unlock()
|
||||||
batch := ps.Batch()
|
batch := ps.Batch()
|
||||||
keys := 0
|
keys, dkeys := 0, 0
|
||||||
for k, v := range s.mem {
|
for k, v := range s.mem {
|
||||||
batch.Put([]byte(k), v)
|
batch.Put([]byte(k), v)
|
||||||
keys++
|
keys++
|
||||||
}
|
}
|
||||||
|
for k := range s.del {
|
||||||
|
batch.Delete([]byte(k))
|
||||||
|
dkeys++
|
||||||
|
}
|
||||||
var err error
|
var err error
|
||||||
if keys != 0 {
|
if keys != 0 || dkeys != 0 {
|
||||||
err = ps.PutBatch(batch)
|
err = ps.PutBatch(batch)
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
s.mem = make(map[string][]byte)
|
s.mem = make(map[string][]byte)
|
||||||
|
s.del = make(map[string]bool)
|
||||||
}
|
}
|
||||||
return keys, err
|
return keys, err
|
||||||
}
|
}
|
||||||
|
@ -110,6 +144,7 @@ func (s *MemoryStore) Persist(ps Store) (int, error) {
|
||||||
// error.
|
// error.
|
||||||
func (s *MemoryStore) Close() error {
|
func (s *MemoryStore) Close() error {
|
||||||
s.mut.Lock()
|
s.mut.Lock()
|
||||||
|
s.del = nil
|
||||||
s.mem = nil
|
s.mem = nil
|
||||||
s.mut.Unlock()
|
s.mut.Unlock()
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -125,4 +125,16 @@ func TestMemoryStorePersist(t *testing.T) {
|
||||||
c, err = ts.Persist(ps)
|
c, err = ts.Persist(ps)
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
assert.Equal(t, 0, c)
|
assert.Equal(t, 0, c)
|
||||||
|
// test persisting deletions
|
||||||
|
err = ts.Delete([]byte("key"))
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
c, err = ts.Persist(ps)
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
assert.Equal(t, 0, c)
|
||||||
|
v, err = ps.Get([]byte("key"))
|
||||||
|
assert.Equal(t, ErrKeyNotFound, err)
|
||||||
|
assert.Equal(t, []byte(nil), v)
|
||||||
|
v, err = ps.Get([]byte("key2"))
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
assert.Equal(t, []byte("value2"), v)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,12 @@ func (s *RedisStore) Get(k []byte) ([]byte, error) {
|
||||||
return []byte(val), nil
|
return []byte(val), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete implements the Store interface.
|
||||||
|
func (s *RedisStore) Delete(k []byte) error {
|
||||||
|
s.client.Del(string(k))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Put implements the Store interface.
|
// Put implements the Store interface.
|
||||||
func (s *RedisStore) Put(k, v []byte) error {
|
func (s *RedisStore) Put(k, v []byte) error {
|
||||||
s.client.Set(string(k), string(v), 0)
|
s.client.Set(string(k), string(v), 0)
|
||||||
|
@ -60,6 +66,9 @@ func (s *RedisStore) PutBatch(b Batch) error {
|
||||||
for k, v := range b.(*MemoryBatch).m {
|
for k, v := range b.(*MemoryBatch).m {
|
||||||
pipe.Set(k, v, 0)
|
pipe.Set(k, v, 0)
|
||||||
}
|
}
|
||||||
|
for k := range b.(*MemoryBatch).del {
|
||||||
|
pipe.Del(k)
|
||||||
|
}
|
||||||
_, err := pipe.Exec()
|
_, err := pipe.Exec()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ type (
|
||||||
// information.
|
// information.
|
||||||
Store interface {
|
Store interface {
|
||||||
Batch() Batch
|
Batch() Batch
|
||||||
|
Delete(k []byte) error
|
||||||
Get([]byte) ([]byte, error)
|
Get([]byte) ([]byte, error)
|
||||||
Put(k, v []byte) error
|
Put(k, v []byte) error
|
||||||
PutBatch(Batch) error
|
PutBatch(Batch) error
|
||||||
|
@ -43,6 +44,7 @@ type (
|
||||||
// Each Store implementation is responsible of casting a Batch
|
// Each Store implementation is responsible of casting a Batch
|
||||||
// to its appropriate type.
|
// to its appropriate type.
|
||||||
Batch interface {
|
Batch interface {
|
||||||
|
Delete(k []byte)
|
||||||
Put(k, v []byte)
|
Put(k, v []byte)
|
||||||
Len() int
|
Len() int
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue