159 lines
3.2 KiB
Go
159 lines
3.2 KiB
Go
package ledger
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// The memory stores keep what the bus keeps, as the bus answers it, for a test of a ledger without a bus: a stream whose
|
|
// sequence counts across every instance, a bucket with revisions that may be full, and snapshots written with an expected
|
|
// sequence.
|
|
|
|
// MemoryHistory is a history in memory.
|
|
type MemoryHistory struct {
|
|
mu sync.Mutex
|
|
seq uint64
|
|
kept []struct {
|
|
key string
|
|
Kept
|
|
}
|
|
}
|
|
|
|
// Matches is whether a key pattern (`*` one name, `>` the rest) names a key.
|
|
func Matches(pattern, key string) bool {
|
|
p, k := strings.Split(pattern, "."), strings.Split(key, ".")
|
|
for i, part := range p {
|
|
if part == ">" {
|
|
return len(k) > i
|
|
}
|
|
if i >= len(k) || (part != "*" && part != k[i]) {
|
|
return false
|
|
}
|
|
}
|
|
return len(p) == len(k)
|
|
}
|
|
|
|
func (h *MemoryHistory) Last(key string) (uint64, error) {
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
last := uint64(0)
|
|
for _, k := range h.kept {
|
|
if k.key == key {
|
|
last = k.Sequence
|
|
}
|
|
}
|
|
return last, nil
|
|
}
|
|
|
|
func (h *MemoryHistory) Append(key string, op []byte, expect uint64) (uint64, error) {
|
|
last, _ := h.Last(key)
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
if last != expect {
|
|
return 0, ErrRaced
|
|
}
|
|
h.seq++
|
|
h.kept = append(h.kept, struct {
|
|
key string
|
|
Kept
|
|
}{key, Kept{Sequence: h.seq, Data: op}})
|
|
return h.seq, nil
|
|
}
|
|
|
|
func (h *MemoryHistory) Read(keys string, from uint64, limit int) ([]Kept, error) {
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
var out []Kept
|
|
for _, k := range h.kept {
|
|
if k.Sequence >= from && Matches(keys, k.key) && (limit == 0 || len(out) < limit) {
|
|
out = append(out, k.Kept)
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// Expire drops every operation of the history, as a ledger's keeping days end them.
|
|
func (h *MemoryHistory) Expire() {
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
h.kept = nil
|
|
}
|
|
|
|
type memoryValue struct {
|
|
value []byte
|
|
rev uint64
|
|
}
|
|
|
|
// MemoryState is a state bucket in memory.
|
|
type MemoryState struct {
|
|
mu sync.Mutex
|
|
rev uint64
|
|
// Full makes every write refused as a full bucket's.
|
|
Full bool
|
|
kv map[string]memoryValue
|
|
}
|
|
|
|
func (s *MemoryState) Get(key string) ([]byte, uint64, error) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
v := s.kv[key]
|
|
return v.value, v.rev, nil
|
|
}
|
|
|
|
func (s *MemoryState) Write(key string, value []byte, revision uint64) (uint64, error) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
if s.Full {
|
|
return 0, ErrFull
|
|
}
|
|
if s.kv[key].rev != revision {
|
|
return 0, ErrChanged
|
|
}
|
|
if s.kv == nil {
|
|
s.kv = map[string]memoryValue{}
|
|
}
|
|
s.rev++
|
|
s.kv[key] = memoryValue{value, s.rev}
|
|
return s.rev, nil
|
|
}
|
|
|
|
func (s *MemoryState) Keys() ([]string, error) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
var out []string
|
|
for k := range s.kv {
|
|
out = append(out, k)
|
|
}
|
|
sort.Strings(out)
|
|
return out, nil
|
|
}
|
|
|
|
// MemorySnapshots are snapshots in memory.
|
|
type MemorySnapshots struct {
|
|
mu sync.Mutex
|
|
at uint64
|
|
kv map[string]memoryValue
|
|
}
|
|
|
|
func (s *MemorySnapshots) Get(key string) ([]byte, uint64, error) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
v := s.kv[key]
|
|
return v.value, v.rev, nil
|
|
}
|
|
|
|
func (s *MemorySnapshots) Put(key string, value []byte, expect uint64) error {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
if s.kv[key].rev != expect {
|
|
return ErrRaced
|
|
}
|
|
if s.kv == nil {
|
|
s.kv = map[string]memoryValue{}
|
|
}
|
|
s.at++
|
|
s.kv[key] = memoryValue{value, s.at}
|
|
return nil
|
|
}
|