Analyzing the cache2go Go Caching Library

Overview

This analysis focuses on the cache2go library, a concurrency-safe caching solution written in Go. The goal is to dissect its core components and understand its design patterns. We will examine the project's strutcure, key data structures, and the implementation of its core functionalities, providing insihgts into how it manages cached data with expiration policies.

What is cache2go?

cache2go is an open-source Go library designed for caching data with expiration capabilities. It provides a thread-safe mechanism to store and retrieve data, automatically removing items that have expired. This makes it suitable for applications requiring efficient in-memory data storage with time-based invalidation.

Project Structure

The library's implementation is contained within three primary source files:

  • cache.go: Contains the main cache structure and high-level operations.
  • cacheitem.go: Defines the individual cache item and its associated methods.
  • cachetable.go: Implements the cache table, which is a collection of cache items.

Key Data Structures

The library's functionality revolves around two primary data structures: CacheItem and CacheTable.

1. CacheItem

Represents a single entry within the cache. It holds the data, metadata about its lifecycle, and callback functions.

// CacheEntry represents a single item stored in the cache.
// Parameter data holds the user-defined value.
type CacheEntry struct {
    sync.RWMutex

    // The unique identifier for this cache entry.
    identifier interface{}
    // The actual data stored in the cache.
    payload    interface{}
    // The duration for which the item remains valid without access.
    lifespan   time.Duration

    // Timestamp of when the item was created.
    createdAt  time.Time
    // Timestamp of the last access.
    lastAccess time.Time
    // Number of times the item has been accessed.
    accessCount int64
    // Callback function triggered before the item is removed.
    onExpiration func(key interface{})
}

2. CacheTable

Represents a table or namespace within the cache, containing multiple CacheItem instances.

// CacheTable represents a collection of cache entries.
type CacheTable struct {
    sync.RWMutex

    // The name of this cache table.
    tableName string
    // A map storing all cache entries within this table.
    entries   map[interface{}]*CacheEntry

    // Timer responsible for triggering cleanup operations.
    cleanupTimer *time.Timer
    // The interval at which cleanup is performed.
    cleanupInterval time.Duration

    // Logger for this specific table.
    logger *log.Logger

    // Callback function invoked when a non-existent key is accessed.
    dataLoader func(key interface{}, args ...interface{}) *CacheEntry
    // Callback function triggered when a new item is added.
    onItemAdded func(item *CacheEntry)
    // Callback function triggered before an item is deleted.
    onItemDeletion func(item *CacheEntry)
}

Code Logic: cacheitem.go

The cacheitem.go file defines the CacheEntry structure and its associated methods. Let's examine the key components.

NewCacheEntry Function

This function creates a new CacheEntry instance.

// NewCacheEntry creates a new cache entry.
// Parameter key is the unique identifier for the entry.
// Parameter lifespan specifies the duration the entry remains valid without access.
// Parameter data is the value to be stored.
func NewCacheEntry(key interface{}, lifespan time.Duration, data interface{}) *CacheEntry {
    now := time.Now()
    return &CacheEntry{
        identifier: key,
        payload:    data,
        lifespan:   lifespan,
        createdAt:  now,
        lastAccess: now,
        accessCount: 0,
        onExpiration: nil,
    }
}

CacheEntry Methods

The CacheEntry type has several methods to manage its state and provide access to its data.

// KeepAlive updates the last access time and increments the access count.
func (entry *CacheEntry) KeepAlive() {
    entry.Lock()
    defer entry.Unlock()
    entry.lastAccess = time.Now()
    entry.accessCount++
}

// Lifespan returns the duration for which the entry is valid.
func (entry *CacheEntry) Lifespan() time.Duration {
    return entry.lifespan
}

// LastAccessed returns the timestamp of the last access.
func (entry *CacheEntry) LastAccessed() time.Time {
    entry.RLock()
    defer entry.RUnlock()
    return entry.lastAccess
}

// CreatedAt returns the timestamp when the entry was created.
func (entry *CacheEntry) CreatedAt() time.Time {
    return entry.createdAt
}

// AccessCount returns the number of times the entry has been accessed.
func (entry *CacheEntry) AccessCount() int64 {
    entry.RLock()
    defer entry.RUnlock()
    return entry.accessCount
}

// Identifier returns the unique key of the cached entry.
func (entry *CacheEntry) Identifier() interface{} {
    return entry.identifier
}

// Payload returns the value stored in the cache entry.
func (entry *CacheEntry) Payload() interface{} {
    return entry.payload
}

// SetOnExpirationCallback configures a function to be called before the entry is removed.
func (entry *CacheEntry) SetOnExpirationCallback(callback func(key interface{})) {
    entry.Lock()
    defer entry.Unlock()
    entry.onExpiration = callback
}

These methods provide thread-safe access to the CacheEntry's properties and allow for managing its lifecycle, including updating access times and setting expiration callbacks. The next section will delve into the CacheTable implementation.

Tags: Go cache2go Caching Concurrency source code analysis

Posted on Wed, 13 May 2026 22:38:18 +0000 by franko75