github.com/TeaOSLab/EdgeNode@v1.3.8/internal/caches/list_file_kv_test.go (about)

     1  // Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
     2  
     3  package caches_test
     4  
     5  import (
     6  	"fmt"
     7  	"github.com/TeaOSLab/EdgeNode/internal/caches"
     8  	"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
     9  	"github.com/iwind/TeaGo/Tea"
    10  	_ "github.com/iwind/TeaGo/bootstrap"
    11  	stringutil "github.com/iwind/TeaGo/utils/string"
    12  	"math/rand"
    13  	"strconv"
    14  	"sync"
    15  	"testing"
    16  	"time"
    17  )
    18  
    19  var testingKVList *caches.KVFileList
    20  
    21  func testOpenKVFileList(t *testing.T) *caches.KVFileList {
    22  	var list = caches.NewKVFileList(Tea.Root + "/data/stores/cache-stores")
    23  	err := list.Init()
    24  	if err != nil {
    25  		t.Fatal(err)
    26  	}
    27  
    28  	testingKVList = list
    29  	return list
    30  }
    31  
    32  func TestNewKVFileList(t *testing.T) {
    33  	var list = testOpenKVFileList(t)
    34  	err := list.Close()
    35  	if err != nil {
    36  		t.Fatal(err)
    37  	}
    38  }
    39  
    40  func TestKVFileList_Add(t *testing.T) {
    41  	var list = testOpenKVFileList(t)
    42  	defer func() {
    43  		_ = list.Close()
    44  	}()
    45  
    46  	err := list.Add(stringutil.Md5("123456"), &caches.Item{
    47  		Type:       caches.ItemTypeFile,
    48  		Key:        "https://example.com/index.html",
    49  		ExpiresAt:  time.Now().Unix() + 60,
    50  		StaleAt:    0,
    51  		HeaderSize: 0,
    52  		BodySize:   4096,
    53  		MetaSize:   0,
    54  		Host:       "",
    55  		ServerId:   1,
    56  		Week:       0,
    57  	})
    58  	if err != nil {
    59  		t.Fatal(err)
    60  	}
    61  }
    62  
    63  func TestKVFileList_Add_Many(t *testing.T) {
    64  	if !testutils.IsSingleTesting() {
    65  		return
    66  	}
    67  
    68  	var list = testOpenKVFileList(t)
    69  	defer func() {
    70  		_ = list.Close()
    71  	}()
    72  
    73  	const start = 0
    74  	const count = 1_000_000
    75  	const concurrent = 100
    76  
    77  	var before = time.Now()
    78  	defer func() {
    79  		var costSeconds = time.Since(before).Seconds()
    80  		t.Log("cost:", fmt.Sprintf("%.2fs", costSeconds), "qps:", fmt.Sprintf("%.2fK/s", float64(count)/1000/costSeconds))
    81  	}()
    82  
    83  	var wg = &sync.WaitGroup{}
    84  	wg.Add(concurrent)
    85  	for c := 0; c < concurrent; c++ {
    86  		go func(c int) {
    87  			defer wg.Done()
    88  
    89  			var segmentStart = start + count/concurrent*c
    90  			for i := segmentStart; i < segmentStart+count/concurrent; i++ {
    91  				err := list.Add(stringutil.Md5(strconv.Itoa(i)), &caches.Item{
    92  					Type:       caches.ItemTypeFile,
    93  					Key:        "https://www.example.com/index.html" + strconv.Itoa(i),
    94  					ExpiresAt:  time.Now().Unix() + 3600,
    95  					StaleAt:    0,
    96  					HeaderSize: 0,
    97  					BodySize:   int64(rand.Int() % 1_000_000),
    98  					MetaSize:   0,
    99  					Host:       "",
   100  					ServerId:   1,
   101  					Week:       0,
   102  				})
   103  				if err != nil {
   104  					t.Log(err)
   105  				}
   106  			}
   107  		}(c)
   108  	}
   109  	wg.Wait()
   110  }
   111  
   112  func TestKVFileList_Add_Many_Suffix(t *testing.T) {
   113  	if !testutils.IsSingleTesting() {
   114  		return
   115  	}
   116  
   117  	var list = testOpenKVFileList(t)
   118  	defer func() {
   119  		_ = list.Close()
   120  	}()
   121  
   122  	const start = 0
   123  	const count = 1000
   124  	const concurrent = 100
   125  
   126  	var before = time.Now()
   127  	defer func() {
   128  		var costSeconds = time.Since(before).Seconds()
   129  		t.Log("cost:", fmt.Sprintf("%.2fs", costSeconds), "qps:", fmt.Sprintf("%.2fK/s", float64(count)/1000/costSeconds))
   130  	}()
   131  
   132  	var wg = &sync.WaitGroup{}
   133  	wg.Add(concurrent)
   134  	for c := 0; c < concurrent; c++ {
   135  		go func(c int) {
   136  			defer wg.Done()
   137  
   138  			var segmentStart = start + count/concurrent*c
   139  			for i := segmentStart; i < segmentStart+count/concurrent; i++ {
   140  				err := list.Add(stringutil.Md5(strconv.Itoa(i)+caches.SuffixAll), &caches.Item{
   141  					Type:       caches.ItemTypeFile,
   142  					Key:        "https://www.example.com/index.html" + strconv.Itoa(i) + caches.SuffixAll + "zip",
   143  					ExpiresAt:  time.Now().Unix() + 60,
   144  					StaleAt:    0,
   145  					HeaderSize: 0,
   146  					BodySize:   int64(rand.Int() % 1_000_000),
   147  					MetaSize:   0,
   148  					Host:       "",
   149  					ServerId:   1,
   150  					Week:       0,
   151  				})
   152  				if err != nil {
   153  					t.Log(err)
   154  				}
   155  			}
   156  		}(c)
   157  	}
   158  	wg.Wait()
   159  }
   160  
   161  func TestKVFileList_Exist(t *testing.T) {
   162  	var list = testOpenKVFileList(t)
   163  	defer func() {
   164  		_ = list.Close()
   165  	}()
   166  
   167  	for _, hash := range []string{
   168  		stringutil.Md5("123456"),
   169  		stringutil.Md5("654321"),
   170  	} {
   171  		b, _, err := list.Exist(hash)
   172  		if err != nil {
   173  			t.Fatal(err)
   174  		}
   175  		t.Log(hash, "=>", b)
   176  	}
   177  }
   178  
   179  func TestKVFileList_ExistMany(t *testing.T) {
   180  	var list = testOpenKVFileList(t)
   181  	defer func() {
   182  		_ = list.Close()
   183  	}()
   184  
   185  	var countFound int
   186  	var count = 10
   187  	if testutils.IsSingleTesting() {
   188  		count = 2_000_000
   189  	}
   190  
   191  	var before = time.Now()
   192  	for i := 0; i < count; i++ {
   193  		ok, _, err := list.Exist(stringutil.Md5(strconv.Itoa(i)))
   194  		if err != nil {
   195  			t.Fatal(err)
   196  		}
   197  		if ok {
   198  			countFound++
   199  		}
   200  	}
   201  	var costSeconds = time.Since(before).Seconds()
   202  	t.Log("total:", costSeconds*1000, "ms", "found:", countFound, "qps:", fmt.Sprintf("%.2fK/s", float64(count)/costSeconds/1000), "per read:", fmt.Sprintf("%.4fms", costSeconds*1000/float64(count)))
   203  }
   204  
   205  func TestKVFileList_ExistQuick(t *testing.T) {
   206  	var list = testOpenKVFileList(t)
   207  	defer func() {
   208  		_ = list.Close()
   209  	}()
   210  
   211  	for _, hash := range []string{
   212  		stringutil.Md5("123456"),
   213  		stringutil.Md5("654321"),
   214  	} {
   215  		b, err := list.ExistQuick(hash)
   216  		if err != nil {
   217  			t.Fatal(err)
   218  		}
   219  		t.Log(hash, "=>", b)
   220  	}
   221  }
   222  
   223  func TestKVFileList_Remove(t *testing.T) {
   224  	var list = testOpenKVFileList(t)
   225  	defer func() {
   226  		_ = list.Close()
   227  	}()
   228  
   229  	for _, hash := range []string{
   230  		stringutil.Md5("123456"),
   231  		stringutil.Md5("654321"),
   232  	} {
   233  		err := list.Remove(hash)
   234  		if err != nil {
   235  			t.Fatal(err)
   236  		}
   237  	}
   238  }
   239  
   240  func TestKVFileList_RemoveMany(t *testing.T) {
   241  	var list = testOpenKVFileList(t)
   242  	defer func() {
   243  		_ = list.Close()
   244  	}()
   245  
   246  	var count = 10
   247  	if testutils.IsSingleTesting() {
   248  		count = 2_000_000
   249  	}
   250  
   251  	var before = time.Now()
   252  	for i := 0; i < count; i++ {
   253  		err := list.Remove(stringutil.Md5(strconv.Itoa(i)))
   254  		if err != nil {
   255  			t.Fatal(err)
   256  		}
   257  	}
   258  	var costSeconds = time.Since(before).Seconds()
   259  	t.Log("total:", costSeconds*1000, "ms", "qps:", fmt.Sprintf("%.2fK/s", float64(count)/costSeconds/1000), "per delete:", fmt.Sprintf("%.4fms", costSeconds*1000/float64(count)))
   260  }
   261  
   262  func TestKVFileList_CleanAll(t *testing.T) {
   263  	var list = testOpenKVFileList(t)
   264  	defer func() {
   265  		_ = list.Close()
   266  	}()
   267  
   268  	err := list.CleanAll()
   269  	if err != nil {
   270  		t.Fatal(err)
   271  	}
   272  }
   273  
   274  func TestKVFileList_Inspect(t *testing.T) {
   275  	if !testutils.IsSingleTesting() {
   276  		return
   277  	}
   278  
   279  	var list = testOpenKVFileList(t)
   280  	defer func() {
   281  		_ = list.Close()
   282  	}()
   283  
   284  	err := list.TestInspect(t)
   285  	if err != nil {
   286  		t.Fatal(err)
   287  	}
   288  }
   289  
   290  func TestKVFileList_Purge(t *testing.T) {
   291  	var list = testOpenKVFileList(t)
   292  	defer func() {
   293  		_ = list.Close()
   294  	}()
   295  
   296  	var before = time.Now()
   297  	count, err := list.Purge(4_000, func(hash string) error {
   298  		//t.Log("hash:", hash)
   299  		return nil
   300  	})
   301  	if err != nil {
   302  		t.Fatal(err)
   303  	}
   304  	t.Log("cost:", fmt.Sprintf("%.2fms", time.Since(before).Seconds()*1000), "count:", count)
   305  }
   306  
   307  func TestKVFileList_PurgeLFU(t *testing.T) {
   308  	var list = testOpenKVFileList(t)
   309  	defer func() {
   310  		_ = list.Close()
   311  	}()
   312  
   313  	var before = time.Now()
   314  	err := list.PurgeLFU(20000, func(hash string) error {
   315  		t.Log("hash:", hash)
   316  		return nil
   317  	})
   318  	if err != nil {
   319  		t.Fatal(err)
   320  	}
   321  	t.Log("cost:", fmt.Sprintf("%.2fms", time.Since(before).Seconds()*1000))
   322  }
   323  
   324  func TestKVFileList_Count(t *testing.T) {
   325  	var list = testOpenKVFileList(t)
   326  	defer func() {
   327  		_ = list.Close()
   328  	}()
   329  
   330  	var before = time.Now()
   331  	count, err := list.Count()
   332  	if err != nil {
   333  		t.Fatal(err)
   334  	}
   335  	t.Log("cost:", fmt.Sprintf("%.2fms", time.Since(before).Seconds()*1000), "count:", count)
   336  }
   337  
   338  func TestKVFileList_Stat(t *testing.T) {
   339  	var list = testOpenKVFileList(t)
   340  	defer func() {
   341  		_ = list.Close()
   342  	}()
   343  
   344  	var before = time.Now()
   345  	stat, err := list.Stat(func(hash string) bool {
   346  		return true
   347  	})
   348  	if err != nil {
   349  		t.Fatal(err)
   350  	}
   351  	t.Log("cost:", fmt.Sprintf("%.2fms", time.Since(before).Seconds()*1000), "stat:", fmt.Sprintf("%+v", stat))
   352  }
   353  
   354  func TestKVFileList_CleanPrefix(t *testing.T) {
   355  	var list = testOpenKVFileList(t)
   356  	defer func() {
   357  		_ = list.Close()
   358  	}()
   359  
   360  	var before = time.Now()
   361  
   362  	defer func() {
   363  		var costSeconds = time.Since(before).Seconds()
   364  		t.Log("cost:", fmt.Sprintf("%.2fms", costSeconds*1000))
   365  	}()
   366  
   367  	err := list.CleanPrefix("https://www.example.com/index.html")
   368  	if err != nil {
   369  		t.Fatal(err)
   370  	}
   371  }
   372  
   373  func TestKVFileList_CleanMatchPrefix(t *testing.T) {
   374  	var list = testOpenKVFileList(t)
   375  	defer func() {
   376  		_ = list.Close()
   377  	}()
   378  
   379  	var before = time.Now()
   380  
   381  	defer func() {
   382  		var costSeconds = time.Since(before).Seconds()
   383  		t.Log("cost:", fmt.Sprintf("%.2fms", costSeconds*1000))
   384  	}()
   385  
   386  	err := list.CleanMatchPrefix("https://*.example.com/index.html")
   387  	if err != nil {
   388  		t.Fatal(err)
   389  	}
   390  }
   391  
   392  func TestKVFileList_CleanMatchKey(t *testing.T) {
   393  	var list = testOpenKVFileList(t)
   394  	defer func() {
   395  		_ = list.Close()
   396  	}()
   397  
   398  	var before = time.Now()
   399  
   400  	defer func() {
   401  		var costSeconds = time.Since(before).Seconds()
   402  		t.Log("cost:", fmt.Sprintf("%.2fms", costSeconds*1000))
   403  	}()
   404  
   405  	err := list.CleanMatchKey("https://*.example.com/index.html123")
   406  	if err != nil {
   407  		t.Fatal(err)
   408  	}
   409  }
   410  
   411  func BenchmarkKVFileList_Exist(b *testing.B) {
   412  	var list = caches.NewKVFileList(Tea.Root + "/data/stores/cache-stores")
   413  	err := list.Init()
   414  	if err != nil {
   415  		b.Fatal(err)
   416  	}
   417  
   418  	defer func() {
   419  		_ = list.Close()
   420  	}()
   421  
   422  	b.ResetTimer()
   423  
   424  	b.RunParallel(func(pb *testing.PB) {
   425  		for pb.Next() {
   426  			_, _, existErr := list.Exist(stringutil.Md5(strconv.Itoa(rand.Int() % 2_000_000)))
   427  			if existErr != nil {
   428  				b.Fatal(existErr)
   429  			}
   430  		}
   431  	})
   432  }