Keep a condition's looks in the store, so a look that changes nothing writes no bucket (issue 420)
Every look rewrote the condition's value in the conditions bucket, because the value carried the count of looks, the last look and the newest evidence: 131 647 writes in four days for twelve open conditions, against ADR 0289's rule that a bucket is written only when what it describes changed. The looks now live in the controller's store (migration 0095, condition_looks), the bucket holds what a condition says and is written only when that changes, and the conditions verb and the condition events put the looks back.
This commit is contained in:
@@ -12,10 +12,14 @@ import (
|
||||
// InMemory is a store and a history held in this process: for tests, and for nothing else — a
|
||||
// condition kept here is forgotten by a restart, which is the fault the store exists to remove.
|
||||
type InMemory struct {
|
||||
// MemoryLooks keeps its conditions' looks, as the controller's store does beside the bucket.
|
||||
MemoryLooks
|
||||
mu sync.Mutex
|
||||
values map[string]Entry
|
||||
revision uint64
|
||||
events []Event
|
||||
// writes counts every create, update and delete, so a test can say a look wrote nothing.
|
||||
writes int
|
||||
events []Event
|
||||
// fail, when set, is what every read and write answers: a store that is away. It is set only
|
||||
// through SetFail, under the lock, because the keeper's telling goroutine reads it while a test
|
||||
// takes the store away.
|
||||
@@ -23,7 +27,9 @@ type InMemory struct {
|
||||
}
|
||||
|
||||
// NewInMemory is an empty store.
|
||||
func NewInMemory() *InMemory { return &InMemory{values: map[string]Entry{}} }
|
||||
func NewInMemory() *InMemory {
|
||||
return &InMemory{values: map[string]Entry{}, MemoryLooks: MemoryLooks{looks: map[string]Looks{}}}
|
||||
}
|
||||
|
||||
// SetFail makes every read and write answer err from now on, or none when err is nil.
|
||||
func (m *InMemory) SetFail(err error) {
|
||||
@@ -52,10 +58,18 @@ func (m *InMemory) Create(_ context.Context, key string, value []byte) error {
|
||||
return ErrMoved
|
||||
}
|
||||
m.revision++
|
||||
m.writes++
|
||||
m.values[key] = Entry{Value: value, Revision: m.revision}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Writes is how many creates, updates and deletes the store took.
|
||||
func (m *InMemory) Writes() int {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
return m.writes
|
||||
}
|
||||
|
||||
func (m *InMemory) Update(_ context.Context, key string, value []byte, revision uint64) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
@@ -66,6 +80,7 @@ func (m *InMemory) Update(_ context.Context, key string, value []byte, revision
|
||||
return ErrMoved
|
||||
}
|
||||
m.revision++
|
||||
m.writes++
|
||||
m.values[key] = Entry{Value: value, Revision: m.revision}
|
||||
return nil
|
||||
}
|
||||
@@ -79,6 +94,7 @@ func (m *InMemory) Delete(_ context.Context, key string, revision uint64) error
|
||||
if e, ok := m.values[key]; !ok || e.Revision != revision {
|
||||
return ErrMoved
|
||||
}
|
||||
m.writes++
|
||||
delete(m.values, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user