diff --git a/internal/core.go b/internal/core.go index 95d634d..a8769b4 100644 --- a/internal/core.go +++ b/internal/core.go @@ -21,20 +21,6 @@ func (s *Store) Get(key string) (string, bool) { return v, ok } -// Set stores value under key. -func (s *Store) Set(key, value string) { - s.mu.Lock() - defer s.mu.Unlock() - s.data[key] = value -} - -// Delete removes key from the store. -func (s *Store) Delete(key string) { - s.mu.Lock() - defer s.mu.Unlock() - delete(s.data, key) -} - // Keys returns all keys currently stored. func (s *Store) Keys() []string { s.mu.RLock() @@ -45,3 +31,34 @@ func (s *Store) Keys() []string { } return keys } + +// applyLocked runs fn while holding the write lock. All mutating operations +// route through this so future batched writes can share one critical section. +func (s *Store) applyLocked(fn func(data map[string]string)) { + s.mu.Lock() + defer s.mu.Unlock() + fn(s.data) +} + +// Set stores value under key. +func (s *Store) Set(key, value string) { + s.applyLocked(func(data map[string]string) { + data[key] = value + }) +} + +// Delete removes key from the store. +func (s *Store) Delete(key string) { + s.applyLocked(func(data map[string]string) { + delete(data, key) + }) +} + +// SetMany stores multiple key/value pairs under a single lock acquisition. +func (s *Store) SetMany(pairs map[string]string) { + s.applyLocked(func(data map[string]string) { + for k, v := range pairs { + data[k] = v + } + }) +} diff --git a/internal/mod.go b/internal/mod.go index e4e806a..0ac51e6 100644 --- a/internal/mod.go +++ b/internal/mod.go @@ -4,3 +4,7 @@ package internal func Greeting() string { return "AutoApproveDemo service starting" } + +// BatchWriteEnabled reports whether the batched-write code path is active. +// Flipped on once SetMany has soaked in production for a release cycle. +var BatchWriteEnabled = false diff --git a/internal/mod_test.go b/internal/mod_test.go index 21de693..ae23712 100644 --- a/internal/mod_test.go +++ b/internal/mod_test.go @@ -16,3 +16,14 @@ func TestStoreSetGet(t *testing.T) { t.Fatalf("expected a=1, got %q ok=%v", v, ok) } } + +func TestStoreSetMany(t *testing.T) { + s := NewStore() + s.SetMany(map[string]string{"a": "1", "b": "2"}) + if v, _ := s.Get("a"); v != "1" { + t.Fatalf("expected a=1, got %q", v) + } + if v, _ := s.Get("b"); v != "2" { + t.Fatalf("expected b=2, got %q", v) + } +}