package hcfs import ( "sync" "time" ) // cache represents an in-memory cache with TTL support type cache struct { items map[string]*cacheItem maxSize int ttl time.Duration mu sync.RWMutex } type cacheItem struct { value interface{} expiration time.Time accessTime time.Time } // newCache creates a new cache instance func newCache(maxSize int, ttl time.Duration) *cache { c := &cache{ items: make(map[string]*cacheItem), maxSize: maxSize, ttl: ttl, } // Start cleanup goroutine go c.cleanup() return c } // get retrieves a value from the cache func (c *cache) get(key string) (interface{}, bool) { c.mu.RLock() defer c.mu.RUnlock() item, exists := c.items[key] if !exists { return nil, false } // Check if item has expired if time.Now().After(item.expiration) { c.mu.RUnlock() c.mu.Lock() delete(c.items, key) c.mu.Unlock() c.mu.RLock() return nil, false } // Update access time item.accessTime = time.Now() return item.value, true } // set stores a value in the cache func (c *cache) set(key string, value interface{}) { c.mu.Lock() defer c.mu.Unlock() // Remove oldest item if cache is full if len(c.items) >= c.maxSize { c.evictOldest() } c.items[key] = &cacheItem{ value: value, expiration: time.Now().Add(c.ttl), accessTime: time.Now(), } } // delete removes a key from the cache func (c *cache) delete(key string) { c.mu.Lock() defer c.mu.Unlock() delete(c.items, key) } // clear removes all items from the cache func (c *cache) clear() { c.mu.Lock() defer c.mu.Unlock() c.items = make(map[string]*cacheItem) } // size returns the current number of items in the cache func (c *cache) size() int { c.mu.RLock() defer c.mu.RUnlock() return len(c.items) } // invalidatePattern removes all keys matching a pattern func (c *cache) invalidatePattern(pattern string) { c.mu.Lock() defer c.mu.Unlock() for key := range c.items { if contains(key, pattern) { delete(c.items, key) } } } // evictOldest removes the least recently used item func (c *cache) evictOldest() { var oldestKey string var oldestTime time.Time for key, item := range c.items { if oldestKey == "" || item.accessTime.Before(oldestTime) { oldestKey = key oldestTime = item.accessTime } } if oldestKey != "" { delete(c.items, oldestKey) } } // cleanup runs periodically to remove expired items func (c *cache) cleanup() { ticker := time.NewTicker(time.Minute) defer ticker.Stop() for range ticker.C { c.mu.Lock() now := time.Now() for key, item := range c.items { if now.After(item.expiration) { delete(c.items, key) } } c.mu.Unlock() } } // Helper function to check if a string contains a substring func contains(s, substr string) bool { return len(s) >= len(substr) && (s == substr || (len(substr) > 0 && indexOf(s, substr) >= 0)) } // Helper function to find index of substring func indexOf(s, substr string) int { for i := 0; i <= len(s)-len(substr); i++ { if s[i:i+len(substr)] == substr { return i } } return -1 } // analytics tracks client usage statistics type analytics struct { sessionStart time.Time operationCount map[string]int64 errorCount map[string]int64 totalRequests int64 failedRequests int64 cacheHits int64 cacheMisses int64 mu sync.RWMutex } // newAnalytics creates a new analytics instance func newAnalytics() *analytics { return &analytics{ sessionStart: time.Now(), operationCount: make(map[string]int64), errorCount: make(map[string]int64), } } // recordRequest increments the total request counter func (a *analytics) recordRequest() { a.mu.Lock() defer a.mu.Unlock() a.totalRequests++ } // recordError increments the error counter func (a *analytics) recordError(errorType string) { a.mu.Lock() defer a.mu.Unlock() a.failedRequests++ a.errorCount[errorType]++ } // recordCacheHit increments the cache hit counter func (a *analytics) recordCacheHit() { a.mu.Lock() defer a.mu.Unlock() a.cacheHits++ } // recordCacheMiss increments the cache miss counter func (a *analytics) recordCacheMiss() { a.mu.Lock() defer a.mu.Unlock() a.cacheMisses++ } // getCacheHitRate calculates the cache hit rate func (a *analytics) getCacheHitRate() float64 { a.mu.RLock() defer a.mu.RUnlock() total := a.cacheHits + a.cacheMisses if total == 0 { return 0.0 } return float64(a.cacheHits) / float64(total) }