mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-12 19:48:44 +00:00
Compare commits
2 Commits
Xe/seriali
...
Xe/nginx-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d799c7858 | ||
|
|
07a571d6cd |
@@ -19,7 +19,7 @@ type Impl[K comparable, V any] struct {
|
|||||||
// stopCh stops the background cleanup worker.
|
// stopCh stops the background cleanup worker.
|
||||||
stopCh chan struct{}
|
stopCh chan struct{}
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
lock sync.Mutex
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
type decayMapEntry[V any] struct {
|
type decayMapEntry[V any] struct {
|
||||||
@@ -64,28 +64,26 @@ func (m *Impl[K, V]) expire(key K) bool {
|
|||||||
|
|
||||||
// Delete a value from the DecayMap by key.
|
// Delete a value from the DecayMap by key.
|
||||||
//
|
//
|
||||||
// This defers deletions to a background thread for performance reasons.
|
|
||||||
//
|
|
||||||
// If the value does not exist, return false. Return true after
|
// If the value does not exist, return false. Return true after
|
||||||
// deletion.
|
// deletion.
|
||||||
func (m *Impl[K, V]) Delete(key K) bool {
|
func (m *Impl[K, V]) Delete(key K) bool {
|
||||||
select {
|
// Use a single write lock to avoid RUnlock->Lock convoy.
|
||||||
// Defer decay deletion to the background worker to avoid convoy.
|
m.lock.Lock()
|
||||||
case m.deleteCh <- deleteReq[K]{key: key, expiry: time.Now().Add(-1 * time.Second)}:
|
defer m.lock.Unlock()
|
||||||
return m.expire(key)
|
_, ok := m.data[key]
|
||||||
default:
|
if ok {
|
||||||
// Channel full: drop request; a future Cleanup() or Get will retry.
|
delete(m.data, key)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get gets a value from the DecayMap by key.
|
// Get gets a value from the DecayMap by key.
|
||||||
//
|
//
|
||||||
// If a value has expired, forcibly delete it if it was not updated.
|
// If a value has expired, forcibly delete it if it was not updated.
|
||||||
func (m *Impl[K, V]) Get(key K) (V, bool) {
|
func (m *Impl[K, V]) Get(key K) (V, bool) {
|
||||||
m.lock.Lock()
|
m.lock.RLock()
|
||||||
defer m.lock.Unlock()
|
|
||||||
value, ok := m.data[key]
|
value, ok := m.data[key]
|
||||||
|
m.lock.RUnlock()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return Zilch[V](), false
|
return Zilch[V](), false
|
||||||
@@ -131,8 +129,8 @@ func (m *Impl[K, V]) Cleanup() {
|
|||||||
|
|
||||||
// Len returns the number of entries in the DecayMap.
|
// Len returns the number of entries in the DecayMap.
|
||||||
func (m *Impl[K, V]) Len() int {
|
func (m *Impl[K, V]) Len() int {
|
||||||
m.lock.Lock()
|
m.lock.RLock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.RUnlock()
|
||||||
return len(m.data)
|
return len(m.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +146,7 @@ func (m *Impl[K, V]) Close() {
|
|||||||
func (m *Impl[K, V]) cleanupWorker() {
|
func (m *Impl[K, V]) cleanupWorker() {
|
||||||
defer m.wg.Done()
|
defer m.wg.Done()
|
||||||
batch := make([]deleteReq[K], 0, 64)
|
batch := make([]deleteReq[K], 0, 64)
|
||||||
ticker := time.NewTicker(15 * time.Minute)
|
ticker := time.NewTicker(10 * time.Millisecond)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
flush := func() {
|
flush := func() {
|
||||||
|
|||||||
@@ -30,7 +30,15 @@ func TestImpl(t *testing.T) {
|
|||||||
t.Error("got value even though it was supposed to be expired")
|
t.Error("got value even though it was supposed to be expired")
|
||||||
}
|
}
|
||||||
|
|
||||||
dm.Cleanup()
|
// Deletion of expired entries after Get is deferred to a background worker.
|
||||||
|
// Assert it eventually disappears from the map.
|
||||||
|
deadline := time.Now().Add(200 * time.Millisecond)
|
||||||
|
for time.Now().Before(deadline) {
|
||||||
|
if dm.Len() == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(5 * time.Millisecond)
|
||||||
|
}
|
||||||
if dm.Len() != 0 {
|
if dm.Len() != 0 {
|
||||||
t.Fatalf("expected background cleanup to remove expired key; len=%d", dm.Len())
|
t.Fatalf("expected background cleanup to remove expired key; len=%d", dm.Len())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
- The memory store now decays values every 15 minutes instead of every 10 milliseconds.
|
|
||||||
- Add Polish locale ([#1292](https://github.com/TecharoHQ/anubis/pull/1309))
|
- Add Polish locale ([#1292](https://github.com/TecharoHQ/anubis/pull/1309))
|
||||||
|
|
||||||
<!-- This changes the project to: -->
|
<!-- This changes the project to: -->
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ type impl struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *impl) Delete(_ context.Context, key string) error {
|
func (i *impl) Delete(_ context.Context, key string) error {
|
||||||
if _, ok := i.store.Get(key); !ok {
|
if !i.store.Delete(key) {
|
||||||
return fmt.Errorf("%w: %q", store.ErrNotFound, key)
|
return fmt.Errorf("%w: %q", store.ErrNotFound, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ func Common(t *testing.T, f store.Factory, config json.RawMessage) {
|
|||||||
t.Error("wanted test to not exist in store but it exists anyways")
|
t.Error("wanted test to not exist in store but it exists anyways")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := s.Delete(t.Context(), t.Name()); err == nil {
|
||||||
|
t.Errorf("key %q does not exist and Delete did not return non-nil", t.Name())
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -79,6 +83,7 @@ func Common(t *testing.T, f store.Factory, config json.RawMessage) {
|
|||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
if err := tt.doer(t, s); !errors.Is(err, tt.err) {
|
if err := tt.doer(t, s); !errors.Is(err, tt.err) {
|
||||||
t.Logf("want: %v", tt.err)
|
t.Logf("want: %v", tt.err)
|
||||||
t.Logf("got: %v", err)
|
t.Logf("got: %v", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user