Move expiration code into its own and add ticker select case

master
Harshavardhana 10 years ago
parent 8a65b90783
commit 01b474fca3
  1. 8
      pkg/storage/drivers/memory/memory.go
  2. 59
      pkg/storage/drivers/memory/memory_intelligent.go

@ -66,7 +66,7 @@ func Start(maxSize uint64, expiration time.Duration) (chan<- string, <-chan erro
memory.objects = NewIntelligent(maxSize, expiration) memory.objects = NewIntelligent(maxSize, expiration)
memory.lock = new(sync.RWMutex) memory.lock = new(sync.RWMutex)
memory.objects.OnEvicted = memory.evictObject memory.objects.OnExpired = memory.expiredObject
// set up memory expiration // set up memory expiration
memory.objects.ExpireObjects(time.Second * 5) 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) 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() cacheStats := memory.objects.Stats()
log.Printf("CurrentSize: %d, CurrentItems: %d, TotalEvictions: %d", log.Printf("CurrentSize: %d, CurrentItems: %d, TotalExpirations: %d",
cacheStats.Bytes, cacheStats.Items, cacheStats.Evictions) cacheStats.Bytes, cacheStats.Items, cacheStats.Expired)
key := a[0].(string) key := a[0].(string)
// loop through all buckets // loop through all buckets
for bucket, storedBucket := range memory.storedBuckets { for bucket, storedBucket := range memory.storedBuckets {

@ -39,8 +39,8 @@ type Intelligent struct {
// expiration is a duration for a cache key to expire // expiration is a duration for a cache key to expire
expiration time.Duration expiration time.Duration
// gcInterval is a duration for garbage collection // stopExpireTimer channel to quit the timer thread
gcInterval time.Duration stopExpireTimer chan struct{}
// maxSize is a total size for overall cache // maxSize is a total size for overall cache
maxSize uint64 maxSize uint64
@ -48,18 +48,18 @@ type Intelligent struct {
// currentSize is a current size in memory // currentSize is a current size in memory
currentSize uint64 currentSize uint64
// OnEvicted - callback function for eviction // OnExpired - callback function for eviction
OnEvicted func(a ...interface{}) OnExpired func(a ...interface{})
// totalEvicted counter to keep track of total evictions // totalExpired counter to keep track of total expirations
totalEvicted uint64 totalExpired uint64
} }
// Stats current cache statistics // Stats current cache statistics
type Stats struct { type Stats struct {
Bytes uint64 Bytes uint64
Items uint64 Items uint64
Evictions uint64 Expired uint64
} }
// NewIntelligent creates an inmemory cache // NewIntelligent creates an inmemory cache
@ -78,24 +78,26 @@ func NewIntelligent(maxSize uint64, expiration time.Duration) *Intelligent {
// Stats get current cache statistics // Stats get current cache statistics
func (r *Intelligent) Stats() Stats { func (r *Intelligent) Stats() Stats {
return Stats{ return Stats{
Bytes: r.currentSize, Bytes: r.currentSize,
Items: uint64(len(r.items)), Items: uint64(len(r.items)),
Evictions: r.totalEvicted, Expired: r.totalExpired,
} }
} }
// ExpireObjects expire objects in go routine // ExpireObjects expire objects in go routine
func (r *Intelligent) ExpireObjects(gcInterval time.Duration) { func (r *Intelligent) ExpireObjects(gcInterval time.Duration) {
r.gcInterval = gcInterval r.stopExpireTimer = make(chan struct{})
ticker := time.NewTicker(gcInterval)
go func() { go func() {
for range time.Tick(gcInterval) { for {
r.Lock() select {
for key := range r.items { case <-ticker.C:
if !r.isValid(key) { r.Expire()
r.Delete(key) case <-r.stopExpireTimer:
} ticker.Stop()
return
} }
r.Unlock()
} }
}() }()
} }
@ -132,15 +134,26 @@ func (r *Intelligent) Set(key string, value interface{}) {
return 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 // Delete deletes a given key if exists
func (r *Intelligent) Delete(key string) { func (r *Intelligent) Delete(key string) {
if _, ok := r.items[key]; ok { if _, ok := r.items[key]; ok {
r.currentSize -= uint64(len(r.items[key].([]byte))) r.currentSize -= uint64(len(r.items[key].([]byte)))
delete(r.items, key) delete(r.items, key)
delete(r.updatedAt, key) delete(r.updatedAt, key)
r.totalEvicted++ r.totalExpired++
if r.OnEvicted != nil { if r.OnExpired != nil {
r.OnEvicted(key) r.OnExpired(key)
} }
} }
} }

Loading…
Cancel
Save