diff --git a/pkg/storage/drivers/memory/memory.go b/pkg/storage/drivers/memory/memory.go index 76d7a757e..e86a02673 100644 --- a/pkg/storage/drivers/memory/memory.go +++ b/pkg/storage/drivers/memory/memory.go @@ -66,7 +66,7 @@ func Start(maxSize uint64, expiration time.Duration) (chan<- string, <-chan erro memory.objects = NewIntelligent(maxSize, expiration) memory.lock = new(sync.RWMutex) - memory.objects.OnEvicted = memory.evictObject + memory.objects.OnExpired = memory.expiredObject // set up memory expiration memory.objects.ExpireObjects(time.Second * 5) @@ -495,10 +495,10 @@ func (memory *memoryDriver) GetObjectMetadata(bucket, key, prefix string) (drive return drivers.ObjectMetadata{}, iodine.New(drivers.ObjectNotFound{Bucket: bucket, Object: key}, nil) } -func (memory *memoryDriver) evictObject(a ...interface{}) { +func (memory *memoryDriver) expiredObject(a ...interface{}) { cacheStats := memory.objects.Stats() - log.Printf("CurrentSize: %d, CurrentItems: %d, TotalEvictions: %d", - cacheStats.Bytes, cacheStats.Items, cacheStats.Evictions) + log.Printf("CurrentSize: %d, CurrentItems: %d, TotalExpirations: %d", + cacheStats.Bytes, cacheStats.Items, cacheStats.Expired) key := a[0].(string) // loop through all buckets for bucket, storedBucket := range memory.storedBuckets { diff --git a/pkg/storage/drivers/memory/memory_intelligent.go b/pkg/storage/drivers/memory/memory_intelligent.go index 08e452017..ed63123af 100644 --- a/pkg/storage/drivers/memory/memory_intelligent.go +++ b/pkg/storage/drivers/memory/memory_intelligent.go @@ -39,8 +39,8 @@ type Intelligent struct { // expiration is a duration for a cache key to expire expiration time.Duration - // gcInterval is a duration for garbage collection - gcInterval time.Duration + // stopExpireTimer channel to quit the timer thread + stopExpireTimer chan struct{} // maxSize is a total size for overall cache maxSize uint64 @@ -48,18 +48,18 @@ type Intelligent struct { // currentSize is a current size in memory currentSize uint64 - // OnEvicted - callback function for eviction - OnEvicted func(a ...interface{}) + // OnExpired - callback function for eviction + OnExpired func(a ...interface{}) - // totalEvicted counter to keep track of total evictions - totalEvicted uint64 + // totalExpired counter to keep track of total expirations + totalExpired uint64 } // Stats current cache statistics type Stats struct { - Bytes uint64 - Items uint64 - Evictions uint64 + Bytes uint64 + Items uint64 + Expired uint64 } // NewIntelligent creates an inmemory cache @@ -78,24 +78,26 @@ func NewIntelligent(maxSize uint64, expiration time.Duration) *Intelligent { // Stats get current cache statistics func (r *Intelligent) Stats() Stats { return Stats{ - Bytes: r.currentSize, - Items: uint64(len(r.items)), - Evictions: r.totalEvicted, + Bytes: r.currentSize, + Items: uint64(len(r.items)), + Expired: r.totalExpired, } } // ExpireObjects expire objects in go routine func (r *Intelligent) ExpireObjects(gcInterval time.Duration) { - r.gcInterval = gcInterval + r.stopExpireTimer = make(chan struct{}) + ticker := time.NewTicker(gcInterval) go func() { - for range time.Tick(gcInterval) { - r.Lock() - for key := range r.items { - if !r.isValid(key) { - r.Delete(key) - } + for { + select { + case <-ticker.C: + r.Expire() + case <-r.stopExpireTimer: + ticker.Stop() + return } - r.Unlock() + } }() } @@ -132,15 +134,26 @@ func (r *Intelligent) Set(key string, value interface{}) { return } +// Expire expires keys which have expired +func (r *Intelligent) Expire() { + r.Lock() + defer r.Unlock() + for key := range r.items { + if !r.isValid(key) { + r.Delete(key) + } + } +} + // Delete deletes a given key if exists func (r *Intelligent) Delete(key string) { if _, ok := r.items[key]; ok { r.currentSize -= uint64(len(r.items[key].([]byte))) delete(r.items, key) delete(r.updatedAt, key) - r.totalEvicted++ - if r.OnEvicted != nil { - r.OnEvicted(key) + r.totalExpired++ + if r.OnExpired != nil { + r.OnExpired(key) } } }