Files
go-jdenticon/internal/engine/cache.go
Kevin McIntyre f1544ef49c
Some checks failed
CI / Test (Go 1.24.x, ubuntu-latest) (push) Successful in 1m53s
CI / Code Quality (push) Failing after 26s
CI / Security Scan (push) Failing after 11s
CI / Test Coverage (push) Successful in 1m13s
CI / Benchmarks (push) Failing after 10m22s
CI / Build CLI (push) Failing after 8s
Benchmarks / Run Benchmarks (push) Failing after 10m13s
Release / Test (push) Successful in 55s
Release / Build (amd64, darwin, ) (push) Failing after 12s
Release / Build (amd64, linux, ) (push) Failing after 6s
Release / Build (amd64, windows, .exe) (push) Failing after 12s
Release / Build (arm64, darwin, ) (push) Failing after 12s
Release / Build (arm64, linux, ) (push) Failing after 12s
Release / Release (push) Has been skipped
CI / Test (Go 1.24.x, macos-latest) (push) Has been cancelled
CI / Test (Go 1.24.x, windows-latest) (push) Has been cancelled
chore: update module path to gitea.dockr.co/kev/go-jdenticon
Move hosting from GitHub to private Gitea instance.
2026-02-10 10:07:57 -05:00

132 lines
3.5 KiB
Go

package engine
import (
"fmt"
"strconv"
"sync/atomic"
lru "github.com/hashicorp/golang-lru/v2"
"gitea.dockr.co/kev/go-jdenticon/internal/constants"
)
// CacheMetrics holds cache performance metrics using atomic operations for efficiency
type CacheMetrics struct {
hits int64 // Use atomic operations, no mutex needed
misses int64 // Use atomic operations, no mutex needed
}
// GetHits returns the number of cache hits
func (m *CacheMetrics) GetHits() int64 {
return atomic.LoadInt64(&m.hits)
}
// GetMisses returns the number of cache misses
func (m *CacheMetrics) GetMisses() int64 {
return atomic.LoadInt64(&m.misses)
}
// recordHit records a cache hit atomically
func (m *CacheMetrics) recordHit() {
atomic.AddInt64(&m.hits, 1)
}
// recordMiss records a cache miss atomically
func (m *CacheMetrics) recordMiss() {
atomic.AddInt64(&m.misses, 1)
}
// cacheKey generates a cache key from hash and size
func (g *Generator) cacheKey(hash string, size float64) string {
// Use a simple concatenation approach for better performance
// Convert float64 size to string with appropriate precision
return hash + ":" + strconv.FormatFloat(size, 'f', 1, 64)
}
// ClearCache removes all entries from the cache and resets metrics
func (g *Generator) ClearCache() {
g.mu.Lock()
defer g.mu.Unlock()
g.cache.Purge()
// Reset metrics
atomic.StoreInt64(&g.metrics.hits, 0)
atomic.StoreInt64(&g.metrics.misses, 0)
}
// GetCacheSize returns the number of items currently in the cache
func (g *Generator) GetCacheSize() int {
g.mu.RLock()
defer g.mu.RUnlock()
return g.cache.Len()
}
// GetCacheCapacity returns the maximum number of items the cache can hold
func (g *Generator) GetCacheCapacity() int {
g.mu.RLock()
defer g.mu.RUnlock()
// LRU cache doesn't expose capacity, return the configured capacity from config
return g.config.CacheSize
}
// GetCacheMetrics returns the cache hit and miss counts
func (g *Generator) GetCacheMetrics() (hits int64, misses int64) {
return g.metrics.GetHits(), g.metrics.GetMisses()
}
// SetConfig updates the generator's color configuration and clears the cache
func (g *Generator) SetConfig(colorConfig ColorConfig) {
g.mu.Lock()
defer g.mu.Unlock()
g.config.ColorConfig = colorConfig
g.cache.Purge() // Clear cache since config changed
}
// SetGeneratorConfig updates the generator's configuration, including cache size
func (g *Generator) SetGeneratorConfig(config GeneratorConfig) error {
g.mu.Lock()
defer g.mu.Unlock()
// Validate cache size
if config.CacheSize <= 0 {
return fmt.Errorf("jdenticon: engine: invalid cache size: %d", config.CacheSize)
}
// Create new cache with updated size if necessary
if config.CacheSize != g.config.CacheSize {
newCache, err := lru.New[string, *Icon](config.CacheSize)
if err != nil {
return fmt.Errorf("jdenticon: engine: failed to create new cache: %w", err)
}
g.cache = newCache
} else {
// Same cache size, just clear existing cache
g.cache.Purge()
}
g.config = config
// Update resolved max icon size
if config.MaxIconSize > 0 {
g.maxIconSize = config.MaxIconSize
} else {
g.maxIconSize = constants.DefaultMaxIconSize
}
return nil
}
// GetConfig returns the current color configuration
func (g *Generator) GetConfig() ColorConfig {
g.mu.RLock()
defer g.mu.RUnlock()
return g.config.ColorConfig
}
// GetGeneratorConfig returns the current generator configuration
func (g *Generator) GetGeneratorConfig() GeneratorConfig {
g.mu.RLock()
defer g.mu.RUnlock()
return g.config
}