cache

package
v0.0.0-...-6067653 Latest Latest
Warning

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

Go to latest
Published: Aug 11, 2025 License: Apache-2.0 Imports: 2 Imported by: 0

README

cache

Thread-safe generic LRU (Least Recently Used) cache implementation with configurable capacity and eviction callbacks.

Features

  • Generic implementation supporting any comparable key type and any value type
  • Thread-safe concurrent access with proper locking
  • Configurable capacity with automatic eviction of least recently used items
  • Optional eviction callbacks for cleanup operations
  • Zero external dependencies using standard library only

Installation

go get github.com/dmitrymomot/saaskit

Usage

package main

import (
    "fmt"
    "github.com/dmitrymomot/saaskit/pkg/cache"
)

func main() {
    // Create cache with capacity of 3 items
    c := cache.NewLRUCache[string, int](3)
    
    // Add items
    c.Put("user:1", 100)
    c.Put("user:2", 200)
    c.Put("user:3", 300)
    
    // Get item (moves to front)
    if value, ok := c.Get("user:1"); ok {
        fmt.Printf("Found: %d\n", value) // Found: 100
    }
    
    // Add fourth item (evicts least recently used)
    c.Put("user:4", 400)
    
    // user:2 was evicted (least recently used)
    if _, ok := c.Get("user:2"); !ok {
        fmt.Println("user:2 was evicted")
    }
}

Common Operations

Basic Cache Operations
c := cache.NewLRUCache[string, string](10)

// Put items
oldValue, existed := c.Put("key", "value")

// Get items
value, found := c.Get("key")

// Remove items
removedValue, existed := c.Remove("key")

// Check size
size := c.Len()

// Clear all items
c.Clear()
Eviction Callbacks
c := cache.NewLRUCache[string, *Resource](5)

// Set cleanup callback
c.SetEvictCallback(func(key string, resource *Resource) {
    fmt.Printf("Evicting %s\n", key)
    resource.Close() // cleanup resources
})

// Items will trigger callback when evicted
c.Put("resource1", &Resource{})
Concurrent Usage
c := cache.NewLRUCache[int, string](100)

// Safe for concurrent access
go func() {
    c.Put(1, "value1")
}()

go func() {
    if val, ok := c.Get(1); ok {
        fmt.Println(val)
    }
}()

API Documentation

Types
type LRUCache[K comparable, V any] struct {
    // Contains filtered or unexported fields
}
Functions
// NewLRUCache creates a new LRU cache with specified capacity
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]

// SetEvictCallback sets callback for when items are evicted
func (c *LRUCache[K, V]) SetEvictCallback(fn func(key K, value V))

// Get retrieves value and marks as recently used
func (c *LRUCache[K, V]) Get(key K) (V, bool)

// Put adds/updates value, returns previous value if existed
func (c *LRUCache[K, V]) Put(key K, value V) (V, bool)

// Remove removes item and returns its value
func (c *LRUCache[K, V]) Remove(key K) (V, bool)

// Len returns current number of items
func (c *LRUCache[K, V]) Len() int

// Clear removes all items (calls eviction callback)
func (c *LRUCache[K, V]) Clear()

For detailed API documentation:

go doc -all ./pkg/cache

Or visit pkg.go.dev for online documentation.

Notes

  • Cache capacity must be positive, otherwise NewLRUCache panics
  • All operations are O(1) time complexity
  • Memory usage is O(capacity) for the cache structure
  • Eviction callbacks are called synchronously during eviction operations

Documentation

Overview

Package cache provides a generic, thread-safe LRU (Least Recently Used) cache implementation for efficiently managing limited resources in memory.

The cache automatically evicts the least recently used items when it reaches its configured capacity, making it ideal for scenarios where you need to cache data but want to prevent unbounded memory growth.

Key Features

  • Generic implementation supporting any comparable key type and any value type
  • Thread-safe operations with mutex-based synchronization
  • Automatic LRU eviction when capacity is exceeded
  • Optional eviction callbacks for resource cleanup (e.g., closing files, connections)
  • Zero dependencies - uses only Go standard library
  • O(1) operations for Get, Put, and Remove

Usage

Create a cache with a specified capacity:

cache := cache.NewLRUCache[string, *sql.DB](100)

Basic operations:

// Add items to cache
cache.Put("user:123", userData)
cache.Put("session:abc", sessionData)

// Retrieve items (marks as recently used)
data, found := cache.Get("user:123")
if found {
	// Use data
}

// Remove specific items
removed, existed := cache.Remove("user:123")

// Clear all items
cache.Clear()

Resource Cleanup

For resources that need cleanup when evicted (like database connections, file handles, or network connections), use eviction callbacks:

cache := cache.NewLRUCache[string, *sql.DB](10)
cache.SetEvictCallback(func(key string, db *sql.DB) {
	db.Close() // Cleanup database connection
})

// Cache will automatically close connections when they're evicted
cache.Put("db1", db1)
cache.Put("db2", db2)

Thread Safety

All operations are thread-safe and can be called concurrently from multiple goroutines:

// Safe to call from multiple goroutines
go cache.Put("key1", value1)
go cache.Put("key2", value2)
go cache.Get("key1")

Performance Characteristics

  • Get: O(1) average case
  • Put: O(1) average case
  • Remove: O(1) average case
  • Memory overhead: Approximately 3x the size of stored values due to internal bookkeeping structures

Use Cases

The cache is particularly useful for:

  • Database connection pooling with automatic cleanup
  • Caching expensive computation results
  • Storing frequently accessed configuration data
  • Managing limited resources like file handles or API clients
  • Session data caching in web applications
  • Template or compiled expression caching

Capacity Management

When the cache reaches its capacity and a new item is added:

  1. The least recently used item is identified
  2. If an eviction callback is set, it's called with the item's key and value
  3. The item is removed from the cache
  4. The new item is added

Items are considered "recently used" when they are:

  • Retrieved with Get()
  • Added or updated with Put()

Example: Database Connection Cache

type ConnectionCache struct {
	cache *cache.LRUCache[string, *sql.DB]
}

func NewConnectionCache(maxConnections int) *ConnectionCache {
	c := &ConnectionCache{
		cache: cache.NewLRUCache[string, *sql.DB](maxConnections),
	}

	// Setup cleanup for evicted connections
	c.cache.SetEvictCallback(func(dsn string, db *sql.DB) {
		db.Close()
	})

	return c
}

func (c *ConnectionCache) GetConnection(dsn string) (*sql.DB, error) {
	if db, found := c.cache.Get(dsn); found {
		return db, nil
	}

	db, err := sql.Open("postgres", dsn)
	if err != nil {
		return nil, err
	}

	c.cache.Put(dsn, db)
	return db, nil
}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type LRUCache

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

LRUCache is a thread-safe LRU cache implementation. When the cache reaches its capacity, the least recently used item is evicted.

func NewLRUCache

func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]

NewLRUCache creates a new LRU cache with the specified capacity. The capacity must be positive, otherwise it panics.

func (*LRUCache[K, V]) Clear

func (c *LRUCache[K, V]) Clear()

Clear removes all items from the cache. If an evict callback is set, it's called for each item.

func (*LRUCache[K, V]) Get

func (c *LRUCache[K, V]) Get(key K) (V, bool)

Get retrieves a value from the cache and marks it as recently used. Returns the value and true if found, zero value and false otherwise.

func (*LRUCache[K, V]) Len

func (c *LRUCache[K, V]) Len() int

func (*LRUCache[K, V]) Put

func (c *LRUCache[K, V]) Put(key K, value V) (V, bool)

Put adds or updates a value in the cache. If the cache is at capacity, the least recently used item is evicted. Returns the previous value if it existed, and a boolean indicating if it existed.

func (*LRUCache[K, V]) Remove

func (c *LRUCache[K, V]) Remove(key K) (V, bool)

Remove removes an item from the cache. Returns the removed value and true if it existed, zero value and false otherwise.

func (*LRUCache[K, V]) SetEvictCallback

func (c *LRUCache[K, V]) SetEvictCallback(fn func(key K, value V))

SetEvictCallback sets a callback function that is called when items are evicted. This is useful for cleanup operations like closing resources.

Jump to

Keyboard shortcuts

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