package decision import "sync" // ringSize is how many turns are kept. Turns arrive at human rate, not machine // rate, so the whole store is memory: no migration, no insert on the answer // path, and nothing of his words survives a restart. That is what makes this // cheap enough to leave on always (V-564). Ecosystem traces went to SQLite // because one act writes several hops and they must outlive the turn; an // arbitration record is read minutes later or never. const ringSize = 25 // Ring holds the newest records, newest first on read. type Ring struct { mu sync.Mutex recs []*Record } func NewRing() *Ring { return &Ring{} } // Push adds one finished record and drops the oldest past the bound. func (r *Ring) Push(rec *Record) { if r == nil || rec == nil { return } r.mu.Lock() defer r.mu.Unlock() r.recs = append(r.recs, rec) if len(r.recs) > ringSize { r.recs = r.recs[len(r.recs)-ringSize:] } } // Recent returns up to n records, newest first. func (r *Ring) Recent(n int) []*Record { if r == nil || n <= 0 { return nil } r.mu.Lock() defer r.mu.Unlock() if n > len(r.recs) { n = len(r.recs) } out := make([]*Record, 0, n) for i := 0; i < n; i++ { out = append(out, r.recs[len(r.recs)-1-i]) } return out }