github.com/web-platform-tests/wpt.fyi@v0.0.0-20240530210107-70cf978996f1/api/query/cache/lru/lru.go (about) 1 // Copyright 2018 The WPT Dashboard Project. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package lru 6 7 import ( 8 "math" 9 "sort" 10 "sync" 11 "time" 12 ) 13 14 // LRU is a least recently used collection that supports element acces and 15 // item eviction. The first access of an unevicted value implicitly adds the 16 // value to the collection. 17 type LRU interface { 18 // Access stores the current time as the "last accessed" time for the given 19 // value in the collection. The first access of an unevicted value implicitly 20 // adds the value to the collection. 21 Access(value int64) 22 // EvictLRU removes and returns a fraction of the collection, based on 23 // the passed percentage. It will always remove at least one item. When 24 // deciding which items to remove, EvictLRU deletes older values from 25 // the collection first. If the collection is empty, nil is returned. 26 EvictLRU(percent float64) []int64 27 } 28 29 type lru struct { 30 values map[int64]time.Time 31 m *sync.Mutex 32 } 33 34 type lruEntry struct { 35 int64 36 time.Time 37 } 38 39 type lruEntries []lruEntry 40 41 // Satisfy the Sort interface requirements (https://golang.org/pkg/sort/#Sort) 42 func (s lruEntries) Len() int { return len(s) } 43 func (s lruEntries) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 44 func (s lruEntries) Less(i, j int) bool { return s[i].Time.Before(s[j].Time) } 45 46 func (l *lru) Access(v int64) { 47 l.syncAccess(v) 48 } 49 50 func (l *lru) EvictLRU(percent float64) []int64 { 51 if len(l.values) == 0 { 52 return nil 53 } 54 percent = math.Max(0.0, math.Min(1.0, percent)) 55 numValuesToDelete := math.Floor(float64(len(l.values)) * percent) 56 // Always delete at least one entry. 57 return l.syncEvictLRU(int(math.Max(1.0, numValuesToDelete))) 58 } 59 60 // NewLRU constructs a new empty LRU. 61 // nolint:ireturn // TODO: Fix ireturn lint error 62 func NewLRU() LRU { 63 return &lru{ 64 values: make(map[int64]time.Time), 65 m: &sync.Mutex{}, 66 } 67 } 68 69 func (l *lru) syncAccess(v int64) { 70 l.m.Lock() 71 defer l.m.Unlock() 72 73 l.values[v] = time.Now() 74 } 75 76 func (l *lru) syncEvictLRU(num int) []int64 { 77 l.m.Lock() 78 defer l.m.Unlock() 79 80 vs := make(lruEntries, 0, len(l.values)) 81 for v, t := range l.values { 82 vs = append(vs, lruEntry{v, t}) 83 } 84 sort.Sort(vs) 85 toRemove := vs[:num] 86 ret := make([]int64, num) 87 for i := range toRemove { 88 value := toRemove[i].int64 89 ret[i] = value 90 delete(l.values, value) 91 } 92 93 return ret 94 }