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 }