github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/commons/caches/lru/arc.go (about) 1 /* 2 * Copyright 2023 Wang Min Xiang 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package lru 19 20 import ( 21 "github.com/aacfactory/errors" 22 "sync" 23 ) 24 25 type ARCCache[K comparable, V any] struct { 26 size int 27 p int 28 t1 *LRU[K, V] 29 b1 *LRU[K, struct{}] 30 t2 *LRU[K, V] 31 b2 *LRU[K, struct{}] 32 lock sync.RWMutex 33 } 34 35 func NewARC[K comparable, V any](size int) (*ARCCache[K, V], error) { 36 if size < 1 { 37 return nil, errors.Warning("fns: size is required") 38 } 39 b1 := New[K, struct{}](size, nil) 40 b2 := New[K, struct{}](size, nil) 41 t1 := New[K, V](size, nil) 42 t2 := New[K, V](size, nil) 43 c := &ARCCache[K, V]{ 44 size: size, 45 p: 0, 46 t1: t1, 47 b1: b1, 48 t2: t2, 49 b2: b2, 50 } 51 return c, nil 52 } 53 54 func (c *ARCCache[K, V]) Get(key K) (value V, ok bool) { 55 c.lock.Lock() 56 defer c.lock.Unlock() 57 if value, ok = c.t1.Peek(key); ok { 58 c.t1.Remove(key) 59 c.t2.Add(key, value) 60 return value, ok 61 } 62 if value, ok = c.t2.Get(key); ok { 63 return value, ok 64 } 65 return 66 } 67 68 func (c *ARCCache[K, V]) Add(key K, value V) { 69 c.lock.Lock() 70 defer c.lock.Unlock() 71 if c.t1.Contains(key) { 72 c.t1.Remove(key) 73 c.t2.Add(key, value) 74 return 75 } 76 if c.t2.Contains(key) { 77 c.t2.Add(key, value) 78 return 79 } 80 if c.b1.Contains(key) { 81 delta := 1 82 b1Len := c.b1.Len() 83 b2Len := c.b2.Len() 84 if b2Len > b1Len { 85 delta = b2Len / b1Len 86 } 87 if c.p+delta >= c.size { 88 c.p = c.size 89 } else { 90 c.p += delta 91 } 92 if c.t1.Len()+c.t2.Len() >= c.size { 93 c.replace(false) 94 } 95 c.b1.Remove(key) 96 c.t2.Add(key, value) 97 return 98 } 99 if c.b2.Contains(key) { 100 delta := 1 101 b1Len := c.b1.Len() 102 b2Len := c.b2.Len() 103 if b1Len > b2Len { 104 delta = b1Len / b2Len 105 } 106 if delta >= c.p { 107 c.p = 0 108 } else { 109 c.p -= delta 110 } 111 if c.t1.Len()+c.t2.Len() >= c.size { 112 c.replace(true) 113 } 114 c.b2.Remove(key) 115 c.t2.Add(key, value) 116 return 117 } 118 if c.t1.Len()+c.t2.Len() >= c.size { 119 c.replace(false) 120 } 121 if c.b1.Len() > c.size-c.p { 122 c.b1.RemoveOldest() 123 } 124 if c.b2.Len() > c.p { 125 c.b2.RemoveOldest() 126 } 127 c.t1.Add(key, value) 128 } 129 130 func (c *ARCCache[K, V]) replace(b2ContainsKey bool) { 131 t1Len := c.t1.Len() 132 if t1Len > 0 && (t1Len > c.p || (t1Len == c.p && b2ContainsKey)) { 133 k, _, ok := c.t1.RemoveOldest() 134 if ok { 135 c.b1.Add(k, struct{}{}) 136 } 137 } else { 138 k, _, ok := c.t2.RemoveOldest() 139 if ok { 140 c.b2.Add(k, struct{}{}) 141 } 142 } 143 } 144 145 func (c *ARCCache[K, V]) Len() int { 146 c.lock.RLock() 147 defer c.lock.RUnlock() 148 return c.t1.Len() + c.t2.Len() 149 } 150 151 func (c *ARCCache[K, V]) Keys() []K { 152 c.lock.RLock() 153 defer c.lock.RUnlock() 154 k1 := c.t1.Keys() 155 k2 := c.t2.Keys() 156 return append(k1, k2...) 157 } 158 159 func (c *ARCCache[K, V]) Values() []V { 160 c.lock.RLock() 161 defer c.lock.RUnlock() 162 v1 := c.t1.Values() 163 v2 := c.t2.Values() 164 return append(v1, v2...) 165 } 166 167 func (c *ARCCache[K, V]) Remove(key K) { 168 c.lock.Lock() 169 defer c.lock.Unlock() 170 if c.t1.Remove(key) { 171 return 172 } 173 if c.t2.Remove(key) { 174 return 175 } 176 if c.b1.Remove(key) { 177 return 178 } 179 if c.b2.Remove(key) { 180 return 181 } 182 } 183 184 func (c *ARCCache[K, V]) Purge() { 185 c.lock.Lock() 186 defer c.lock.Unlock() 187 c.t1.Purge() 188 c.t2.Purge() 189 c.b1.Purge() 190 c.b2.Purge() 191 } 192 193 func (c *ARCCache[K, V]) Contains(key K) bool { 194 c.lock.RLock() 195 defer c.lock.RUnlock() 196 return c.t1.Contains(key) || c.t2.Contains(key) 197 } 198 199 func (c *ARCCache[K, V]) Peek(key K) (value V, ok bool) { 200 c.lock.RLock() 201 defer c.lock.RUnlock() 202 if val, ok := c.t1.Peek(key); ok { 203 return val, ok 204 } 205 return c.t2.Peek(key) 206 }