From eed10ce514f28e4acf772f76c92ca05eebec105f Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Thu, 5 May 2022 21:20:22 -0600 Subject: Fix various problems with the srv build --- srv/src/pow/store.go | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 srv/src/pow/store.go (limited to 'srv/src/pow/store.go') diff --git a/srv/src/pow/store.go b/srv/src/pow/store.go new file mode 100644 index 0000000..0b5e7d0 --- /dev/null +++ b/srv/src/pow/store.go @@ -0,0 +1,92 @@ +package pow + +import ( + "errors" + "sync" + "time" + + "github.com/tilinna/clock" +) + +// ErrSeedSolved is used to indicate a seed has already been solved. +var ErrSeedSolved = errors.New("seed already solved") + +// Store is used to track information related to proof-of-work challenges and +// solutions. +type Store interface { + + // MarkSolved will return ErrSeedSolved if the seed was already marked. The + // seed will be cleared from the Store once expiresAt is reached. + MarkSolved(seed []byte, expiresAt time.Time) error + + Close() error +} + +type inMemStore struct { + clock clock.Clock + + m map[string]time.Time + l sync.Mutex + closeCh chan struct{} + spinLoopCh chan struct{} // only used by tests +} + +const inMemStoreGCPeriod = 5 * time.Second + +// NewMemoryStore initializes and returns an in-memory Store implementation. +func NewMemoryStore(clock clock.Clock) Store { + s := &inMemStore{ + clock: clock, + m: map[string]time.Time{}, + closeCh: make(chan struct{}), + spinLoopCh: make(chan struct{}, 1), + } + go s.spin(s.clock.NewTicker(inMemStoreGCPeriod)) + return s +} + +func (s *inMemStore) spin(ticker *clock.Ticker) { + defer ticker.Stop() + + for { + select { + case <-ticker.C: + now := s.clock.Now() + + s.l.Lock() + for seed, expiresAt := range s.m { + if !now.Before(expiresAt) { + delete(s.m, seed) + } + } + s.l.Unlock() + + case <-s.closeCh: + return + } + + select { + case s.spinLoopCh <- struct{}{}: + default: + } + } +} + +func (s *inMemStore) MarkSolved(seed []byte, expiresAt time.Time) error { + seedStr := string(seed) + + s.l.Lock() + defer s.l.Unlock() + + if _, ok := s.m[seedStr]; ok { + return ErrSeedSolved + } + + s.m[seedStr] = expiresAt + return nil +} + +func (s *inMemStore) Close() error { + close(s.closeCh) + return nil +} -- cgit v1.2.3