blob: f8ddd4906c71c55fd409439076289ed1beb49431 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package mem provides a simple, in-memory implementation of
// server.Store. Since it's a prototype implementation, it doesn't
// bother with entry-level locking.
package mem
import (
"strconv"
"sync"
"v.io/v23/vdl"
"v.io/v23/verror"
"v.io/x/ref/services/groups/internal/store"
)
type entry struct {
Value interface{}
Version uint64
}
type memstore struct {
mu sync.Mutex
err error
data map[string]*entry
}
var _ store.Store = (*memstore)(nil)
func New() store.Store {
return &memstore{data: map[string]*entry{}}
}
func (st *memstore) Get(k string, v interface{}) (version string, err error) {
st.mu.Lock()
defer st.mu.Unlock()
if st.err != nil {
return "", convertError(st.err)
}
e, ok := st.data[k]
if !ok {
return "", verror.New(store.ErrUnknownKey, nil, k)
}
if err := vdl.Convert(v, e.Value); err != nil {
return "", convertError(err)
}
return strconv.FormatUint(e.Version, 10), nil
}
func (st *memstore) Insert(k string, v interface{}) error {
st.mu.Lock()
defer st.mu.Unlock()
if st.err != nil {
return convertError(st.err)
}
if _, ok := st.data[k]; ok {
return verror.New(store.ErrKeyExists, nil, k)
}
st.data[k] = &entry{Value: v}
return nil
}
func (st *memstore) Update(k string, v interface{}, version string) error {
st.mu.Lock()
defer st.mu.Unlock()
if st.err != nil {
return convertError(st.err)
}
e, ok := st.data[k]
if !ok {
return verror.New(store.ErrUnknownKey, nil, k)
}
if err := e.checkVersion(version); err != nil {
return err
}
st.data[k] = &entry{Value: v, Version: e.Version + 1}
return nil
}
func (st *memstore) Delete(k string, version string) error {
st.mu.Lock()
defer st.mu.Unlock()
if st.err != nil {
return convertError(st.err)
}
e, ok := st.data[k]
if !ok {
return verror.New(store.ErrUnknownKey, nil, k)
}
if err := e.checkVersion(version); err != nil {
return err
}
delete(st.data, k)
return nil
}
func (st *memstore) Close() error {
st.mu.Lock()
defer st.mu.Unlock()
if st.err != nil {
return convertError(st.err)
}
st.err = verror.New(verror.ErrCanceled, nil, "closed store")
return nil
}
////////////////////////////////////////
// Internal helpers
func (e *entry) checkVersion(version string) error {
newVersion := strconv.FormatUint(e.Version, 10)
if version != newVersion {
return verror.NewErrBadVersion(nil)
}
return nil
}
func convertError(err error) error {
return verror.Convert(verror.IDAction{}, nil, err)
}