Add very basic in-memory storage adapter

This commit is contained in:
2016-07-11 14:11:38 +01:00
parent 6b0244c552
commit e3ec2ff16c
2 changed files with 233 additions and 0 deletions

69
storage/inmemory/store.go Normal file
View File

@@ -0,0 +1,69 @@
package inmemory
import (
"errors"
"sync"
)
// ErrNotFound is returned when Get() tries to fetch a non-existent key.
var ErrNotFound = errors.New("not found")
// New creates a new Store using given path to persist data.
func New() (*Store, error) {
store := &Store{
Data: map[string][]byte{},
Sequence: 0,
}
return store, nil
}
// Store allows storing data into a in-memory map.
type Store struct {
sync.RWMutex
Data map[string][]byte
Sequence int
Closed bool
}
// Close database.
func (s *Store) Close() error {
s.Data = make(map[string][]byte)
s.Sequence = 0
return nil
}
// Get a given key's value.
func (s *Store) Get(key []byte) ([]byte, error) {
s.RLock()
value := s.Data[string(key)]
s.RUnlock()
if value == nil {
return nil, ErrNotFound
}
return value, nil
}
// Set a given key's to the specified value.
func (s *Store) Set(key []byte, value []byte) error {
s.Lock()
s.Data[string(key)] = value
s.Unlock()
return nil
}
// Delete a given key.
func (s *Store) Delete(key []byte) error {
s.Lock()
delete(s.Data, string(key))
s.Unlock()
return nil
}
// NextSequence returns a auto-incrementing int.
func (s *Store) NextSequence() (int, error) {
s.Lock()
s.Sequence++
seq := s.Sequence
s.Unlock()
return seq, nil
}

View File

@@ -0,0 +1,164 @@
package inmemory
import (
"testing"
"github.com/jimeh/ozu.io/storage"
"github.com/stretchr/testify/suite"
)
// Setup Suite
var examples = []struct {
key []byte
value []byte
}{
{key: []byte("hello"), value: []byte("world")},
{key: []byte("foo"), value: []byte("bar")},
{key: []byte("wtf"), value: []byte("dude")},
}
type StoreSuite struct {
suite.Suite
store *Store
}
func (s *StoreSuite) SetupTest() {
store, err := New()
s.Require().NoError(err)
s.store = store
}
func (s *StoreSuite) TearDownTest() {
_ = s.store.Close()
}
func (s *StoreSuite) Seed() {
for _, e := range examples {
s.store.Data[string(e.key)] = e.value
}
}
// Tests
func (s *StoreSuite) TestStoreInterface() {
s.Implements(new(storage.Store), new(Store))
}
func (s *StoreSuite) TestSet() {
for _, e := range examples {
err := s.store.Set(e.key, e.value)
s.NoError(err)
}
for _, e := range examples {
result, _ := s.store.Data[string(e.key)]
s.Equal(e.value, result)
}
}
func (s *StoreSuite) TestGetExisting() {
s.Seed()
for _, e := range examples {
result, err := s.store.Get(e.key)
s.NoError(err)
s.Equal(e.value, result)
}
}
func (s *StoreSuite) TestGetNonExistant() {
result, err := s.store.Get([]byte("does-not-exist"))
s.Nil(result)
s.EqualError(err, "not found")
}
func (s *StoreSuite) TestDeleteExisting() {
s.Seed()
for _, e := range examples {
value := s.store.Data[string(e.key)]
s.Require().Equal(e.value, value)
value, err := s.store.Get(e.key)
s.Require().NoError(err)
s.Require().Equal(value, e.value)
err = s.store.Delete(e.key)
s.NoError(err)
value, err = s.store.Get(e.key)
s.Nil(value)
s.EqualError(err, "not found")
_, has := s.store.Data[string(e.key)]
s.Equal(false, has)
}
}
func (s *StoreSuite) TestDeleteNonExistant() {
err := s.store.Delete([]byte("does-not-exist"))
s.NoError(err)
}
func (s *StoreSuite) TestNextSequenceExisting() {
s.store.Sequence = 5
result, err := s.store.NextSequence()
s.NoError(err)
s.Equal(6, result)
}
func (s *StoreSuite) TestNextSequenceNonExistant() {
for i := 1; i < 10; i++ {
result, err := s.store.NextSequence()
s.NoError(err)
s.Equal(i, result)
}
}
// Run Suite
func TestStoreSuite(t *testing.T) {
suite.Run(t, new(StoreSuite))
}
// Benchmarks
func BenchmarkGet(b *testing.B) {
store, _ := New()
key := []byte("hello")
value := []byte("world")
_ = store.Set(key, value)
for n := 0; n < b.N; n++ {
_, _ = store.Get(key)
}
_ = store.Close()
}
func BenchmarkSet(b *testing.B) {
store, _ := New()
key := []byte("hello")
value := []byte("world")
for n := 0; n < b.N; n++ {
_ = store.Set(append(key, string(n)...), value)
}
_ = store.Close()
}
func BenchmarkNextSequence(b *testing.B) {
store, _ := New()
for n := 0; n < b.N; n++ {
_, _ = store.NextSequence()
}
_ = store.Close()
}