2015-03-02 18:48:53 +00:00
|
|
|
package physical
|
|
|
|
|
|
|
|
import (
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
|
2016-08-19 20:45:17 +00:00
|
|
|
log "github.com/mgutz/logxi/v1"
|
|
|
|
|
2015-03-02 18:48:53 +00:00
|
|
|
"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 {
|
2015-11-03 16:47:16 +00:00
|
|
|
root *radix.Tree
|
|
|
|
l sync.RWMutex
|
|
|
|
permitPool *PermitPool
|
2016-08-19 20:45:17 +00:00
|
|
|
logger log.Logger
|
2015-03-02 18:48:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewInmem constructs a new in-memory backend
|
2016-08-19 20:45:17 +00:00
|
|
|
func NewInmem(logger log.Logger) *InmemBackend {
|
2015-03-02 18:48:53 +00:00
|
|
|
in := &InmemBackend{
|
2015-11-03 16:47:16 +00:00
|
|
|
root: radix.New(),
|
2015-11-03 20:26:07 +00:00
|
|
|
permitPool: NewPermitPool(DefaultParallelOperations),
|
2015-03-02 18:48:53 +00:00
|
|
|
}
|
|
|
|
return in
|
|
|
|
}
|
|
|
|
|
|
|
|
// Put is used to insert or update an entry
|
|
|
|
func (i *InmemBackend) Put(entry *Entry) error {
|
2015-11-03 16:47:16 +00:00
|
|
|
i.permitPool.Acquire()
|
|
|
|
defer i.permitPool.Release()
|
|
|
|
|
2015-11-03 19:48:05 +00:00
|
|
|
i.l.Lock()
|
|
|
|
defer i.l.Unlock()
|
|
|
|
|
2015-03-02 18:48:53 +00:00
|
|
|
i.root.Insert(entry.Key, entry)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get is used to fetch an entry
|
|
|
|
func (i *InmemBackend) Get(key string) (*Entry, error) {
|
2015-11-03 16:47:16 +00:00
|
|
|
i.permitPool.Acquire()
|
|
|
|
defer i.permitPool.Release()
|
|
|
|
|
2015-11-03 19:48:05 +00:00
|
|
|
i.l.RLock()
|
|
|
|
defer i.l.RUnlock()
|
|
|
|
|
2015-03-02 18:48:53 +00:00
|
|
|
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 {
|
2015-11-03 16:47:16 +00:00
|
|
|
i.permitPool.Acquire()
|
|
|
|
defer i.permitPool.Release()
|
|
|
|
|
2015-11-03 19:48:05 +00:00
|
|
|
i.l.Lock()
|
|
|
|
defer i.l.Unlock()
|
|
|
|
|
2015-03-02 18:48:53 +00:00
|
|
|
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) {
|
2015-11-03 16:47:16 +00:00
|
|
|
i.permitPool.Acquire()
|
|
|
|
defer i.permitPool.Release()
|
|
|
|
|
2015-11-03 19:48:05 +00:00
|
|
|
i.l.RLock()
|
|
|
|
defer i.l.RUnlock()
|
|
|
|
|
2015-03-02 18:48:53 +00:00
|
|
|
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
|
|
|
|
}
|