Files
mesh-tools/node-tools/internal/ledger/memory.go
T

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
}