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 }