Documentation
¶
Overview ¶
Package bdcache provides a high-performance cache with S3-FIFO eviction and optional persistence.
Index ¶
- type Cache
- func (c *Cache[K, V]) Cleanup() int
- func (c *Cache[K, V]) Close() error
- func (c *Cache[K, V]) Delete(ctx context.Context, key K)
- func (c *Cache[K, V]) Get(ctx context.Context, key K) (value V, found bool, err error)
- func (c *Cache[K, V]) Len() int
- func (c *Cache[K, V]) Set(ctx context.Context, key K, value V, ttl time.Duration) error
- type Entry
- type Option
- type Options
- type PersistenceLayer
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Cache ¶
type Cache[K comparable, V any] struct { // contains filtered or unexported fields }
Cache is a generic cache with memory and optional persistence layers.
Example (Basic) ¶
package main
import (
"context"
"fmt"
"github.com/codeGROOVE-dev/bdcache"
)
func main() {
ctx := context.Background()
// Create a simple in-memory cache
cache, err := bdcache.New[string, int](ctx)
if err != nil {
panic(err)
}
defer func() { _ = cache.Close() }() //nolint:errcheck // Example code, error handling would clutter the example
// Store a value
if err := cache.Set(ctx, "answer", 42, 0); err != nil {
panic(err)
}
// Retrieve it
val, found, err := cache.Get(ctx, "answer")
if err != nil {
panic(err)
}
if found {
fmt.Printf("The answer is %d\n", val)
}
}
Output: The answer is 42
Example (StructValues) ¶
package main
import (
"context"
"fmt"
"github.com/codeGROOVE-dev/bdcache"
)
func main() {
ctx := context.Background()
type User struct {
ID int
Name string
Email string
}
// Cache can store any type
cache, err := bdcache.New[int, User](ctx)
if err != nil {
panic(err)
}
defer func() { _ = cache.Close() }() //nolint:errcheck // Example code, error handling would clutter the example
// Store a struct
user := User{
ID: 1,
Name: "Alice",
Email: "alice@example.com",
}
if err := cache.Set(ctx, user.ID, user, 0); err != nil {
panic(err)
}
// Retrieve it
retrieved, found, err := cache.Get(ctx, 1)
if err != nil {
panic(err)
}
if found {
fmt.Printf("User: %s (%s)\n", retrieved.Name, retrieved.Email)
}
}
Output: User: Alice (alice@example.com)
Example (WithBestStore) ¶
package main
import (
"context"
"fmt"
"github.com/codeGROOVE-dev/bdcache"
)
func main() {
ctx := context.Background()
// Automatically selects best storage:
// - Cloud Datastore if K_SERVICE env var is set (Cloud Run/Knative)
// - Local files otherwise
cache, err := bdcache.New[string, int](ctx,
bdcache.WithBestStore("myapp"),
)
if err != nil {
panic(err)
}
defer func() { _ = cache.Close() }() //nolint:errcheck // Example code, error handling would clutter the example
if err := cache.Set(ctx, "counter", 100, 0); err != nil {
panic(err)
}
val, found, err := cache.Get(ctx, "counter")
if err != nil {
panic(err)
}
if found {
fmt.Printf("Counter: %d\n", val)
}
}
Output: Counter: 100
Example (WithLocalStore) ¶
package main
import (
"context"
"fmt"
"github.com/codeGROOVE-dev/bdcache"
)
func main() {
ctx := context.Background()
// Create cache with local file persistence
cache, err := bdcache.New[string, string](ctx,
bdcache.WithLocalStore("myapp"),
bdcache.WithMemorySize(5000),
)
if err != nil {
panic(err)
}
defer func() { _ = cache.Close() }() //nolint:errcheck // Example code, error handling would clutter the example
// Values are cached in memory and persisted to disk
if err := cache.Set(ctx, "config", "production", 0); err != nil {
panic(err)
}
// After restart, values are loaded from disk automatically
val, found, err := cache.Get(ctx, "config")
if err != nil {
panic(err)
}
if found {
fmt.Printf("Config: %s\n", val)
}
}
Output: Config: production
Example (WithTTL) ¶
package main
import (
"context"
"fmt"
"time"
"github.com/codeGROOVE-dev/bdcache"
)
func main() {
ctx := context.Background()
// Create cache with default TTL
cache, err := bdcache.New[string, string](ctx,
bdcache.WithDefaultTTL(5*time.Minute),
)
if err != nil {
panic(err)
}
defer func() { _ = cache.Close() }() //nolint:errcheck // Example code, error handling would clutter the example
// Set with default TTL (ttl=0 uses configured DefaultTTL)
if err := cache.Set(ctx, "session", "user-123", 0); err != nil {
panic(err)
}
// Set with custom TTL (overrides default)
if err := cache.Set(ctx, "token", "abc123", 1*time.Hour); err != nil {
panic(err)
}
// Retrieve values
session, found, err := cache.Get(ctx, "session")
if err != nil {
panic(err)
}
if found {
fmt.Printf("Session: %s\n", session)
}
}
Output: Session: user-123
func (*Cache[K, V]) Cleanup ¶
Cleanup removes expired entries from the cache. Returns the number of entries removed.
func (*Cache[K, V]) Get ¶
Get retrieves a value from the cache. It first checks the memory cache, then falls back to persistence if available.
func (*Cache[K, V]) Set ¶
Set stores a value in the cache with an optional TTL. A zero TTL means no expiration (or uses DefaultTTL if configured). The value is ALWAYS stored in memory, even if persistence fails. Returns an error if the key violates persistence constraints or if persistence fails. Even when an error is returned, the value is cached in memory.
type Option ¶
type Option func(*Options)
Option is a functional option for configuring a Cache.
func WithBestStore ¶
WithBestStore automatically selects the best persistence option: - If K_SERVICE environment variable is set (Google Cloud Run/Knative): uses Cloud Datastore - Otherwise: uses local file store.
func WithCloudDatastore ¶
WithCloudDatastore enables Cloud Datastore persistence using the given cache ID as database ID. An empty project ID will auto-detect the correct project.
func WithDefaultTTL ¶
WithDefaultTTL sets the default TTL for cache items.
func WithLocalStore ¶
WithLocalStore enables local file persistence using the given cache ID as subdirectory name. Files are stored in os.UserCacheDir()/cacheID.
func WithMemorySize ¶
WithMemorySize sets the maximum number of items in the memory cache.
func WithWarmup ¶
WithWarmup enables cache warmup by loading the N most recently updated entries from persistence on startup. By default, warmup is disabled (0). Set to a positive number to load that many entries.
type Options ¶
type Options struct {
CacheID string
MemorySize int
DefaultTTL time.Duration
WarmupLimit int
UseDatastore bool
}
Options configures a Cache instance.
type PersistenceLayer ¶
type PersistenceLayer[K comparable, V any] interface { // ValidateKey checks if a key is valid for this persistence layer. // Returns an error if the key violates constraints. ValidateKey(key K) error // Load retrieves a value from persistent storage. // Returns the value, expiry time, whether it was found, and any error. Load(ctx context.Context, key K) (V, time.Time, bool, error) // Store saves a value to persistent storage with an expiry time. Store(ctx context.Context, key K, value V, expiry time.Time) error // Delete removes a value from persistent storage. Delete(ctx context.Context, key K) error // LoadRecent returns channels for streaming the most recently updated entries from persistent storage. // Used for warming up the cache on startup. Returns up to 'limit' most recently updated entries. // The entry channel should be closed when all entries have been sent. // If an error occurs, send it on the error channel. LoadRecent(ctx context.Context, limit int) (<-chan Entry[K, V], <-chan error) // LoadAll returns channels for streaming all entries from persistent storage. // Equivalent to LoadRecent(ctx, 0). LoadAll(ctx context.Context) (<-chan Entry[K, V], <-chan error) // Close releases any resources held by the persistence layer. Close() error }
PersistenceLayer defines the interface for cache persistence backends.