Initial release: Go Jdenticon library v0.1.0
- Core library with SVG and PNG generation - CLI tool with generate and batch commands - Cross-platform path handling for Windows compatibility - Comprehensive test suite with integration tests
This commit is contained in:
131
internal/engine/cache.go
Normal file
131
internal/engine/cache.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru/v2"
|
||||
"github.com/ungluedlabs/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
|
||||
}
|
||||
Reference in New Issue
Block a user