Apply a ledger operation: check it against its type, append it with the last sequence expected, derive the state at the revision read, write the snapshot (issue 1966 T2)
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user