2018-03-17 11:53:21 +00:00
|
|
|
package storage
|
|
|
|
|
2018-03-21 16:11:04 +00:00
|
|
|
import (
|
2021-09-24 13:00:13 +00:00
|
|
|
"bytes"
|
|
|
|
"sort"
|
2019-09-18 15:20:41 +00:00
|
|
|
"strings"
|
2019-08-27 13:32:52 +00:00
|
|
|
"sync"
|
2021-07-18 13:32:10 +00:00
|
|
|
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util/slice"
|
2018-03-21 16:11:04 +00:00
|
|
|
)
|
|
|
|
|
2018-03-17 11:53:21 +00:00
|
|
|
// MemoryStore is an in-memory implementation of a Store, mainly
|
|
|
|
// used for testing. Do not use MemoryStore in production.
|
|
|
|
type MemoryStore struct {
|
2019-09-26 17:49:02 +00:00
|
|
|
mut sync.RWMutex
|
2018-03-17 11:53:21 +00:00
|
|
|
mem map[string][]byte
|
2019-10-07 14:08:09 +00:00
|
|
|
// A map, not a slice, to avoid duplicates.
|
|
|
|
del map[string]bool
|
2018-03-17 11:53:21 +00:00
|
|
|
}
|
|
|
|
|
2019-10-22 14:56:03 +00:00
|
|
|
// MemoryBatch is an in-memory batch compatible with MemoryStore.
|
2018-03-17 11:53:21 +00:00
|
|
|
type MemoryBatch struct {
|
2019-10-07 17:25:33 +00:00
|
|
|
MemoryStore
|
2018-03-17 11:53:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Put implements the Batch interface.
|
|
|
|
func (b *MemoryBatch) Put(k, v []byte) {
|
2021-08-11 15:53:18 +00:00
|
|
|
b.MemoryStore.put(string(k), slice.Copy(v))
|
2019-10-07 14:08:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Delete implements Batch interface.
|
|
|
|
func (b *MemoryBatch) Delete(k []byte) {
|
2021-08-11 15:53:18 +00:00
|
|
|
b.MemoryStore.drop(string(k))
|
2018-03-17 11:53:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewMemoryStore creates a new MemoryStore object.
|
|
|
|
func NewMemoryStore() *MemoryStore {
|
|
|
|
return &MemoryStore{
|
2019-09-26 17:49:02 +00:00
|
|
|
mem: make(map[string][]byte),
|
2019-10-07 14:08:09 +00:00
|
|
|
del: make(map[string]bool),
|
2018-03-17 11:53:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get implements the Store interface.
|
|
|
|
func (s *MemoryStore) Get(key []byte) ([]byte, error) {
|
2019-09-26 17:49:02 +00:00
|
|
|
s.mut.RLock()
|
|
|
|
defer s.mut.RUnlock()
|
2019-10-07 14:05:53 +00:00
|
|
|
if val, ok := s.mem[string(key)]; ok {
|
2018-03-17 11:53:21 +00:00
|
|
|
return val, nil
|
|
|
|
}
|
|
|
|
return nil, ErrKeyNotFound
|
|
|
|
}
|
|
|
|
|
2019-10-07 17:13:59 +00:00
|
|
|
// put puts a key-value pair into the store, it's supposed to be called
|
|
|
|
// with mutex locked.
|
|
|
|
func (s *MemoryStore) put(key string, value []byte) {
|
|
|
|
s.mem[key] = value
|
|
|
|
delete(s.del, key)
|
|
|
|
}
|
|
|
|
|
2019-09-26 15:35:36 +00:00
|
|
|
// Put implements the Store interface. Never returns an error.
|
2018-03-17 11:53:21 +00:00
|
|
|
func (s *MemoryStore) Put(key, value []byte) error {
|
2019-10-07 14:08:09 +00:00
|
|
|
newKey := string(key)
|
2021-07-18 13:32:10 +00:00
|
|
|
vcopy := slice.Copy(value)
|
2019-10-07 17:13:59 +00:00
|
|
|
s.mut.Lock()
|
|
|
|
s.put(newKey, vcopy)
|
2019-10-07 14:08:09 +00:00
|
|
|
s.mut.Unlock()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-10-22 14:56:03 +00:00
|
|
|
// drop deletes a key-value pair from the store, it's supposed to be called
|
2019-10-07 17:13:59 +00:00
|
|
|
// with mutex locked.
|
|
|
|
func (s *MemoryStore) drop(key string) {
|
|
|
|
s.del[key] = true
|
|
|
|
delete(s.mem, key)
|
|
|
|
}
|
|
|
|
|
2019-10-07 14:08:09 +00:00
|
|
|
// Delete implements Store interface. Never returns an error.
|
|
|
|
func (s *MemoryStore) Delete(key []byte) error {
|
|
|
|
newKey := string(key)
|
2019-10-07 17:13:59 +00:00
|
|
|
s.mut.Lock()
|
|
|
|
s.drop(newKey)
|
2019-09-26 17:49:02 +00:00
|
|
|
s.mut.Unlock()
|
2018-03-17 11:53:21 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-09-26 15:35:36 +00:00
|
|
|
// PutBatch implements the Store interface. Never returns an error.
|
2018-03-17 11:53:21 +00:00
|
|
|
func (s *MemoryStore) PutBatch(batch Batch) error {
|
|
|
|
b := batch.(*MemoryBatch)
|
2021-08-12 10:35:09 +00:00
|
|
|
return s.PutChangeSet(b.mem, b.del)
|
|
|
|
}
|
|
|
|
|
|
|
|
// PutChangeSet implements the Store interface. Never returns an error.
|
|
|
|
func (s *MemoryStore) PutChangeSet(puts map[string][]byte, dels map[string]bool) error {
|
2019-10-07 17:13:59 +00:00
|
|
|
s.mut.Lock()
|
2021-08-12 10:35:09 +00:00
|
|
|
for k := range puts {
|
|
|
|
s.put(k, puts[k])
|
2019-10-07 14:08:09 +00:00
|
|
|
}
|
2021-08-12 10:35:09 +00:00
|
|
|
for k := range dels {
|
|
|
|
s.drop(k)
|
2018-03-17 11:53:21 +00:00
|
|
|
}
|
2021-08-12 10:35:09 +00:00
|
|
|
s.mut.Unlock()
|
2018-03-17 11:53:21 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-02-09 15:53:58 +00:00
|
|
|
// Seek implements the Store interface.
|
2018-03-17 11:53:21 +00:00
|
|
|
func (s *MemoryStore) Seek(key []byte, f func(k, v []byte)) {
|
2020-02-24 14:51:50 +00:00
|
|
|
s.mut.RLock()
|
|
|
|
s.seek(key, f)
|
|
|
|
s.mut.RUnlock()
|
|
|
|
}
|
|
|
|
|
2020-12-24 16:32:27 +00:00
|
|
|
// SeekAll is like seek but also iterates over deleted items.
|
|
|
|
func (s *MemoryStore) SeekAll(key []byte, f func(k, v []byte)) {
|
|
|
|
s.mut.RLock()
|
|
|
|
defer s.mut.RUnlock()
|
|
|
|
sk := string(key)
|
|
|
|
for k, v := range s.mem {
|
|
|
|
if strings.HasPrefix(k, sk) {
|
|
|
|
f([]byte(k), v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for k := range s.del {
|
|
|
|
if strings.HasPrefix(k, sk) {
|
|
|
|
f([]byte(k), nil)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-24 14:51:50 +00:00
|
|
|
// seek is an internal unlocked implementation of Seek.
|
|
|
|
func (s *MemoryStore) seek(key []byte, f func(k, v []byte)) {
|
2021-07-12 11:14:14 +00:00
|
|
|
sk := string(key)
|
2021-09-24 13:00:13 +00:00
|
|
|
var memList []KeyValue
|
2019-09-18 15:20:41 +00:00
|
|
|
for k, v := range s.mem {
|
2021-07-12 11:14:14 +00:00
|
|
|
if strings.HasPrefix(k, sk) {
|
2021-09-24 13:00:13 +00:00
|
|
|
memList = append(memList, KeyValue{
|
|
|
|
Key: []byte(k),
|
|
|
|
Value: v,
|
|
|
|
})
|
2019-09-18 15:20:41 +00:00
|
|
|
}
|
|
|
|
}
|
2021-09-24 13:00:13 +00:00
|
|
|
sort.Slice(memList, func(i, j int) bool {
|
|
|
|
return bytes.Compare(memList[i].Key, memList[j].Key) < 0
|
|
|
|
})
|
|
|
|
for _, kv := range memList {
|
|
|
|
f(kv.Key, kv.Value)
|
|
|
|
}
|
2018-03-17 11:53:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Batch implements the Batch interface and returns a compatible Batch.
|
|
|
|
func (s *MemoryStore) Batch() Batch {
|
2019-09-26 15:39:53 +00:00
|
|
|
return newMemoryBatch()
|
|
|
|
}
|
|
|
|
|
|
|
|
// newMemoryBatch returns new memory batch.
|
|
|
|
func newMemoryBatch() *MemoryBatch {
|
2019-10-07 17:25:33 +00:00
|
|
|
return &MemoryBatch{MemoryStore: *NewMemoryStore()}
|
2018-03-17 11:53:21 +00:00
|
|
|
}
|
2018-03-21 16:11:04 +00:00
|
|
|
|
2019-09-26 15:35:36 +00:00
|
|
|
// Close implements Store interface and clears up memory. Never returns an
|
|
|
|
// error.
|
2019-09-16 15:52:47 +00:00
|
|
|
func (s *MemoryStore) Close() error {
|
2019-09-26 17:49:02 +00:00
|
|
|
s.mut.Lock()
|
2019-10-07 14:08:09 +00:00
|
|
|
s.del = nil
|
2019-09-16 15:52:47 +00:00
|
|
|
s.mem = nil
|
2019-09-26 17:49:02 +00:00
|
|
|
s.mut.Unlock()
|
2019-09-16 15:52:47 +00:00
|
|
|
return nil
|
|
|
|
}
|