github.com/jxskiss/gopkg@v0.17.3/lru/cache_test.go (about) 1 package lru 2 3 import ( 4 "math/rand" 5 "runtime" 6 "testing" 7 "time" 8 ) 9 10 func createFilledCache(ttl time.Duration) *Cache { 11 c := NewCache(1000) 12 for i := 0; i < 1000; i++ { 13 key := int64(rand.Intn(5000)) 14 c.Set(key, key, ttl) 15 } 16 return c 17 } 18 19 func createRandInts(size int) []int64 { 20 s := make([]int64, size) 21 for i := 0; i < size; i++ { 22 s[i] = rand.Int63n(5000) 23 } 24 return s 25 } 26 27 func TestBasicEviction(t *testing.T) { 28 t.Parallel() 29 c := NewCache(3) 30 if _, ok, _ := c.Get("a"); ok { 31 t.Error("a") 32 } 33 34 c.Set("b", "vb", 2*time.Second) 35 c.Set("a", "va", time.Second) 36 c.Set("c", "vc", 3*time.Second) 37 38 if v, _, _ := c.Get("a"); v != "va" { 39 t.Error("va") 40 } 41 if v, _, _ := c.Get("b"); v != "vb" { 42 t.Error("vb") 43 } 44 if v, _, _ := c.Get("c"); v != "vc" { 45 t.Error("vc") 46 } 47 48 c.Set("d", "vd", time.Second) 49 if _, ok, _ := c.Get("a"); ok { 50 t.Error("expecting element A to be evicted") 51 } 52 c.Set("e", "ve", time.Second) 53 if _, ok, _ := c.Get("b"); ok { 54 t.Error("expecting element B to be evicted") 55 } 56 c.Set("f", "vf", time.Second) 57 if _, ok, _ := c.Get("c"); ok { 58 t.Error("expecting element C to be evicted") 59 } 60 61 if v, _, _ := c.Get("d"); v != "vd" { 62 t.Error("expecting element D to not be evicted") 63 } 64 65 // e, f, d, [g] 66 c.Set("g", "vg", time.Second) 67 if _, ok, _ := c.Get("E"); ok { 68 t.Error("expecting element E to be evicted") 69 } 70 71 if l := c.Len(); l != 3 { 72 t.Errorf("invalid length, want= 3, got= %v", l) 73 } 74 75 c.Del("missing") 76 c.Del("g") 77 if l := c.Len(); l != 2 { 78 t.Errorf("invalid length, want= 2, got= %v", l) 79 } 80 81 // f, d, [h, i] 82 c.MSet(map[string]string{"h": "vh", "i": "vi"}, time.Second) 83 if _, ok, _ := c.Get("e"); ok { 84 t.Error("expecting element E to be evicted") 85 } 86 if _, ok, _ := c.Get("f"); ok { 87 t.Error("expecting element F to be evicted") 88 } 89 if v, _, _ := c.Get("d"); v != "vd" { 90 t.Error("expecting element D to not be evicted") 91 } 92 93 // h/i, i/h, d, [h, i] 94 m := c.MGetString("h", "i") 95 if m["h"] != "vh" { 96 t.Error("expecting MSetString and MGetString to work") 97 } 98 if m["i"] != "vi" { 99 t.Error("expecting MSetString and MGetString to work") 100 } 101 102 if v, _, _ := c.GetQuiet("d"); v != "vd" { 103 t.Error("expecting GetQuiet to work") 104 } 105 106 if v, _ := c.GetNotStale("d"); v != "vd" { 107 t.Error("expecting GetNotStale to work") 108 } 109 } 110 111 func TestConcurrentGet(t *testing.T) { 112 t.Parallel() 113 c := createFilledCache(time.Second) 114 s := createRandInts(50000) 115 116 done := make(chan bool) 117 worker := func() { 118 for i := 0; i < 5000; i++ { 119 key := s[i] 120 v, exists, _ := c.Get(key) 121 if exists && v.(int64) != key { 122 t.Errorf("value not match: want= %v, got= %v", key, v) 123 } 124 } 125 done <- true 126 } 127 workers := 4 128 for i := 0; i < workers; i++ { 129 go worker() 130 } 131 for i := 0; i < workers; i++ { 132 _ = <-done 133 } 134 } 135 136 func TestConcurrentSet(t *testing.T) { 137 t.Parallel() 138 c := createFilledCache(time.Second) 139 s := createRandInts(5000) 140 141 done := make(chan bool) 142 worker := func() { 143 ttl := 4 * time.Second 144 for i := 0; i < 5000; i++ { 145 key := s[i] 146 c.Set(key, key, ttl) 147 } 148 done <- true 149 } 150 workers := 4 151 for i := 0; i < workers; i++ { 152 go worker() 153 } 154 for i := 0; i < workers; i++ { 155 _ = <-done 156 } 157 } 158 159 func TestConcurrentGetSet(t *testing.T) { 160 t.Parallel() 161 c := createFilledCache(time.Second) 162 s := createRandInts(5000) 163 164 done := make(chan bool) 165 getWorker := func() { 166 for i := 0; i < 5000; i++ { 167 key := s[i] 168 v, exists, _ := c.Get(key) 169 if exists && v.(int64) != key { 170 t.Errorf("value not match: want= %v, got= %v", key, v) 171 } 172 } 173 done <- true 174 } 175 setWorker := func() { 176 ttl := 4 * time.Second 177 for i := 0; i < 5000; i++ { 178 key := s[i] 179 c.Set(key, key, ttl) 180 } 181 done <- true 182 } 183 workers := 4 184 for i := 0; i < workers; i++ { 185 go getWorker() 186 go setWorker() 187 } 188 for i := 0; i < workers*2; i++ { 189 _ = <-done 190 } 191 } 192 193 func BenchmarkConcurrentGetLRUCache(bb *testing.B) { 194 c := createFilledCache(time.Second) 195 s := createRandInts(5000) 196 197 bb.ReportAllocs() 198 bb.ResetTimer() 199 cpu := runtime.GOMAXPROCS(0) 200 ch := make(chan bool) 201 worker := func() { 202 for i := 0; i < bb.N/cpu; i++ { 203 c.Get(s[i%5000]) 204 } 205 ch <- true 206 } 207 for i := 0; i < cpu; i++ { 208 go worker() 209 } 210 for i := 0; i < cpu; i++ { 211 _ = <-ch 212 } 213 } 214 215 func BenchmarkConcurrentSetLRUCache(bb *testing.B) { 216 c := createFilledCache(time.Second) 217 s := createRandInts(5000) 218 219 bb.ReportAllocs() 220 bb.ResetTimer() 221 cpu := runtime.GOMAXPROCS(0) 222 ch := make(chan bool) 223 worker := func() { 224 ttl := 4 * time.Second 225 for i := 0; i < bb.N/cpu; i++ { 226 key := s[i%5000] 227 c.Set(key, key, ttl) 228 } 229 ch <- true 230 } 231 for i := 0; i < cpu; i++ { 232 go worker() 233 } 234 for i := 0; i < cpu; i++ { 235 _ = <-ch 236 } 237 } 238 239 // No expiry 240 func BenchmarkConcurrentSetNXLRUCache(bb *testing.B) { 241 c := createFilledCache(time.Second) 242 s := createRandInts(5000) 243 244 bb.ReportAllocs() 245 bb.ResetTimer() 246 cpu := runtime.GOMAXPROCS(0) 247 ch := make(chan bool) 248 worker := func() { 249 for i := 0; i < bb.N/cpu; i++ { 250 key := s[i%5000] 251 c.Set(key, key, 0) 252 } 253 ch <- true 254 } 255 for i := 0; i < cpu; i++ { 256 go worker() 257 } 258 for i := 0; i < cpu; i++ { 259 _ = <-ch 260 } 261 }