open-vault/physical/inmem.go
2017-02-20 11:08:03 -05:00

143 lines
3 KiB
Go

package physical
import (
"strings"
"sync"
log "github.com/mgutz/logxi/v1"
"github.com/armon/go-radix"
)
// InmemBackend is an in-memory only physical backend. It is useful
// for testing and development situations where the data is not
// expected to be durable.
type InmemBackend struct {
sync.RWMutex
root *radix.Tree
permitPool *PermitPool
logger log.Logger
}
type TransactionalInmemBackend struct {
InmemBackend
}
// NewInmem constructs a new in-memory backend
func NewInmem(logger log.Logger) *InmemBackend {
in := &InmemBackend{
root: radix.New(),
permitPool: NewPermitPool(DefaultParallelOperations),
logger: logger,
}
return in
}
// Basically for now just creates a permit pool of size 1 so only one operation
// can run at a time
func NewTransactionalInmem(logger log.Logger) *TransactionalInmemBackend {
in := &TransactionalInmemBackend{
InmemBackend: InmemBackend{
root: radix.New(),
permitPool: NewPermitPool(1),
logger: logger,
},
}
return in
}
// Put is used to insert or update an entry
func (i *InmemBackend) Put(entry *Entry) error {
i.permitPool.Acquire()
defer i.permitPool.Release()
i.Lock()
defer i.Unlock()
return i.PutInternal(entry)
}
func (i *InmemBackend) PutInternal(entry *Entry) error {
i.root.Insert(entry.Key, entry)
return nil
}
// Get is used to fetch an entry
func (i *InmemBackend) Get(key string) (*Entry, error) {
i.permitPool.Acquire()
defer i.permitPool.Release()
i.RLock()
defer i.RUnlock()
return i.GetInternal(key)
}
func (i *InmemBackend) GetInternal(key string) (*Entry, error) {
if raw, ok := i.root.Get(key); ok {
return raw.(*Entry), nil
}
return nil, nil
}
// Delete is used to permanently delete an entry
func (i *InmemBackend) Delete(key string) error {
i.permitPool.Acquire()
defer i.permitPool.Release()
i.Lock()
defer i.Unlock()
return i.DeleteInternal(key)
}
func (i *InmemBackend) DeleteInternal(key string) error {
i.root.Delete(key)
return nil
}
// List is used ot list all the keys under a given
// prefix, up to the next prefix.
func (i *InmemBackend) List(prefix string) ([]string, error) {
i.permitPool.Acquire()
defer i.permitPool.Release()
i.RLock()
defer i.RUnlock()
return i.ListInternal(prefix)
}
func (i *InmemBackend) ListInternal(prefix string) ([]string, error) {
var out []string
seen := make(map[string]interface{})
walkFn := func(s string, v interface{}) bool {
trimmed := strings.TrimPrefix(s, prefix)
sep := strings.Index(trimmed, "/")
if sep == -1 {
out = append(out, trimmed)
} else {
trimmed = trimmed[:sep+1]
if _, ok := seen[trimmed]; !ok {
out = append(out, trimmed)
seen[trimmed] = struct{}{}
}
}
return false
}
i.root.WalkPrefix(prefix, walkFn)
return out, nil
}
// Implements the transaction interface
func (t *TransactionalInmemBackend) Transaction(txns []TxnEntry) error {
t.permitPool.Acquire()
defer t.permitPool.Release()
t.Lock()
defer t.Unlock()
return genericTransactionHandler(t, txns)
}