go-cache

cache libraryGoGolangin-memory cachethread-safeexpiration

GitHub Overview

patrickmn/go-cache

An in-memory key:value store/cache (similar to Memcached) library for Go, suitable for single-machine applications.

Stars8,675
Watchers117
Forks900
Created:January 2, 2012
Language:Go
License:MIT License

Topics

cachegolibrary

Star History

patrickmn/go-cache Star History
Data as of: 10/22/2025, 08:07 AM

Cache Library

go-cache

Overview

go-cache (patrickmn/go-cache) is an in-memory key:value store/cache library for Go, similar to memcached. It's suitable for applications running on a single machine and is essentially a thread-safe map[string]interface{} with expiration times.

Details

go-cache is very simple and fast because it doesn't need to serialize or transmit its contents over the network. Any object can be stored, for a given duration or forever, and the cache can be safely used by multiple goroutines. The entire cache can be saved to and loaded from a file to recover from downtime quickly.

Internally, it can be configured with a default expiration time (e.g., 5 minutes) and cleanup interval (e.g., 10 minutes), periodically removing expired items. It provides simple yet practical functionality and is a very user-friendly cache solution for Go developers.

Pros and Cons

Pros

  • Simple and intuitive API design
  • Thread-safe, safely accessible from multiple goroutines
  • Memcached-like user experience
  • Fast operation without network serialization
  • Can store arbitrary Go objects
  • Automatic expired item removal
  • File save/load functionality for downtime recovery
  • Optimal for single-machine applications

Cons

  • Single-machine limitation (no distributed cache support)
  • Limited functionality compared to other cache systems (Redis, Memcached, etc.)
  • Not suitable for large-scale data or complex cache strategies
  • Few detailed memory usage control features
  • No network access capability

Reference Links

Code Examples

Basic Setup

package main

import (
    "fmt"
    "time"
    "github.com/patrickmn/go-cache"
)

func main() {
    // Create cache with 5 minute default expiration and 10 minute cleanup interval
    c := cache.New(5*time.Minute, 10*time.Minute)
}

Basic Set/Get Operations

// Store string
c.Set("username", "john_doe", cache.DefaultExpiration)

// Store arbitrary object
user := map[string]interface{}{
    "id":   123,
    "name": "John Doe",
    "email": "[email protected]",
}
c.Set("user:123", user, cache.DefaultExpiration)

// Get value
username, found := c.Get("username")
if found {
    fmt.Printf("Username: %s\n", username.(string))
}

// Get with type assertion
if userData, found := c.Get("user:123"); found {
    if userMap, ok := userData.(map[string]interface{}); ok {
        fmt.Printf("User: %v\n", userMap)
    }
}

Expiration Time Specification

// Expire after 1 hour
c.Set("temp_data", "temporary", 1*time.Hour)

// Store permanently (no expiration)
c.Set("config", "permanent_value", cache.NoExpiration)

// Use default expiration
c.Set("default_ttl", "uses_default", cache.DefaultExpiration)

// Expire after 10 seconds
c.Set("short_lived", "quick_access", 10*time.Second)

Add and Increment Operations

// Add only if key doesn't exist
err := c.Add("counter", 1, cache.DefaultExpiration)
if err != nil {
    fmt.Printf("Key already exists: %v\n", err)
}

// Increment numeric value
c.Set("views", 100, cache.DefaultExpiration)
newValue, err := c.Increment("views", 1)
if err == nil {
    fmt.Printf("New view count: %d\n", newValue)
}

// Decrement
newValue, err = c.Decrement("views", 5)
if err == nil {
    fmt.Printf("Decremented view count: %d\n", newValue)
}

// Increment float64
c.Set("score", 10.5, cache.DefaultExpiration)
newScore, err := c.IncrementFloat("score", 2.3)
if err == nil {
    fmt.Printf("New score: %.2f\n", newScore)
}

Cache Management Operations

// Delete item
c.Delete("username")

// Check key existence (with expiration check)
_, found := c.Get("user:123")
fmt.Printf("User exists: %t\n", found)

// Get all items
items := c.Items()
fmt.Printf("Total items: %d\n", len(items))

// Manually delete expired items
c.DeleteExpired()

// Clear entire cache
c.Flush()

Expiration Check and Update

// Check item expiration
if item, found := c.get("user:123"); found {
    fmt.Printf("Expires at: %v\n", item.Expiration)
}

// Update expiration (maintain existing value, change only expiration)
if currentValue, found := c.Get("user:123"); found {
    c.Set("user:123", currentValue, 2*time.Hour) // Extend to 2 hours
}

// TTL implementation (using Go standard library)
func getTTL(c *cache.Cache, key string) time.Duration {
    if item, found := c.get(key); found {
        if item.Expiration > 0 {
            return time.Until(time.Unix(0, item.Expiration))
        }
        return -1 // NoExpiration
    }
    return 0 // Not found
}

File Save and Restore

// Save cache to file
items := c.Items()
err := saveToFile("cache_backup.gob", items)
if err != nil {
    fmt.Printf("Save error: %v\n", err)
}

// Restore cache from file
items, err := loadFromFile("cache_backup.gob")
if err != nil {
    fmt.Printf("Load error: %v\n", err)
} else {
    // Create new cache with restored items
    restoredCache := cache.NewFrom(cache.DefaultExpiration, 10*time.Minute, items)
}

// File save helper function example
func saveToFile(filename string, items map[string]cache.Item) error {
    // Serialize using encoding/gob or json
    // Implementation depends on specific requirements
    return nil
}

Configuration and Customization

// Custom cleanup interval
c := cache.New(30*time.Minute, 1*time.Minute) // Cleanup every minute

// Disable cleanup (manual management)
c := cache.New(30*time.Minute, -1)

// Custom callback functionality (pseudo-implementation)
c.OnEvicted(func(key string, value interface{}) {
    fmt.Printf("Evicted: %s = %v\n", key, value)
})

// Usage statistics tracking (requires custom implementation)
type StatsCache struct {
    *cache.Cache
    hits   int64
    misses int64
}

func (s *StatsCache) Get(key string) (interface{}, bool) {
    value, found := s.Cache.Get(key)
    if found {
        s.hits++
    } else {
        s.misses++
    }
    return value, found
}