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  }