github.com/TeaOSLab/EdgeNode@v1.3.8/internal/ttlcache/cache_test.go (about) 1 package ttlcache 2 3 import ( 4 "github.com/TeaOSLab/EdgeNode/internal/utils/fasttime" 5 memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem" 6 "github.com/TeaOSLab/EdgeNode/internal/utils/testutils" 7 "github.com/iwind/TeaGo/assert" 8 "github.com/iwind/TeaGo/rands" 9 "github.com/iwind/TeaGo/types" 10 timeutil "github.com/iwind/TeaGo/utils/time" 11 "runtime" 12 "runtime/debug" 13 "strconv" 14 "sync/atomic" 15 "testing" 16 "time" 17 ) 18 19 func TestNewCache(t *testing.T) { 20 var cache = NewCache[int]() 21 cache.Write("a", 1, time.Now().Unix()+3600) 22 cache.Write("b", 2, time.Now().Unix()+1) 23 cache.Write("c", 1, time.Now().Unix()+3602) 24 cache.Write("d", 1, time.Now().Unix()+1) 25 26 for _, piece := range cache.pieces { 27 if len(piece.m) > 0 { 28 for k, item := range piece.m { 29 t.Log(k, "=>", item.Value, item.expiredAt) 30 } 31 } 32 } 33 t.Log("a:", cache.Read("a")) 34 if testutils.IsSingleTesting() { 35 time.Sleep(5 * time.Second) 36 } 37 38 for i := 0; i < len(cache.pieces); i++ { 39 cache.GC() 40 } 41 42 t.Log("b:", cache.Read("b")) 43 t.Log("d:", cache.Read("d")) 44 t.Log("left:", cache.Count(), "items") 45 } 46 47 func TestCache_Memory(t *testing.T) { 48 if !testutils.IsSingleTesting() { 49 return 50 } 51 52 var cache = NewCache[int]() 53 var isReady bool 54 55 testutils.StartMemoryStats(t, func() { 56 if !isReady { 57 return 58 } 59 t.Log(cache.Count(), "items") 60 }) 61 62 var count = 1_000_000 63 if memutils.SystemMemoryGB() > 4 { 64 count = 20_000_000 65 } 66 for i := 0; i < count; i++ { 67 cache.Write("a"+strconv.Itoa(i), 1, time.Now().Unix()+int64(rands.Int(0, 300))) 68 } 69 70 func() { 71 var before = time.Now() 72 runtime.GC() 73 var costSeconds = time.Since(before).Seconds() 74 var stats = &debug.GCStats{} 75 debug.ReadGCStats(stats) 76 t.Log("GC pause:", stats.Pause[0].Seconds()*1000, "ms", "cost:", costSeconds*1000, "ms") 77 }() 78 79 isReady = true 80 81 t.Log(cache.Count()) 82 83 time.Sleep(10 * time.Second) 84 for i := 0; i < count; i++ { 85 if i%2 == 0 { 86 cache.Delete("a" + strconv.Itoa(i)) 87 } 88 } 89 90 t.Log(cache.Count()) 91 92 cache.Count() 93 94 time.Sleep(3600 * time.Second) 95 } 96 97 func TestCache_IncreaseInt64(t *testing.T) { 98 var a = assert.NewAssertion(t) 99 100 var cache = NewCache[int64]() 101 var unixTime = time.Now().Unix() 102 103 { 104 cache.IncreaseInt64("a", 1, unixTime+3600, false) 105 var item = cache.Read("a") 106 t.Log(item) 107 a.IsTrue(item.Value == 1) 108 a.IsTrue(item.expiredAt == unixTime+3600) 109 } 110 { 111 cache.IncreaseInt64("a", 1, unixTime+3600+1, true) 112 var item = cache.Read("a") 113 t.Log(item) 114 a.IsTrue(item.Value == 2) 115 a.IsTrue(item.expiredAt == unixTime+3600+1) 116 } 117 { 118 cache.Write("b", 1, time.Now().Unix()+3600+2) 119 t.Log(cache.Read("b")) 120 } 121 { 122 cache.IncreaseInt64("b", 1, time.Now().Unix()+3600+3, false) 123 t.Log(cache.Read("b")) 124 } 125 } 126 127 func TestCache_Read(t *testing.T) { 128 if !testutils.IsSingleTesting() { 129 return 130 } 131 132 runtime.GOMAXPROCS(1) 133 134 var cache = NewCache[int](PiecesOption{Count: 32}) 135 136 for i := 0; i < 10_000_000; i++ { 137 cache.Write("HELLO_WORLD_"+strconv.Itoa(i), i, time.Now().Unix()+int64(i%10240)+1) 138 } 139 time.Sleep(10 * time.Second) 140 141 total := 0 142 for _, piece := range cache.pieces { 143 //t.Log(len(piece.m), "keys") 144 total += len(piece.m) 145 } 146 t.Log(total, "total keys") 147 148 before := time.Now() 149 for i := 0; i < 10_240; i++ { 150 _ = cache.Read("HELLO_WORLD_" + strconv.Itoa(i)) 151 } 152 t.Log(time.Since(before).Seconds()*1000, "ms") 153 } 154 155 func TestCache_GC(t *testing.T) { 156 if !testutils.IsSingleTesting() { 157 return 158 } 159 160 var cache = NewCache[int](&PiecesOption{Count: 5}) 161 cache.Write("a", 1, time.Now().Unix()+1) 162 cache.Write("b", 2, time.Now().Unix()+2) 163 cache.Write("c", 3, time.Now().Unix()+3) 164 cache.Write("d", 4, time.Now().Unix()+4) 165 cache.Write("e", 5, time.Now().Unix()+10) 166 167 go func() { 168 for i := 0; i < 1000; i++ { 169 cache.Write("f", 1, time.Now().Unix()+1) 170 time.Sleep(10 * time.Millisecond) 171 } 172 }() 173 174 for i := 0; i < 20; i++ { 175 cache.GC() 176 t.Log("items:", cache.Count()) 177 178 if cache.Count() == 0 { 179 break 180 } 181 time.Sleep(1 * time.Second) 182 } 183 184 t.Log("now:", time.Now().Unix()) 185 for _, p := range cache.pieces { 186 t.Log("expire list:", p.expiresList.Count(), p.expiresList) 187 for k, v := range p.m { 188 t.Log(k, v.Value, v.expiredAt) 189 } 190 } 191 } 192 193 func TestCache_GC2(t *testing.T) { 194 if !testutils.IsSingleTesting() { 195 return 196 } 197 198 runtime.GOMAXPROCS(1) 199 200 var cache1 = NewCache[int](NewPiecesOption(256)) 201 for i := 0; i < 10_000_000; i++ { 202 cache1.Write(strconv.Itoa(i), i, time.Now().Unix()+10) 203 } 204 205 var cache2 = NewCache[int](NewPiecesOption(5)) 206 for i := 0; i < 1_000_000; i++ { 207 cache2.Write(strconv.Itoa(i), i, time.Now().Unix()+int64(rands.Int(0, 20))) 208 } 209 210 for i := 0; i < 3600; i++ { 211 t.Log(timeutil.Format("H:i:s"), cache1.Count(), "items", cache2.Count(), "items") 212 if cache1.Count() == 0 && cache2.Count() == 0 { 213 break 214 } 215 time.Sleep(1 * time.Second) 216 } 217 } 218 219 func TestCacheDestroy(t *testing.T) { 220 var cache = NewCache[int]() 221 t.Log("count:", SharedManager.Count()) 222 cache.Destroy() 223 t.Log("count:", SharedManager.Count()) 224 } 225 226 func BenchmarkNewCache(b *testing.B) { 227 runtime.GOMAXPROCS(1) 228 229 var cache = NewCache[int](NewPiecesOption(128)) 230 for i := 0; i < 2_000_000; i++ { 231 cache.Write(strconv.Itoa(i), i, time.Now().Unix()+int64(rands.Int(10, 100))) 232 } 233 b.Log("start reading ...") 234 235 b.ResetTimer() 236 237 b.RunParallel(func(pb *testing.PB) { 238 for pb.Next() { 239 cache.Read(strconv.Itoa(rands.Int(0, 999999))) 240 } 241 }) 242 } 243 244 func BenchmarkCache_Add(b *testing.B) { 245 runtime.GOMAXPROCS(1) 246 247 var cache = NewCache[int]() 248 for i := 0; i < b.N; i++ { 249 cache.Write(strconv.Itoa(i), i, fasttime.Now().Unix()+int64(i%1024)) 250 } 251 } 252 253 func BenchmarkCache_Add_Parallel(b *testing.B) { 254 runtime.GOMAXPROCS(1) 255 256 var cache = NewCache[int64]() 257 var i int64 258 b.RunParallel(func(pb *testing.PB) { 259 for pb.Next() { 260 var j = atomic.AddInt64(&i, 1) 261 cache.Write(types.String(j%1e6), j, fasttime.Now().Unix()+i%1024) 262 } 263 }) 264 } 265 266 func BenchmarkNewCacheGC(b *testing.B) { 267 runtime.GOMAXPROCS(1) 268 269 var cache = NewCache[int](NewPiecesOption(1024)) 270 for i := 0; i < 3_000_000; i++ { 271 cache.Write(strconv.Itoa(i), i, time.Now().Unix()+int64(rands.Int(0, 100))) 272 } 273 //b.Log(cache.pieces[0].Count()) 274 275 b.ResetTimer() 276 b.RunParallel(func(pb *testing.PB) { 277 for pb.Next() { 278 cache.GC() 279 } 280 }) 281 } 282 283 func BenchmarkNewCacheClean(b *testing.B) { 284 runtime.GOMAXPROCS(1) 285 286 var cache = NewCache[int](NewPiecesOption(128)) 287 for i := 0; i < 3_000_000; i++ { 288 cache.Write(strconv.Itoa(i), i, time.Now().Unix()+int64(rands.Int(10, 100))) 289 } 290 291 b.ResetTimer() 292 b.RunParallel(func(pb *testing.PB) { 293 for pb.Next() { 294 cache.Clean() 295 } 296 }) 297 }