You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(eviction): robustify all eviction strategies, add config options, and improve docs
- Refactored all eviction algorithms (LRU, LFU, ARC, Clock, CAWOLFU) for thread safety, zero-capacity handling, and deadlock prevention.
- Inlined eviction logic in Clock and CAWOLFU to avoid recursive locking and deadlocks.
- Ensured all mutating operations use proper locking and updated value/frequency on duplicate keys.
- Improved memory hygiene by resetting pooled items before reuse.
- Added buffer size and debounce interval options for expiration trigger channel in config and HyperCache.
- Updated README to clarify package paths and usage, and fixed example commands.
- Added PRD.md with design review and suggestions.
- Updated benchmark to use LRU for proactive eviction test.
- Improved code comments and documentation for maintainability.
Hypercache is a thread‑safe caching library with pluggable backends and eviction algorithms, already targeting Go 1.25 and generics. The design exposes a service interface that supports middleware layers for decorating cache operations.
5
+
6
+
Findings & Suggestions
7
+
Ticker Lifecycle – Background jobs create time.Tickers but never stop them, which can leak resources; explicitly call tick.Stop() when terminating the loops.
8
+
9
+
WorkerPool Resize Logic – Resizing the pool sends a quit signal pool.workers times regardless of how many workers need removal; adjust to send -diff signals and consider buffering to avoid blocking.
10
+
11
+
Expired‑Key Semantics – GetMultiple returns ErrKeyExpired, yet tests expect ErrKeyNotFound for expired items, indicating a behavior mismatch or test expectation issue.
12
+
13
+
Per‑Call Goroutines – Get and GetWithInfo spawn a goroutine for each expired item, which may create overhead under heavy load; consider synchronous cleanup or a dedicated worker to batch expirations.
14
+
15
+
Object Pool Hygiene – ItemPoolManager returns items to the pool without resetting fields, risking retention of large values; zero the struct before reusing it.
16
+
17
+
Modern Go Features – The project already uses Go 1.25; further modernization could include:
18
+
19
+
Generics for typed values rather than any, providing compile‑time safety.
20
+
21
+
Use of maps.Clone/maps.DeleteFunc and slices.SortFunc for cleaner collection handling.
22
+
23
+
errors.Is/errors.Join to simplify error comparisons.
24
+
25
+
Potential Enhancements
26
+
27
+
Expose a MGet/MSet on backends for efficient multi-key operations.
28
+
29
+
Provide context-aware cancellation in WorkerPool and background jobs to ease shutdown.
30
+
31
+
Add methods such as Contains, Peek, Increment, or TTL refresh APIs.
32
+
33
+
Integrate OpenTelemetry metrics and tracing for observability.
Copy file name to clipboardExpand all lines: README.md
+11-11Lines changed: 11 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,29 +6,29 @@
6
6
7
7
HyperCache is a **thread-safe****high-performance** cache implementation in `Go` that supports multiple backends with an optional size limit, expiration, and eviction of items with custom algorithms alongside the defaults. It can be used as a standalone cache, distributed environents, or as a cache middleware for a service. It can implement a [service interface](./service.go) to intercept and decorate the cache methods with middleware (default or custom).
8
8
It is optimized for performance and flexibility, allowing to specify of the expiration and eviction intervals and providing and registering new eviction algorithms, stats collectors, and middleware(s).
9
-
It ships with a default [historigram stats collector](./stats/stats.go) and several eviction algorithms. However, you can develop and register your own if it implements the [Eviction Algorithm interface](./eviction/eviction.go).:
9
+
It ships with a default [historigram stats collector](./pkg/stats/stats.go) and several eviction algorithms. However, you can develop and register your own if it implements the [Eviction Algorithm interface](./pkg/eviction/eviction.go).:
10
10
11
-
-[Recently Used (LRU) eviction algorithm](./eviction/lru.go)
12
-
-[The Least Frequently Used (LFU) algorithm](./eviction/lfu.go)
backend backend.IBackend[T] // `backend`` holds the backend that the cache uses to store the items. It must implement the IBackend interface.
43
-
cacheBackendChecker introspect.CacheBackendChecker[T] // `cacheBackendChecker` holds an instance of the CacheBackendChecker interface. It helps to determine the type of the backend.
44
-
itemPoolManager*cache.ItemPoolManager// `itemPoolManager` manages the item pool for the cache.
45
-
stopchanbool// `stop` channel to signal the expiration and eviction loops to stop
46
-
workerPool*WorkerPool// `workerPool` holds a pointer to the worker pool that the cache uses to run the expiration and eviction loops.
47
-
expirationTriggerChchanbool// `expirationTriggerCh` channel to signal the expiration trigger loop to start
48
-
evictChchanbool// `evictCh` channel to signal the eviction loop to start
49
-
evictionAlgorithmNamestring// `evictionAlgorithmName` name of the eviction algorithm to use when evicting items
50
-
evictionAlgorithm eviction.IAlgorithm// `evictionAlgorithm` eviction algorithm to use when evicting items
51
-
expirationInterval time.Duration// `expirationInterval` interval at which the expiration loop should run
52
-
evictionInterval time.Duration// interval at which the eviction loop should run
53
-
shouldEvict atomic.Bool// `shouldEvict` indicates whether the cache should evict items or not
54
-
maxEvictionCountuint// `evictionInterval` maximum number of items that can be evicted in a single eviction loop iteration
55
-
maxCacheSizeint64// maxCacheSize instructs the cache not allocate more memory than this limit, value in MB, 0 means no limit
56
-
memoryAllocation atomic.Int64// memoryAllocation is the current memory allocation of the cache, value in bytes
57
-
mutex sync.RWMutex// `mutex` holds a RWMutex (Read-Write Mutex) that is used to protect the eviction algorithm from concurrent access
58
-
once sync.Once// `once` holds a Once struct that is used to ensure that the expiration and eviction loops are only started once
59
-
statsCollectorNamestring// `statsCollectorName` holds the name of the stats collector that the cache should use when collecting cache statistics
42
+
backend backend.IBackend[T] // `backend`` holds the backend that the cache uses to store the items. It must implement the IBackend interface.
43
+
cacheBackendChecker introspect.CacheBackendChecker[T] // `cacheBackendChecker` holds an instance of the CacheBackendChecker interface. It helps to determine the type of the backend.
44
+
itemPoolManager*cache.ItemPoolManager// `itemPoolManager` manages the item pool for the cache.
45
+
stopchanbool// `stop` channel to signal the expiration and eviction loops to stop
46
+
workerPool*WorkerPool// `workerPool` holds a pointer to the worker pool that the cache uses to run the expiration and eviction loops.
47
+
expirationTriggerChchanbool// `expirationTriggerCh` channel to signal the expiration trigger loop to start
0 commit comments