github.com/TeaOSLab/EdgeNode@v1.3.8/internal/utils/kvstore/table_field_test.go (about)

     1  // Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
     2  
     3  package kvstore_test
     4  
     5  import (
     6  	"encoding/binary"
     7  	"errors"
     8  	"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
     9  	"github.com/TeaOSLab/EdgeNode/internal/utils/kvstore"
    10  	"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
    11  	"strconv"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  type testCachedItem struct {
    17  	Hash       string `json:"1"` // as key
    18  	URL        string `json:"2"`
    19  	ExpiresAt  int64  `json:"3"`
    20  	Tag        string `json:"tag"`
    21  	HeaderSize int64  `json:"headerSize"`
    22  	BodySize   int64  `json:"bodySize"`
    23  	MetaSize   int    `json:"metaSize"`
    24  	StaleAt    int64  `json:"staleAt"`
    25  	CreatedAt  int64  `json:"createdAt"`
    26  	Host       string `json:"host"`
    27  	ServerId   int64  `json:"serverId"`
    28  }
    29  
    30  type testCacheItemEncoder[T interface{ *testCachedItem }] struct {
    31  	kvstore.BaseObjectEncoder[T]
    32  }
    33  
    34  func (this *testCacheItemEncoder[T]) EncodeField(value T, fieldName string) ([]byte, error) {
    35  	switch fieldName {
    36  	case "expiresAt":
    37  		var b = make([]byte, 4)
    38  		binary.BigEndian.PutUint32(b, uint32(any(value).(*testCachedItem).ExpiresAt))
    39  		return b, nil
    40  	case "staleAt":
    41  		var b = make([]byte, 4)
    42  		binary.BigEndian.PutUint32(b, uint32(any(value).(*testCachedItem).StaleAt))
    43  		return b, nil
    44  	case "url":
    45  		return []byte(any(value).(*testCachedItem).URL), nil
    46  	}
    47  	return nil, errors.New("EncodeField: invalid field name '" + fieldName + "'")
    48  }
    49  
    50  func TestTable_AddField(t *testing.T) {
    51  	var table = testOpenStoreTable[*testCachedItem](t, "cache_items", &testCacheItemEncoder[*testCachedItem]{})
    52  
    53  	defer func() {
    54  		_ = testingStore.Close()
    55  	}()
    56  
    57  	err := table.AddFields("expiresAt")
    58  	if err != nil {
    59  		t.Fatal(err)
    60  	}
    61  
    62  	var before = time.Now()
    63  	for _, item := range []*testCachedItem{
    64  		{
    65  			Hash:      "a1",
    66  			URL:       "https://example.com/a1",
    67  			ExpiresAt: 1710832067,
    68  		},
    69  		{
    70  			Hash:      "a5",
    71  			URL:       "https://example.com/a5",
    72  			ExpiresAt: time.Now().Unix() + 7200,
    73  		},
    74  		{
    75  			Hash:      "a4",
    76  			URL:       "https://example.com/a4",
    77  			ExpiresAt: time.Now().Unix() + 86400,
    78  		},
    79  		{
    80  			Hash:      "a3",
    81  			URL:       "https://example.com/a3",
    82  			ExpiresAt: time.Now().Unix() + 1800,
    83  		},
    84  		{
    85  			Hash:      "a2",
    86  			URL:       "https://example.com/a2",
    87  			ExpiresAt: time.Now().Unix() + 365*86400,
    88  		},
    89  	} {
    90  		err = table.Set(item.Hash, item)
    91  		if err != nil {
    92  			t.Fatal(err)
    93  		}
    94  	}
    95  
    96  	t.Log("set cost:", time.Since(before).Seconds()*1000, "ms")
    97  
    98  	testInspectDB(t)
    99  }
   100  
   101  func TestTable_AddField_Many(t *testing.T) {
   102  	if !testutils.IsSingleTesting() {
   103  		return
   104  	}
   105  
   106  	//runtime.GOMAXPROCS(1)
   107  
   108  	var table = testOpenStoreTable[*testCachedItem](t, "cache_items", &testCacheItemEncoder[*testCachedItem]{})
   109  
   110  	defer func() {
   111  		_ = testingStore.Close()
   112  	}()
   113  
   114  	{
   115  		err := table.AddFields("expiresAt")
   116  		if err != nil {
   117  			t.Fatal(err)
   118  		}
   119  	}
   120  
   121  	{
   122  		err := table.AddFields("staleAt")
   123  		if err != nil {
   124  			t.Fatal(err)
   125  		}
   126  	}
   127  
   128  	{
   129  		err := table.AddFields("url")
   130  		if err != nil {
   131  			t.Fatal(err)
   132  		}
   133  	}
   134  
   135  	var before = time.Now()
   136  	const from = 0
   137  	const count = 4_000_000
   138  
   139  	defer func() {
   140  		var costSeconds = time.Since(before).Seconds()
   141  		t.Log("cost:", costSeconds*1000, "ms", "qps:", int64(float64(count)/costSeconds))
   142  	}()
   143  
   144  	for i := from; i < from+count; i++ {
   145  		var item = &testCachedItem{
   146  			Hash:      "a" + strconv.Itoa(i),
   147  			URL:       "https://example.com/a" + strconv.Itoa(i),
   148  			ExpiresAt: 1710832067 + int64(i),
   149  			StaleAt:   fasttime.Now().Unix() + int64(i),
   150  			CreatedAt: fasttime.Now().Unix(),
   151  		}
   152  		err := table.Set(item.Hash, item)
   153  		if err != nil {
   154  			t.Fatal(err)
   155  		}
   156  	}
   157  }
   158  
   159  func TestTable_AddField_Delete_Many(t *testing.T) {
   160  	if !testutils.IsSingleTesting() {
   161  		return
   162  	}
   163  
   164  	//runtime.GOMAXPROCS(1)
   165  
   166  	var table = testOpenStoreTable[*testCachedItem](t, "cache_items", &testCacheItemEncoder[*testCachedItem]{})
   167  
   168  	defer func() {
   169  		_ = testingStore.Close()
   170  	}()
   171  
   172  	{
   173  		err := table.AddFields("expiresAt")
   174  		if err != nil {
   175  			t.Fatal(err)
   176  		}
   177  	}
   178  
   179  	{
   180  		err := table.AddFields("staleAt")
   181  		if err != nil {
   182  			t.Fatal(err)
   183  		}
   184  	}
   185  
   186  	{
   187  		err := table.AddFields("url")
   188  		if err != nil {
   189  			t.Fatal(err)
   190  		}
   191  	}
   192  
   193  	var before = time.Now()
   194  	const from = 0
   195  	const count = 1_000_000
   196  
   197  	for i := from; i < from+count; i++ {
   198  		var item = &testCachedItem{
   199  			Hash: "a" + strconv.Itoa(i),
   200  		}
   201  		err := table.Delete(item.Hash)
   202  		if err != nil {
   203  			t.Fatal(err)
   204  		}
   205  	}
   206  
   207  	var costSeconds = time.Since(before).Seconds()
   208  	t.Log("cost:", costSeconds*1000, "ms", "qps:", int64(float64(count)/costSeconds))
   209  
   210  	countLeft, err := table.Count()
   211  	if err != nil {
   212  		t.Fatal(err)
   213  	}
   214  	t.Log("left:", countLeft)
   215  }
   216  
   217  func TestTable_DropField(t *testing.T) {
   218  	var table = testOpenStoreTable[*testCachedItem](t, "cache_items", &testCacheItemEncoder[*testCachedItem]{})
   219  
   220  	defer func() {
   221  		_ = testingStore.Close()
   222  	}()
   223  
   224  	var before = time.Now()
   225  	defer func() {
   226  		var costSeconds = time.Since(before).Seconds()
   227  		t.Log("cost:", costSeconds*1000, "ms")
   228  	}()
   229  
   230  	err := table.DropField("expiresAt")
   231  	if err != nil {
   232  		t.Fatal(err)
   233  	}
   234  }
   235  
   236  /**func TestTable_DeleteFieldValue(t *testing.T) {
   237  	var table = testOpenStoreTable[*testCachedItem](t, "cache_items", &testCacheItemEncoder[*testCachedItem]{})
   238  	err := table.AddField("expiresAt")
   239  	if err != nil {
   240  		t.Fatal(err)
   241  	}
   242  
   243  	var before = time.Now()
   244  	defer func() {
   245  		var costSeconds = time.Since(before).Seconds()
   246  		t.Log("cost:", costSeconds*1000, "ms")
   247  	}()
   248  
   249  	err = table.Delete("a2")
   250  	if err != nil {
   251  		t.Fatal(err)
   252  	}
   253  
   254  	testInspectDB(t)
   255  }
   256  **/
   257  
   258  func TestTable_Inspect(t *testing.T) {
   259  	var table = testOpenStoreTable[*testCachedItem](t, "cache_items", &testCacheItemEncoder[*testCachedItem]{})
   260  
   261  	defer func() {
   262  		_ = testingStore.Close()
   263  	}()
   264  
   265  	err := table.AddFields("expiresAt")
   266  	if err != nil {
   267  		t.Fatal(err)
   268  	}
   269  
   270  	testInspectDB(t)
   271  }