From 2e5628e5aa949ee50ce19f5d261d156dd51710ee Mon Sep 17 00:00:00 2001 From: MircoT Date: Thu, 2 Jul 2020 17:15:03 +0200 Subject: [PATCH] Change queue management --- SmartCache/sim/cache/aiNN.go | 2 +- SmartCache/sim/cache/aiRL.go | 4 +- SmartCache/sim/cache/queue.go | 88 +++++++++++----------------- SmartCache/sim/cache/queue_test.go | 22 +++---- SmartCache/sim/cache/simpleCache.go | 12 ++-- SmartCache/sim/cache/weightFunLRU.go | 2 +- 6 files changed, 52 insertions(+), 78 deletions(-) diff --git a/SmartCache/sim/cache/aiNN.go b/SmartCache/sim/cache/aiNN.go index 32c3e8d1..1b999ca7 100644 --- a/SmartCache/sim/cache/aiNN.go +++ b/SmartCache/sim/cache/aiNN.go @@ -78,7 +78,7 @@ func (cache *AINN) Dumps(fileAndStats bool) [][]byte { if fileAndStats { // ----- Files ----- logger.Info("Dump cache files") - for file := range cache.files.Get(LRUQueue) { + for file := range cache.files.Get() { dumpInfo, _ := json.Marshal(DumpInfo{Type: "FILES"}) dumpFile, _ := json.Marshal(file) record, _ := json.Marshal(DumpRecord{ diff --git a/SmartCache/sim/cache/aiRL.go b/SmartCache/sim/cache/aiRL.go index f38360b6..dc4a10b6 100644 --- a/SmartCache/sim/cache/aiRL.go +++ b/SmartCache/sim/cache/aiRL.go @@ -100,7 +100,7 @@ func (cache *AIRL) Dumps(fileAndStats bool) [][]byte { if fileAndStats { // ----- Files ----- logger.Info("Dump cache files") - for file := range cache.files.Get(LRUQueue) { + for file := range cache.files.Get() { dumpInfo, _ := json.Marshal(DumpInfo{Type: "FILES"}) dumpFile, _ := json.Marshal(file) record, _ := json.Marshal(DumpRecord{ @@ -276,7 +276,7 @@ func (cache *AIRL) updateCategoryStates() { idxWeights := cache.evictionFeatureManager.FileFeatureIdxWeights() fileFeatureIndexes := cache.evictionFeatureManager.FileFeatureIdexMap() - for file := range cache.files.Get(NoQueue) { + for file := range cache.files.Get() { // fmt.Println(file.Filename) cache.bufferIdxVector = cache.bufferIdxVector[:0] for feature := range cache.evictionFeatureManager.FileFeatureIter() { diff --git a/SmartCache/sim/cache/queue.go b/SmartCache/sim/cache/queue.go index 5a724c6e..6d793061 100644 --- a/SmartCache/sim/cache/queue.go +++ b/SmartCache/sim/cache/queue.go @@ -95,6 +95,7 @@ const ( type Manager struct { files map[int64]*FileSupportData queue []*FileSupportData + qType queueType FrequencySum float64 FrequencySumSquare float64 SizeSum float64 @@ -102,7 +103,7 @@ type Manager struct { } // Init initialize the struct -func (man *Manager) Init() { +func (man *Manager) Init(qType queueType) { man.files = make(map[int64]*FileSupportData, 0) man.queue = make([]*FileSupportData, 0) } @@ -124,55 +125,17 @@ func (man Manager) GetFile(id int64) *FileSupportData { } // Get values from a queue -func (man Manager) Get(queue queueType) chan *FileSupportData { +func (man Manager) Get() chan *FileSupportData { ch := make(chan *FileSupportData) go func() { defer close(ch) // Filtering trick // https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating - switch queue { - case LRUQueue: - var curQueue ByRecency = man.queue - if !sort.IsSorted(curQueue) { - sort.Sort(curQueue) - } - for _, file := range curQueue { - ch <- file - } - case LFUQueue: - var curQueue ByFrequency = man.queue - if !sort.IsSorted(curQueue) { - sort.Sort(curQueue) - } - for _, file := range curQueue { - ch <- file - } - case SizeBigQueue: - var curQueue ByBigSize = man.queue - if !sort.IsSorted(curQueue) { - sort.Sort(curQueue) - } - for _, file := range curQueue { - ch <- file - } - case SizeSmallQueue: - var curQueue BySmallSize = man.queue - if !sort.IsSorted(curQueue) { - sort.Sort(curQueue) - } - for _, file := range curQueue { + if man.qType != NoQueue { + for _, file := range man.queue { ch <- file } - case WeightQueue: - var curQueue ByWeight = man.queue - if !sort.IsSorted(curQueue) { - sort.Sort(curQueue) - } - for _, file := range curQueue { - ch <- file - } - default: - logger.Debug("No queue requested, only files...") + } else { for _, file := range man.files { ch <- file } @@ -184,15 +147,13 @@ func (man Manager) Get(queue queueType) chan *FileSupportData { // Remove a file already in queue func (man *Manager) Remove(files []int64) { for _, file := range files { - for idx := len(man.queue) - 1; idx > -1; idx-- { - // https://github.com/golang/go/wiki/SliceTricks#delete - if man.queue[idx].Filename == file { - copy(man.queue[idx:], man.queue[idx+1:]) - man.queue[len(man.queue)-1] = nil // or the zero value of T - man.queue = man.queue[:len(man.queue)-1] - break - } - } + removeIdx := sort.Search(len(man.queue), func(idx int) bool { return man.queue[idx].Filename > file }) + // Delete trick + // https://github.com/golang/go/wiki/SliceTricks#delete + copy(man.queue[removeIdx:], man.queue[removeIdx+1:]) + man.queue[len(man.queue)-1] = nil // or the zero value of T + man.queue = man.queue[:len(man.queue)-1] + curFile := man.files[file] man.SizeSum -= curFile.Size man.SizeSumSquare -= (curFile.Size * curFile.Size) @@ -205,11 +166,32 @@ func (man *Manager) Remove(files []int64) { // Insert a file into the queue manager func (man *Manager) Insert(file FileSupportData) { man.files[file.Filename] = &file - man.queue = append(man.queue, &file) man.SizeSum += file.Size man.SizeSumSquare += (file.Size * file.Size) man.FrequencySum += float64(file.Frequency) man.FrequencySumSquare += float64(file.Frequency * file.Frequency) + var insertIdx = -1 + switch man.qType { + case LRUQueue: + insertIdx = sort.Search(len(man.queue), func(idx int) bool { return man.queue[idx].Recency > file.Recency }) + case LFUQueue: + insertIdx = sort.Search(len(man.queue), func(idx int) bool { return man.queue[idx].Frequency > file.Frequency }) + case SizeBigQueue: + insertIdx = sort.Search(len(man.queue), func(idx int) bool { return man.queue[idx].Size > file.Size || man.queue[idx].Recency > file.Recency }) + case SizeSmallQueue: + insertIdx = sort.Search(len(man.queue), func(idx int) bool { return man.queue[idx].Size < file.Size || man.queue[idx].Recency > file.Recency }) + case WeightQueue: + insertIdx = sort.Search(len(man.queue), func(idx int) bool { return man.queue[idx].Recency > file.Recency }) + } + if insertIdx == len(man.queue) { + man.queue = append(man.queue, &file) + } else { + // Trick + // https://github.com/golang/go/wiki/SliceTricks#insert + man.queue = append(man.queue, nil) + copy(man.queue[insertIdx+1:], man.queue[insertIdx:]) + man.queue[insertIdx] = &file + } } // Update a file into the queue manager diff --git a/SmartCache/sim/cache/queue_test.go b/SmartCache/sim/cache/queue_test.go index a1839cf7..0d05fd70 100644 --- a/SmartCache/sim/cache/queue_test.go +++ b/SmartCache/sim/cache/queue_test.go @@ -18,7 +18,7 @@ func BenchmarkQueue(b *testing.B) { r := rand.New(rand.NewSource(42)) man := Manager{} - man.Init() + man.Init(LRUQueue) for idx := 0; idx < numTests; idx++ { man.Insert( @@ -47,7 +47,7 @@ func BenchmarkQueue(b *testing.B) { func TestLRUQueue(t *testing.T) { r := rand.New(rand.NewSource(42)) man := Manager{} - man.Init() + man.Init(LRUQueue) insertedFiles := []int64{} @@ -72,7 +72,7 @@ func TestLRUQueue(t *testing.T) { }) prevRecency := int64(numTests + 1) - for file := range man.Get(LRUQueue) { + for file := range man.Get() { // fmt.Println(file.Filename, file.Recency, prevRecency) if prevRecency < file.Recency { t.Log("LRU order not valid") @@ -93,7 +93,7 @@ func TestLRUQueue(t *testing.T) { func TestLFUQueue(t *testing.T) { r := rand.New(rand.NewSource(42)) man := Manager{} - man.Init() + man.Init(LFUQueue) insertedFiles := []int64{} @@ -118,7 +118,7 @@ func TestLFUQueue(t *testing.T) { }) prevFrequency := int64(-1) - for file := range man.Get(LFUQueue) { + for file := range man.Get() { // fmt.Println(file.Filename, file.Frequency, prevFrequency) if prevFrequency > file.Frequency { t.Log("LFU order not valid") @@ -139,7 +139,7 @@ func TestLFUQueue(t *testing.T) { func TestSizeQueue(t *testing.T) { r := rand.New(rand.NewSource(42)) man := Manager{} - man.Init() + man.Init(SizeBigQueue) insertedFiles := []int64{} @@ -164,7 +164,7 @@ func TestSizeQueue(t *testing.T) { }) prevSize := float64(-1.0) - for file := range man.Get(SizeBigQueue) { + for file := range man.Get() { // fmt.Println(file.Filename, file.Size, prevSize) if prevSize > file.Size { t.Log("Big size order not valid") @@ -172,14 +172,6 @@ func TestSizeQueue(t *testing.T) { } prevSize = file.Size } - for file := range man.Get(SizeSmallQueue) { - // fmt.Println(file.Filename, file.Size, prevSize) - if prevSize < file.Size { - t.Log("Small size order not valid") - t.Fatal() - } - prevSize = file.Size - } man.Remove(insertedFiles) diff --git a/SmartCache/sim/cache/simpleCache.go b/SmartCache/sim/cache/simpleCache.go index 5b150b14..8ffb9cfb 100644 --- a/SmartCache/sim/cache/simpleCache.go +++ b/SmartCache/sim/cache/simpleCache.go @@ -54,7 +54,7 @@ func (cache *SimpleCache) Init(vars ...interface{}) interface{} { } cache.stats.Init() - cache.files.Init() + cache.files.Init(cache.ordType) if cache.HighWaterMark == 0.0 { cache.HighWaterMark = 95.0 @@ -82,7 +82,7 @@ func (cache *SimpleCache) SetBandwidth(bandwidth float64) { // ClearFiles remove the cache files func (cache *SimpleCache) ClearFiles() { - cache.files.Init() + cache.files.Init(cache.ordType) cache.stats.Clear() cache.size = 0. } @@ -134,7 +134,7 @@ func (cache *SimpleCache) Dumps(fileAndStats bool) [][]byte { if fileAndStats { // ----- Files ----- logger.Info("Dump cache files") - for file := range cache.files.Get(LRUQueue) { + for file := range cache.files.Get() { dumpInfo, _ := json.Marshal(DumpInfo{Type: "FILES"}) dumpFile, _ := json.Marshal(file) record, _ := json.Marshal(DumpRecord{ @@ -358,7 +358,7 @@ func (cache *SimpleCache) Free(amount float64, percentage bool) float64 { } if sizeToDelete > 0. { deletedFiles := make([]int64, 0) - for curFile := range cache.files.Get(cache.ordType) { + for curFile := range cache.files.Get() { logger.Debug("delete", zap.Int64("filename", curFile.Filename), zap.Float64("fileSize", curFile.Size), @@ -534,7 +534,7 @@ func (cache *SimpleCache) MeanFrequency() float64 { func (cache *SimpleCache) MeanRecency() float64 { totRecency := 0.0 curTick := float64(cache.tick) - for file := range cache.files.Get(NoQueue) { + for file := range cache.files.Get() { totRecency += (curTick - float64(file.Recency)) } return totRecency / float64(cache.files.Len()) @@ -557,7 +557,7 @@ func (cache *SimpleCache) StdDevFreq() float64 { func (cache *SimpleCache) StdDevRec() float64 { mean := cache.MeanRecency() sum := 0.0 - for file := range cache.files.Get(NoQueue) { + for file := range cache.files.Get() { sum += math.Pow(float64(file.Recency)-mean, 2) } return math.Sqrt(sum / (float64(cache.files.Len()) - 1.0)) diff --git a/SmartCache/sim/cache/weightFunLRU.go b/SmartCache/sim/cache/weightFunLRU.go index fb8a8c31..6fde78ce 100644 --- a/SmartCache/sim/cache/weightFunLRU.go +++ b/SmartCache/sim/cache/weightFunLRU.go @@ -34,7 +34,7 @@ func (cache *WeightFunLRU) Dumps(fileAndStats bool) [][]byte { if fileAndStats { // ----- Files ----- logger.Info("Dump cache files") - for file := range cache.files.Get(LRUQueue) { + for file := range cache.files.Get() { dumpInfo, _ := json.Marshal(DumpInfo{Type: "FILES"}) dumpFile, _ := json.Marshal(file) record, _ := json.Marshal(DumpRecord{