diff --git a/lru.go b/lru.go index ca16c59..34f2f3b 100644 --- a/lru.go +++ b/lru.go @@ -5,7 +5,18 @@ import ( "time" ) -// NewLRU creates a new LRUCache with the specified capacity. +// NewLRU creates a new LRU cache with the specified capacity. +// +// Parameters: +// - capacity: The maximum number of items the cache can hold. +// +// Returns: +// - A pointer to an initialized LRU cache. +// +// Details: +// - The cache uses a combination of a map and a doubly linked list for efficient +// O(1) insertion, deletion, and lookup operations. +// - Items are evicted based on the "least recently used" policy when the capacity is exceeded. func NewLRU(capacity int) *LRU { return &LRU{ capacity: capacity, @@ -14,15 +25,34 @@ func NewLRU(capacity int) *LRU { } } -// NewLRUCache creates a new LRUCache with the specified capacity and an optional eviction callback. +// NewLRUCallback creates a new LRU cache with the specified capacity and eviction callback. +// +// Parameters: +// - capacity: The maximum number of items the cache can hold. +// - callback: A function of type `OnCallback` that gets invoked when an item is evicted. +// +// Returns: +// - A pointer to an initialized LRU cache. +// +// Details: +// - The callback function is executed before an item is removed from the cache. func NewLRUCallback(capacity int, callback OnCallback) *LRU { c := NewLRU(capacity) c.onEvict = callback return c } -// NewLRUCache creates a new LRUCache with the specified capacity, an optional eviction callback, -// and an optional time-to-live for cache entries. +// NewLRUExpires creates a new LRU cache with a time-to-live for entries. +// +// Parameters: +// - capacity: The maximum number of items the cache can hold. +// - expiry: The expiration duration for each cache entry. +// +// Returns: +// - A pointer to an initialized LRU cache. +// +// Details: +// - Starts a background goroutine to periodically remove expired items. func NewLRUExpires(capacity int, expiry time.Duration) *LRU { c := NewLRU(capacity) c.SetExpiry(expiry) @@ -32,7 +62,18 @@ func NewLRUExpires(capacity int, expiry time.Duration) *LRU { return c } -// Get retrieves a value from the cache based on the key. +// Get retrieves the value associated with a given key from the cache. +// +// Parameters: +// - key: The key whose value is to be retrieved. +// +// Returns: +// - The value associated with the key, or nil if the key is not found. +// - A boolean indicating whether the key exists. +// +// Details: +// - Moves the accessed item to the front of the list, marking it as most recently used. +// - Evicts the item if it is expired (when expiration is enabled). func (c *LRU) Get(key string) (value interface{}, ok bool) { c.mutex.RLock() defer c.mutex.RUnlock() @@ -51,7 +92,13 @@ func (c *LRU) Get(key string) (value interface{}, ok bool) { return nil, false } -// GetAll returns all key-value pairs in the cache. +// GetAll retrieves all key-value pairs currently in the cache. +// +// Returns: +// - A map containing all key-value pairs in the cache. +// +// Details: +// - Does not modify the order of items in the cache. func (c *LRU) GetAll() map[string]interface{} { c.mutex.RLock() defer c.mutex.RUnlock() @@ -64,7 +111,11 @@ func (c *LRU) GetAll() map[string]interface{} { return allEntries } -// Pairs returns the least recently used key-value pair without removing it from the cache. +// Pairs retrieves the least recently used key-value pair without removing it. +// +// Returns: +// - The key and value of the least recently used item. +// - A boolean indicating whether such an item exists. func (c *LRU) Pairs() (key string, value interface{}, ok bool) { c.mutex.RLock() defer c.mutex.RUnlock() @@ -77,7 +128,16 @@ func (c *LRU) Pairs() (key string, value interface{}, ok bool) { return "", nil, false } -// Set adds a key-value pair to the cache. If the cache is full, it removes the least recently used item. +// Set inserts or updates a key-value pair in the cache. +// +// Parameters: +// - key: The key to be added or updated. +// - value: The value to be associated with the key. +// +// Details: +// - If the key exists, updates its value and moves it to the front of the list. +// - If the key does not exist and the cache is full, evicts the least recently used item. +// - The expiration time is reset or initialized based on the cache's expiration setting. func (c *LRU) Set(key string, value interface{}) { c.mutex.Lock() defer c.mutex.Unlock() @@ -108,7 +168,10 @@ func (c *LRU) Set(key string, value interface{}) { } } -// Update updates the value associated with a specific key in the cache. +// Update updates the value associated with a key in the cache. +// Parameters: +// - key: The key to update. +// - value: The new value to associate with the key. func (c *LRU) Update(key string, value interface{}) { c.mutex.Lock() defer c.mutex.Unlock() @@ -121,7 +184,13 @@ func (c *LRU) Update(key string, value interface{}) { } } -// Remove removes a specific key from the cache. +// Remove deletes a specific key-value pair from the cache. +// +// Parameters: +// - key: The key to be removed. +// +// Details: +// - If the key does not exist, the method does nothing. func (c *LRU) Remove(key string) { c.mutex.Lock() defer c.mutex.Unlock() @@ -130,7 +199,10 @@ func (c *LRU) Remove(key string) { } } -// Clear removes all items from the cache. +// Clear removes all key-value pairs from the cache. +// +// Details: +// - Resets the internal data structures to their initial state. func (c *LRU) Clear() { c.mutex.Lock() defer c.mutex.Unlock() @@ -138,7 +210,10 @@ func (c *LRU) Clear() { c.list.Init() } -// Len returns the number of items in the cache. +// Len returns the current number of items in the cache. +// +// Returns: +// - The number of items in the cache. func (c *LRU) Len() int { c.mutex.RLock() defer c.mutex.RUnlock() @@ -146,6 +221,9 @@ func (c *LRU) Len() int { } // IsEmpty checks if the cache is empty. +// +// Returns: +// - A boolean indicating whether the cache contains no items. func (c *LRU) IsEmpty() bool { return c.Len() == 0 } @@ -187,13 +265,35 @@ func (c *LRU) SetCapacity(capacity int) { } // SetCallback sets the eviction callback function. +// +// Parameters: +// - callback: A function of type `OnCallback` to be invoked when an item is evicted from the cache. +// +// Details: +// - Uses write locking to ensure thread-safe updates to the `onEvict` field. +// - Replaces the existing callback (if any) with the provided one. +// - This callback function will be triggered during evictions, allowing custom behavior +// (e.g., logging, cleanup, or persisting evicted data). +// +// Example Usage: +// +// cache.SetCallback(func(key string, value interface{}) { +// fmt.Printf("Evicted: key=%s, value=%v\n", key, value) +// }) func (c *LRU) SetCallback(callback OnCallback) { c.mutex.Lock() defer c.mutex.Unlock() c.onEvict = callback } -// SetExpiry updates the expiration time for cache entries. +// SetExpiry sets the default expiration duration for cache entries. +// +// Parameters: +// - expiry: The duration after which a cache entry should expire. +// +// Details: +// - This affects only new entries or updated entries after the call to SetExpiry. +// - Existing entries retain their current expiration times until updated. func (c *LRU) SetExpiry(expiry time.Duration) { c.mutex.Lock() defer c.mutex.Unlock() @@ -201,6 +301,15 @@ func (c *LRU) SetExpiry(expiry time.Duration) { } // GetStates returns a snapshot of the current cache state. +// +// Returns: +// - A slice of `state` objects representing all the items in the cache. +// - Each `state` includes the key, value, access time, and expiration time. +// +// Details: +// - Uses read locking to ensure safe concurrent access. +// - Iterates through all cache entries, capturing their metadata. +// - Creates a new `state` object for each entry using a builder-like pattern. func (c *LRU) GetStates() []state { c.mutex.RLock() defer c.mutex.RUnlock() @@ -219,7 +328,16 @@ func (c *LRU) GetStates() []state { return snapshot } -// GetState returns the metadata of the least recently used item without removing it from the cache. +// GetState returns the metadata of the least recently used (LRU) item without removing it. +// +// Returns: +// - A pointer to a `state` object representing the LRU item, or nil if the cache is empty. +// - A boolean indicating whether a valid state was retrieved. +// +// Details: +// - Uses read locking to safely access the cache state. +// - Retrieves the least recently used item from the tail of the doubly-linked list. +// - Constructs a `state` object to represent the item's metadata. func (c *LRU) GetState() (m *state, ok bool) { c.mutex.RLock() defer c.mutex.RUnlock() @@ -238,6 +356,17 @@ func (c *LRU) GetState() (m *state, ok bool) { } // IsMostRecentlyUsed checks if a specific key is the most recently used item in the cache. +// +// Parameters: +// - key: The key to check. +// +// Returns: +// - true if the specified key is the most recently used item. +// - false otherwise or if the cache is empty. +// +// Details: +// - Uses read locking to safely access the cache state. +// - Compares the provided key with the key of the item at the front of the list (MRU). func (c *LRU) IsMostRecentlyUsed(key string) bool { c.mutex.RLock() defer c.mutex.RUnlock() @@ -249,7 +378,16 @@ func (c *LRU) IsMostRecentlyUsed(key string) bool { return false } -// GetMostRecentlyUsed returns the most recently used key-value pair without removing it from the cache. +// GetMostRecentlyUsed returns the most recently used (MRU) key-value pair without removing it. +// +// Returns: +// - A pointer to a `state` object representing the MRU item, or nil if the cache is empty. +// - A boolean indicating whether a valid state was retrieved. +// +// Details: +// - Uses read locking to safely access the cache state. +// - Retrieves the most recently used item from the head of the doubly-linked list. +// - Constructs a `state` object to represent the item's metadata. func (c *LRU) GetMostRecentlyUsed() (m *state, ok bool) { c.mutex.RLock() defer c.mutex.RUnlock() @@ -268,6 +406,15 @@ func (c *LRU) GetMostRecentlyUsed() (m *state, ok bool) { } // ExpandExpiry extends the expiration time of a specific key in the cache. +// +// Parameters: +// - key: The key of the cache entry to extend the expiration for. +// - expiry: The duration by which to extend the expiration time. +// +// Details: +// - Uses write locking to ensure safe updates. +// - If the key exists, updates its expiration time and moves it to the front of the list. +// - Does nothing if the key does not exist in the cache. func (c *LRU) ExpandExpiry(key string, expiry time.Duration) { c.mutex.Lock() defer c.mutex.Unlock() @@ -280,6 +427,18 @@ func (c *LRU) ExpandExpiry(key string, expiry time.Duration) { } // PersistExpiry returns the remaining time until expiration for a specific key. +// +// Parameters: +// - key: The key of the cache entry to check. +// +// Returns: +// - The remaining time until the entry expires. +// - A boolean indicating whether the key exists in the cache. +// +// Details: +// - Uses read locking to safely access the cache state. +// - If the key exists, calculates the time remaining until expiration. +// - Returns 0 and false if the key does not exist. func (c *LRU) PersistExpiry(key string) (remain time.Duration, ok bool) { c.mutex.RLock() defer c.mutex.RUnlock() @@ -295,12 +454,21 @@ func (c *LRU) PersistExpiry(key string) (remain time.Duration, ok bool) { return 0, false } -// DestroyCleanup stops the background goroutine for periodic cache cleanup. +// DestroyCleanup stops the background cleanup process. +// +// Details: +// - Should be called when the cache is no longer needed to prevent goroutine leaks. func (c *LRU) DestroyCleanup() { close(c.stopCleanup) } -// evict evicts an element from the cache. +// evict removes a given element from the cache. +// +// Parameters: +// - element: The list element to be removed. +// +// Details: +// - Executes the eviction callback (if any) before removal. func (c *LRU) evict(element *list.Element) { // Invoke the eviction callback before removing the item if c.onEvict != nil { @@ -311,7 +479,10 @@ func (c *LRU) evict(element *list.Element) { c.list.Remove(element) } -// cleanupExpired removes expired entries from the cache. +// cleanupExpired removes all expired entries from the cache. +// +// Details: +// - Iterates through all items and evicts those that have exceeded their expiration time. func (c *LRU) cleanupExpired() { c.mutex.Lock() defer c.mutex.Unlock() @@ -326,7 +497,11 @@ func (c *LRU) cleanupExpired() { } } -// startCleanup starts a background goroutine for periodic cache cleanup. +// startCleanup starts a background goroutine to periodically remove expired entries. +// +// Details: +// - Runs a cleanup operation at regular intervals to evict expired items. +// - Stops when the `stopCleanup` channel is closed. func (c *LRU) startCleanup() { ticker := time.NewTicker(c.expiration / 2) // Run cleanup at half the expiration interval defer ticker.Stop() @@ -340,7 +515,13 @@ func (c *LRU) startCleanup() { } } -// calculateExpiry calculates the expiration time for a cache entry. +// calculateExpiry calculates the expiration time for a new cache entry. +// +// Returns: +// - A time.Time value representing the expiration time. +// +// Details: +// - If no expiration is set, returns the zero value for time.Time. func (c *LRU) calculateExpiry() time.Time { if c.expiration > 0 { return time.Now().Add(c.expiration) diff --git a/types.go b/types.go index 391afd2..c53d6fe 100644 --- a/types.go +++ b/types.go @@ -7,9 +7,22 @@ import ( ) // OnCallback is a callback function type that gets called when an item is evicted from the cache. +// Parameters: +// - key: The key of the item being evicted. +// - value: The value associated with the key. type OnCallback func(key string, value interface{}) -// LRU represents the LRU cache. +// LRU represents an implementation of a Least Recently Used (LRU) cache. +// It provides thread-safe operations, optional entry expiration, and an eviction callback. +// +// Fields: +// - capacity: The maximum number of items the cache can hold. +// - cache: A map for quick access to cache entries by key. +// - list: A doubly linked list for maintaining access order. +// - mutex: A read-write lock to ensure thread-safe operations. +// - onEvict: An optional callback function invoked when an item is evicted. +// - expiration: The duration for which entries are valid in the cache. Zero means no expiration. +// - stopCleanup: A channel used to signal stopping of the background cleanup goroutine. type LRU struct { capacity int cache map[string]*list.Element @@ -20,7 +33,12 @@ type LRU struct { stopCleanup chan struct{} } -// state represents the state of the least recently used item. +// state represents metadata about the least recently used item. +// Fields: +// - key: The key of the cache entry. +// - value: The value associated with the key. +// - accessTime: The last time the entry was accessed. +// - expiration: The expiration time of the entry. type state struct { key string value interface{} @@ -28,7 +46,11 @@ type state struct { expiration time.Time } -// entries represents a key-value pair in the cache. +// entries represents a cache entry with associated metadata. +// Fields: +// - key: The key of the entry. +// - value: The value associated with the key. +// - expiration: The expiration time of the entry. type entries struct { key string value interface{}