hashicorp/golang-lru

repository·main·Indexed 26 days ago

https://github.com/hashicorp/golang-lru

A fixed-size, thread-safe Least Recently Used (LRU) cache implementation for Go. It provides standard LRU caches, expirable caches with TTL, TwoQueueCache (2Q) to separate frequent and recent entries, and Adaptive Replacement Cache (ARC) to track both frequency and recency.

Tokens
2.2K
Snippets
2
Records
20
Agent score
87%

What's inside golang-lru

  1. Use a fixed-size thread-safe LRU cache

    main

    The lru package provides a fixed-size, thread-safe Least Recently Used (LRU) cache. You can initialize a new cache using lru.New[K, V](size), where K is the key type, V is the value type, and size is the maximum number of items allowed in the cache. Use Add(key, value) to insert items and Len() to check the current number of items.

    package main
    
    import (
    	"fmt"
    	"github.com/hashicorp/golang-lru/v2"
    )
    
    func main() {
    	l, _ := lru.New[int, any](128)
    	for i := 0; i < 256; i++ {
    		l.Add(i, nil)
    	}
    	if l.Len() != 128 {
    		panic(fmt.Sprintf("bad len: %v", l.Len()))
    	}
    }
  2. Use an expirable LRU cache with TTL

    main

    The expirable package provides an LRU cache where items expire after a specified Time To Live (TTL). Initialize it using expirable.NewLRU[K, V](size, onEvict, ttl), where onEvict is an optional callback function and ttl is a time.Duration. Use Add(key, value) to set items and Get(key) to retrieve them. If an item has exceeded its TTL, Get will return ok == false.

    package main
    
    import (
    	"fmt"
    	"time"
    
    	"github.com/hashicorp/golang-lru/v2/expirable"
    )
    
    func main() {
    	// make cache with 10ms TTL and 5 max keys
    	cache := expirable.NewLRU[string, string](5, nil, time.Millisecond*10)
    
    
    	// set value under key1.
    	cache.Add("key1", "val1")
    
    	// get value under key1
    	r, ok := cache.Get("key1")
    
    	// check for OK value
    	if ok {
    		fmt.Printf("value before expiration is found: %v, value: %q\n", ok, r)
    	}
    
    	// wait for cache to expire
    	time.Sleep(time.Millisecond * 12)
    
    	// get value under key1 after key expiration
    	r, ok = cache.Get("key1")
    	fmt.Printf("value after expiration is found: %v, value: %q\n", ok, r)
    
    	// set value under key2, would evict old entry because it is already expired.
    	cache.Add("key2", "val2")
    
    	fmt.Printf("Cache len: %d\n", cache.Len())
    	// Output:
    	// value before expiration is found: true, value: "val1"
    	// value after expiration is found: false, value: ""
    	// Cache len: 1
    }
  3. Initialize an Adaptive Replacement Cache (ARC) with NewARC

    main
    Use NewARC to create a thread-safe, fixed-size Adaptive Replacement Cache. ARC tracks both frequency and recency of use to prevent new entries from evicting frequently used older entries. It is computationally roughly 2x the cost of a standard LRU and has linear memory overhead relative to cache size.
  4. Use TwoQueueCache methods: Get, Add, and Remove

    main

    The TwoQueueCache provides standard cache operations. Note that Get promotes items from the 'recent' queue to the 'frequent' queue upon access.

    • Get(key K) (value V, ok bool): Retrieves a value. If the key is in the 'recent' queue, it is promoted to 'frequent'.
    • Add(key K, value V): Adds or updates an entry. If a recently evicted key is re-added, it is promoted directly to 'frequent'.
    • Remove(key K): Deletes a specific key from the cache.
    • Purge(): Clears all entries from the cache.
  5. Retrieve all Keys and Values from TwoQueueCache

    main

    You can extract all keys or values from the cache. In both cases, the items from the frequent queue are returned first, followed by items from the recent queue.

    • Keys() []K: Returns a slice of all keys.
    • Values() []V: Returns a slice of all values.
  6. Manage TwoQueueCache size and capacity

    main

    You can query the current state of the cache or adjust its capacity dynamically:

    • Len() int: Returns the current number of items in the cache (recent + frequent).
    • Cap() int: Returns the total capacity of the cache.
    • Resize(size int) (evicted int): Changes the cache capacity. Returns the number of items that were evicted to accommodate the new size.
  7. Perform conditional Add operations

    main

    The Cache provides two methods for conditional insertion:

    1. ContainsOrAdd(key K, value V): Checks if a key exists without updating recency. If not found, adds the value. Returns (ok, evicted).
    2. PeekOrAdd(key K, value V): Checks if a key exists without updating recency. If not found, adds the value. Returns (previousValue, ok, evicted).
  8. Initialize a TwoQueueCache

    main

    A TwoQueueCache is a thread-safe, fixed-size cache that separates frequently used and recently used entries to prevent new bursts of access from evicting frequent items. You can initialize it using default parameters or by providing custom ratios.

    • New2Q(size int): Creates a cache with default recentRatio (0.25) and ghostRatio (0.50).
    • New2QParams(size int, recentRatio float64, ghostRatio float64): Creates a cache with custom ratios. Both ratios must be between 0.0 and 1.0.
  9. Retrieve items from the cache

    main

    Use Get(key K) to retrieve a value and a boolean indicating if the key was found. Note that Get updates the item's position to 'most recently used'.

    Use Peek(key K) to retrieve a value without updating its 'recently used' status.

    Use Contains(key K) to check for existence without updating its 'recently used' status.

  10. Get cache metadata and all keys/values

    main

    The following methods allow you to inspect the state of the cache:

    • Len() int: Returns the current number of cached entries (T1 + T2).
    • Cap() int: Returns the total capacity of the cache.
    • Keys() []K: Returns a slice containing all cached keys.
    • Values() []V: Returns a slice containing all cached values.
  11. Inspect cache contents without updating recency or frequency

    main

    Use Contains and Peek to check for existence or retrieve values without triggering the ARC adaptation logic (recency/frequency updates).

    • Contains(key K) bool: Returns true if the key exists in the cache.
    • Peek(key K) (value V, ok bool): Returns the value and a boolean indicating if the key was found.