inmem

package
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 18, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package inmem provides a thread-safe, configurable in-memory implementation of the cache.Cache and cache.TTLCache interfaces.

Overview

This package offers `SafeMapCache`, an in-memory cache using a Go map protected by a single `sync.RWMutex`. It supports item expiration (TTL), configurable capacity limits, and automatic removal of expired items via a background garbage collector.

Note: Due to the single mutex design, this implementation is best suited for low-to-moderate concurrency scenarios. High contention on the lock might become a bottleneck.

Features

  • Thread-Safe: Uses `sync.RWMutex` for safe concurrent operations.
  • Configurable: Accepts options via `NewSafeMap` for:
  • Default TTL (`WithDefaultTTL`, default: 0/no expiry).
  • Maximum number of items (`WithMaxSize`, default: 10000).
  • Garbage collection interval (`WithGCInterval`, default: 5 minutes, min: 5 seconds).
  • TTL Support: Items expire after their TTL (set via `SetWithTTL` or the configured default).
  • Size Limiting: Returns `cache.ErrCacheFull` if `Set` attempts to add a new item when the cache is at `MaxSize`.
  • Garbage Collection: A background goroutine periodically removes expired items based on the configured interval.
  • Efficient `Len()`: Provides an O(1) approximate count of active items using an atomic counter.
  • Explicit Cleanup: Requires calling the `Stop()` method to gracefully shut down the garbage collector and clear the cache.
  • Context Aware: Operations respect context cancellation/deadlines.
  • Testable Time: Uses a `Clock` interface for reliable time-based testing.

Usage

Create a new cache using `NewSafeMap`. It is **essential** to call the `Stop()` method when the cache is no longer needed to ensure the background garbage collector goroutine is terminated cleanly. Using `defer` is a common pattern.

// Cache with a default 1-hour TTL, max 5000 items, and 10-minute GC interval
cacheOpts := []inmem.SafeMapCacheOption[string, []byte]{
    inmem.WithDefaultTTL[string, []byte](1*time.Hour),
    inmem.WithMaxSize[string, []byte](5000),
    inmem.WithGCInterval[string, []byte](10*time.Minute),
}
c := inmem.NewSafeMap(cacheOpts...)
defer c.Stop(context.Background()) // Ensure Stop is called for cleanup

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

_ = c.Set(ctx, "config:data", someBytes) // Uses default TTL (1 hour)
_ = c.SetWithTTL(ctx, "session:abc", tokenBytes, 15*time.Minute) // Explicit TTL

val, err := c.Get(ctx, "config:data")
// ... handle error or use val ...

count := c.Len() // Get approximate count
fmt.Printf("Approximate items in cache: %d\n", count)

_ = c.Delete(ctx, "session:abc") // Mark session for deletion

Important Considerations

  • `Delete` Behavior: Calling `Delete(ctx, key)` marks the item as expired immediately (subsequent `Get(ctx, key)` will return `cache.ErrExpired`) and decrements the counter used by `Len()`. However, the key and value **remain in memory** until the next garbage collection cycle physically removes them from the underlying map. Memory is not reclaimed instantly upon calling `Delete`.
  • `Len()` Approximation: `Len()` returns the count of items considered active (added minus deleted/GC'd). It may include items that have passed their TTL but have not yet been removed by the garbage collector.
  • Memory Usage: Size is limited by available RAM and the `MaxSize` setting.
  • Resource Cleanup: **Failure to call the `Stop()` method will result in leaking the garbage collector goroutine.**

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewGarbageCollector

func NewGarbageCollector[K comparable, V any](interval time.Duration) *garbageCollector[K, V]

NewGarbageCollector creates a new garbage collector with the specified interval. The interval must be greater than 0. If not, nil is returned.

func NewSafeMap

func NewSafeMap[K comparable, V any](opts ...SafeMapCacheOption[K, V]) *safeMapCache[K, V]

NewSafeMap creates a new instance of safeMapCache. It initializes the items map and sets up the garbage collector. The garbage collector is started in a separate goroutine. The clock is set to the real time package by default.

Types

type Clock

type Clock interface {
	// Now returns the current time.
	Now() time.Time

	// NewTicker creates a new Ticker that will send ticks on the
	// returned channel. The ticks will be sent at intervals of d.
	NewTicker(d time.Duration) *time.Ticker
}

Clock is an interface that provides methods to get the current time, wait for a duration, and create a new ticker. It allows for easy mocking and testing of time-dependent code. The default implementation uses the real time package.

type GarbageCollector

type GarbageCollector[K comparable, V any] interface {
	// Start begins the garbage collection process.
	// This should be called in a separate goroutine.
	// E.g. go gc.Start(c)
	Start(c garbageCollection[K, V])

	// Stop stops the garbage collection process.
	Stop(ctx context.Context) error

	// IsActive returns true if the garbage collector is currently running.
	IsActive() bool
}

GarbageCollector is an interface that defines the methods for a garbage collector. It is responsible for periodically deleting expired items from the cache.

type SafeMapCache

type SafeMapCache[K comparable, V any] struct {
	// contains filtered or unexported fields
}

func (SafeMapCache) Clear

func (c SafeMapCache) Clear(ctx context.Context) error

Clear removes all items from the cache. It uses a write lock to ensure thread safety. It checks if the context is canceled or timed out. If the context is canceled or times out, it returns an error.

func (SafeMapCache) Delete

func (c SafeMapCache) Delete(ctx context.Context, key K) error

Delete sets an item from the cache to expire. It does not actually delete the item from the cache. The actual deletion is handled by the garbage collector. If the item does not exist, it does nothing. It uses a write lock to ensure thread safety. It checks if the context is canceled or timed out. If the context is canceled or times out, it returns an error. It also checks if the item exists before deleting it.

func (SafeMapCache) Get

func (c SafeMapCache) Get(ctx context.Context, key K) (V, error)

Get retrieves an item from the cache. It uses a read lock to ensure thread safety. It checks if the item exists and if it has expired. If the item is found and not expired, it returns the value. If the item is not found or expired, it returns an error. The context is used to check for cancellation or timeout. If the context is canceled or times out, it returns an error.

func (SafeMapCache) Len

func (c SafeMapCache) Len() int

Len returns an approximate of the number of items in the cache. It relies on a counter that is updated when items are added or deleted. This is not a precise count, but it is efficient and fast.

Example:

cache := NewSafeMap[string, any]()
// GC every minute
cache.SetWithTTL(context.Background(), "key", "value", 10*time.Second)
fmt.Print(cache.Len()) // 1
// Wait for 20 seconds
time.Sleep(20 * time.Second)
fmt.Print(cache.Len()) // 1 (item is expired but still counted)
// Wait for GC
time.Sleep(60 * time.Second)
fmt.Print(cache.Len()) // 0

func (SafeMapCache) Set

func (c SafeMapCache) Set(ctx context.Context, key K, value V) error

Set stores an item in the cache with no expiration. It uses a write lock to ensure thread safety. It checks if the context is canceled or timed out. If the context is canceled or times out, it returns an error.

func (SafeMapCache) SetWithTTL

func (c SafeMapCache) SetWithTTL(ctx context.Context, key K, value V, ttl time.Duration) error

SetWithTTL stores an item in the cache with a specified expiration time. It uses a write lock to ensure thread safety. It checks if the context is canceled or timed out. If the context is canceled or times out, it returns an error. It also checks if the TTL is valid (greater than 0).

func (SafeMapCache) Stop

func (c SafeMapCache) Stop(ctx context.Context) error

Stop stops the garbage collector and clears the cache. This method should be called when the cache is no longer needed.

type SafeMapCacheOption

type SafeMapCacheOption[K comparable, V any] func(*safeMapCache[K, V])

func WithDefaultTTL

func WithDefaultTTL[K comparable, V any](ttl time.Duration) SafeMapCacheOption[K, V]

WithDefaultTTL sets the default time-to-live (TTL) for items in the cache. If the TTL is set to 0, items will not expire. The default TTL is 0, meaning items will not expire by default.

func WithGCInterval

func WithGCInterval[K comparable, V any](interval time.Duration) SafeMapCacheOption[K, V]

WithGCInterval sets the interval for the garbage collector. The garbage collector will run at this interval to delete expired items. The default interval is 5 minutes. It cannot be lower than 5 seconds.

func WithMaxSize

func WithMaxSize[K comparable, V any](size int) SafeMapCacheOption[K, V]

WithMaxSize sets the maximum size of the cache. If the cache exceeds this size, it will not accept new items. The default size is 10000.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL