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:
Roman Khimov 2019-10-07 17:08:09 +03:00
parent add9368e9d
commit 48b6a427cf
6 changed files with 81 additions and 4 deletions

View file

@ -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
}) })
} }

View file

@ -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)

View file

@ -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

View file

@ -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)
} }

View file

@ -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
} }

View file

@ -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
} }