github.com/cs3org/reva/v2@v2.27.7/pkg/store/memory/memstore_test.go (about) 1 package memory 2 3 import ( 4 "context" 5 "encoding/hex" 6 "hash/fnv" 7 "math/rand" 8 "sort" 9 "strconv" 10 "strings" 11 "sync" 12 "testing" 13 "time" 14 15 "sync/atomic" 16 17 "go-micro.dev/v4/store" 18 ) 19 20 func TestWriteAndRead(t *testing.T) { 21 cache := NewMemStore() 22 data := map[string]string{ 23 "abaya": "v329487", 24 "abaaz": "v398342", 25 "abayakjdkj": "v989898", 26 "zzzz": "viaooouyenbdnya", 27 "abazzz": "v57869nbdnya", 28 "mbmbmb": "viuyenbdnya", 29 "zozzz": "vooouyenbdnya", 30 "zzaz": "viaooouyenbdnya", 31 "mbzzaamb": "viunya", 32 } 33 34 for key, value := range data { 35 record := &store.Record{ 36 Key: key, 37 Value: []byte(value), 38 } 39 _ = cache.Write(record) 40 } 41 42 t.Run("Plain", func(t *testing.T) { 43 readPlain(t, cache) 44 }) 45 t.Run("Prefix", func(t *testing.T) { 46 readPrefix(t, cache) 47 }) 48 t.Run("Suffix", func(t *testing.T) { 49 readSuffix(t, cache) 50 }) 51 t.Run("PrefixSuffix", func(t *testing.T) { 52 readPrefixSuffix(t, cache) 53 }) 54 t.Run("PrefixLimitOffset", func(t *testing.T) { 55 readPrefixLimitOffset(t, cache) 56 }) 57 t.Run("SuffixLimitOffset", func(t *testing.T) { 58 readSuffixLimitOffset(t, cache) 59 }) 60 t.Run("PrefixSuffixLimitOffset", func(t *testing.T) { 61 readPrefixSuffixLimitOffset(t, cache) 62 }) 63 } 64 65 func readPlain(t *testing.T, cache store.Store) { 66 // expected data in the cache 67 data := map[string]string{ 68 "abaya": "v329487", 69 "abaaz": "v398342", 70 "abayakjdkj": "v989898", 71 "zzzz": "viaooouyenbdnya", 72 "abazzz": "v57869nbdnya", 73 "mbmbmb": "viuyenbdnya", 74 "zozzz": "vooouyenbdnya", 75 "zzaz": "viaooouyenbdnya", 76 "mbzzaamb": "viunya", 77 } 78 for key, value := range data { 79 records, _ := cache.Read(key) 80 if len(records) != 1 { 81 t.Fatalf("Plain read for key %s returned %d records", key, len(records)) 82 } 83 if key != records[0].Key { 84 t.Errorf("Plain read for key %s returned got wrong key %s", key, records[0].Key) 85 } 86 v := string(records[0].Value) 87 if value != v { 88 t.Errorf("Plain read for key %s returned different value, expected %s, got %s", key, value, v) 89 } 90 } 91 } 92 93 func readPrefix(t *testing.T, cache store.Store) { 94 pref1 := []struct { 95 Key string 96 Value string 97 }{ 98 {Key: "abaya", Value: "v329487"}, 99 {Key: "abayakjdkj", Value: "v989898"}, 100 } 101 102 pref2 := []struct { 103 Key string 104 Value string 105 }{ 106 {Key: "zozzz", Value: "vooouyenbdnya"}, 107 {Key: "zzaz", Value: "viaooouyenbdnya"}, 108 {Key: "zzzz", Value: "viaooouyenbdnya"}, 109 } 110 111 records, _ := cache.Read("abaya", store.ReadPrefix()) 112 if len(records) != 2 { 113 t.Fatalf("Prefix read for \"abaya\" returned %d records, expected 2", len(records)) 114 } 115 for index, record := range records { 116 // it should be sorted alphabetically 117 if pref1[index].Key != record.Key { 118 t.Errorf("Unexpected key for prefix \"abaya\", index %d, expected %s, got %s", index, pref1[index].Key, record.Key) 119 } 120 if pref1[index].Value != string(record.Value) { 121 t.Errorf("Unexpected value for prefix \"abaya\", index %d, expected %s, got %s", index, pref1[index].Value, record.Value) 122 } 123 } 124 125 records, _ = cache.Read("z", store.ReadPrefix()) 126 if len(records) != 3 { 127 t.Fatalf("Prefix read for \"z\" returned %d records, expected 3", len(records)) 128 } 129 for index, record := range records { 130 // it should be sorted alphabetically 131 if pref2[index].Key != record.Key { 132 t.Errorf("Unexpected key for prefix \"z\", index %d, expected %s, got %s", index, pref2[index].Key, record.Key) 133 } 134 if pref2[index].Value != string(record.Value) { 135 t.Errorf("Unexpected value for prefix \"z\", index %d, expected %s, got %s", index, pref2[index].Value, record.Value) 136 } 137 } 138 } 139 140 func readSuffix(t *testing.T, cache store.Store) { 141 pref1 := []struct { 142 Key string 143 Value string 144 }{ 145 {Key: "abaaz", Value: "v398342"}, 146 {Key: "zzaz", Value: "viaooouyenbdnya"}, 147 } 148 pref2 := []struct { 149 Key string 150 Value string 151 }{ 152 {Key: "abaaz", Value: "v398342"}, 153 {Key: "zzaz", Value: "viaooouyenbdnya"}, 154 {Key: "abazzz", Value: "v57869nbdnya"}, 155 {Key: "zozzz", Value: "vooouyenbdnya"}, 156 {Key: "zzzz", Value: "viaooouyenbdnya"}, 157 } 158 159 records, _ := cache.Read("az", store.ReadSuffix()) 160 if len(records) != 2 { 161 t.Fatalf("Suffix read for \"az\" returned %d records, expected 2", len(records)) 162 } 163 for index, record := range records { 164 // it should be sorted alphabetically 165 if pref1[index].Key != record.Key { 166 t.Errorf("Unexpected key for suffix \"az\", index %d, expected %s, got %s", index, pref1[index].Key, record.Key) 167 } 168 if pref1[index].Value != string(record.Value) { 169 t.Errorf("Unexpected value for suffix \"az\", index %d, expected %s, got %s", index, pref1[index].Value, record.Value) 170 } 171 } 172 173 records, _ = cache.Read("z", store.ReadSuffix()) 174 if len(records) != 5 { 175 t.Fatalf("Suffix read for \"z\" returned %d records, expected 5", len(records)) 176 } 177 for index, record := range records { 178 if pref2[index].Key != record.Key { 179 t.Errorf("Unexpected key for suffix \"z\", index %d, expected %s, got %s", index, pref2[index].Key, record.Key) 180 } 181 if pref2[index].Value != string(record.Value) { 182 t.Errorf("Unexpected value for suffix \"z\", index %d, expected %s, got %s", index, pref2[index].Value, record.Value) 183 } 184 } 185 } 186 187 func readPrefixSuffix(t *testing.T, cache store.Store) { 188 pref1 := []struct { 189 Key string 190 Value string 191 }{ 192 {Key: "zozzz", Value: "vooouyenbdnya"}, 193 {Key: "zzaz", Value: "viaooouyenbdnya"}, 194 {Key: "zzzz", Value: "viaooouyenbdnya"}, 195 } 196 pref2 := []struct { 197 Key string 198 Value string 199 }{ 200 {Key: "mbmbmb", Value: "viuyenbdnya"}, 201 {Key: "mbzzaamb", Value: "viunya"}, 202 } 203 204 records, _ := cache.Read("z", store.ReadPrefix(), store.ReadSuffix()) 205 if len(records) != 3 { 206 t.Fatalf("Prefix-Suffix read for \"z\" returned %d records, expected 3", len(records)) 207 } 208 for index, record := range records { 209 // it should be sorted alphabetically 210 if pref1[index].Key != record.Key { 211 t.Errorf("Unexpected key for prefix-suffix \"z\", index %d, expected %s, got %s", index, pref1[index].Key, record.Key) 212 } 213 if pref1[index].Value != string(record.Value) { 214 t.Errorf("Unexpected value for prefix-suffix \"z\", index %d, expected %s, got %s", index, pref1[index].Value, record.Value) 215 } 216 } 217 218 records, _ = cache.Read("mb", store.ReadPrefix(), store.ReadSuffix()) 219 if len(records) != 2 { 220 t.Fatalf("Prefix-Suffix read for \"mb\" returned %d records, expected 2", len(records)) 221 } 222 for index, record := range records { 223 // it should be sorted alphabetically 224 if pref2[index].Key != record.Key { 225 t.Errorf("Unexpected key for prefix-suffix \"mb\", index %d, expected %s, got %s", index, pref2[index].Key, record.Key) 226 } 227 if pref2[index].Value != string(record.Value) { 228 t.Errorf("Unexpected value for prefix-suffix \"mb\", index %d, expected %s, got %s", index, pref2[index].Value, record.Value) 229 } 230 } 231 } 232 233 func readPrefixLimitOffset(t *testing.T, cache store.Store) { 234 pref1 := []struct { 235 Key string 236 Value string 237 }{ 238 {Key: "abaaz", Value: "v398342"}, 239 {Key: "abaya", Value: "v329487"}, 240 } 241 pref2 := []struct { 242 Key string 243 Value string 244 }{ 245 {Key: "abayakjdkj", Value: "v989898"}, 246 {Key: "abazzz", Value: "v57869nbdnya"}, 247 } 248 249 records, _ := cache.Read("aba", store.ReadPrefix(), store.ReadLimit(2)) 250 if len(records) != 2 { 251 t.Fatalf("Limit prefix read for \"aba\" returned %d records, expected 2", len(records)) 252 } 253 for index, record := range records { 254 // it should be sorted alphabetically 255 if pref1[index].Key != record.Key { 256 t.Errorf("Unexpected key for limit prefix \"aba\", index %d, expected %s, got %s", index, pref1[index].Key, record.Key) 257 } 258 if pref1[index].Value != string(record.Value) { 259 t.Errorf("Unexpected value for limit prefix \"aba\", index %d, expected %s, got %s", index, pref1[index].Value, record.Value) 260 } 261 } 262 263 records, _ = cache.Read("aba", store.ReadPrefix(), store.ReadLimit(2), store.ReadOffset(2)) 264 if len(records) != 2 { 265 t.Fatalf("Offset-limit prefix read for \"aba\" returned %d records, expected 2", len(records)) 266 } 267 for index, record := range records { 268 // it should be sorted alphabetically 269 if pref2[index].Key != record.Key { 270 t.Errorf("Unexpected key for offset-limit prefix \"aba\", index %d, expected %s, got %s", index, pref2[index].Key, record.Key) 271 } 272 if pref2[index].Value != string(record.Value) { 273 t.Errorf("Unexpected value for offset-limit prefix \"aba\", index %d, expected %s, got %s", index, pref2[index].Value, record.Value) 274 } 275 } 276 } 277 278 func readSuffixLimitOffset(t *testing.T, cache store.Store) { 279 pref1 := []struct { 280 Key string 281 Value string 282 }{ 283 {Key: "abaaz", Value: "v398342"}, 284 {Key: "zzaz", Value: "viaooouyenbdnya"}, 285 } 286 pref2 := []struct { 287 Key string 288 Value string 289 }{ 290 {Key: "abazzz", Value: "v57869nbdnya"}, 291 {Key: "zozzz", Value: "vooouyenbdnya"}, 292 } 293 294 records, _ := cache.Read("z", store.ReadSuffix(), store.ReadLimit(2)) 295 if len(records) != 2 { 296 t.Fatalf("Limit suffix read for \"z\" returned %d records, expected 2", len(records)) 297 } 298 for index, record := range records { 299 // it should be sorted alphabetically 300 if pref1[index].Key != record.Key { 301 t.Errorf("Unexpected key for limit suffix \"z\", index %d, expected %s, got %s", index, pref1[index].Key, record.Key) 302 } 303 if pref1[index].Value != string(record.Value) { 304 t.Errorf("Unexpected value for limit suffix \"z\", index %d, expected %s, got %s", index, pref1[index].Value, record.Value) 305 } 306 } 307 308 records, _ = cache.Read("z", store.ReadSuffix(), store.ReadLimit(2), store.ReadOffset(2)) 309 if len(records) != 2 { 310 t.Fatalf("Offset-limit suffix read for \"z\" returned %d records, expected 2", len(records)) 311 } 312 for index, record := range records { 313 // it should be sorted alphabetically 314 if pref2[index].Key != record.Key { 315 t.Errorf("Unexpected key for offset-limit suffix \"z\", index %d, expected %s, got %s", index, pref2[index].Key, record.Key) 316 } 317 if pref2[index].Value != string(record.Value) { 318 t.Errorf("Unexpected value for offset-limit suffix \"z\", index %d, expected %s, got %s", index, pref2[index].Value, record.Value) 319 } 320 } 321 } 322 323 func readPrefixSuffixLimitOffset(t *testing.T, cache store.Store) { 324 pref1 := []struct { 325 Key string 326 Value string 327 }{ 328 {Key: "zzaz", Value: "viaooouyenbdnya"}, 329 {Key: "zzzz", Value: "viaooouyenbdnya"}, 330 } 331 332 records, _ := cache.Read("z", store.ReadPrefix(), store.ReadSuffix(), store.ReadOffset(1), store.ReadLimit(2)) 333 if len(records) != 2 { 334 t.Fatalf("Limit suffix read for \"z\" returned %d records, expected 2", len(records)) 335 } 336 for index, record := range records { 337 // it should be sorted alphabetically 338 if pref1[index].Key != record.Key { 339 t.Errorf("Unexpected key for limit suffix \"z\", index %d, expected %s, got %s", index, pref1[index].Key, record.Key) 340 } 341 if pref1[index].Value != string(record.Value) { 342 t.Errorf("Unexpected value for limit suffix \"z\", index %d, expected %s, got %s", index, pref1[index].Value, record.Value) 343 } 344 } 345 } 346 347 func TestWriteExpiryAndRead(t *testing.T) { 348 cache := NewMemStore() 349 350 data := map[string]string{ 351 "abaya": "v329487", 352 "abaaz": "v398342", 353 "abayakjdkj": "v989898", 354 "zzaz": "viaooouyenbdnya", 355 "abazzz": "v57869nbdnya", 356 "mbmbmb": "viuyenbdnya", 357 "mbzzaamb": "viunya", 358 "zozzz": "vooouyenbdnya", 359 } 360 361 for key, value := range data { 362 record := &store.Record{ 363 Key: key, 364 Value: []byte(value), 365 Expiry: time.Second * 1000, 366 } 367 _ = cache.Write(record) 368 } 369 370 records, _ := cache.Read("zzaz") 371 if len(records) != 1 { 372 t.Fatalf("Failed read for \"zzaz\" returned %d records, expected 1", len(records)) 373 } 374 record := records[0] 375 if record.Expiry < 999*time.Second || record.Expiry > 1000*time.Second { 376 // The expiry will be adjusted on retrieval 377 t.Errorf("Abnormal expiry range: expected %d-%d, got %d", 999*time.Second, 1000*time.Second, record.Expiry) 378 } 379 } 380 381 func TestWriteExpiryWithExpiryAndRead(t *testing.T) { 382 cache := NewMemStore() 383 384 data := map[string]string{ 385 "abaya": "v329487", 386 "abaaz": "v398342", 387 "abayakjdkj": "v989898", 388 "zzaz": "viaooouyenbdnya", 389 "abazzz": "v57869nbdnya", 390 "mbmbmb": "viuyenbdnya", 391 "mbzzaamb": "viunya", 392 "zozzz": "vooouyenbdnya", 393 } 394 395 for key, value := range data { 396 record := &store.Record{ 397 Key: key, 398 Value: []byte(value), 399 Expiry: time.Second * 1000, 400 } 401 // write option will override the record data 402 _ = cache.Write(record, store.WriteExpiry(time.Now().Add(time.Hour))) 403 } 404 405 records, _ := cache.Read("zzaz") 406 if len(records) != 1 { 407 t.Fatalf("Failed read for \"zzaz\" returned %d records, expected 1", len(records)) 408 } 409 record := records[0] 410 if record.Expiry < 3599*time.Second || record.Expiry > 3600*time.Second { 411 // The expiry will be adjusted on retrieval 412 t.Errorf("Abnormal expiry range: expected %d-%d, got %d", 3599*time.Second, 3600*time.Second, record.Expiry) 413 } 414 } 415 416 func TestWriteExpiryWithTTLAndRead(t *testing.T) { 417 cache := NewMemStore() 418 419 data := map[string]string{ 420 "abaya": "v329487", 421 "abaaz": "v398342", 422 "abayakjdkj": "v989898", 423 "zzaz": "viaooouyenbdnya", 424 "abazzz": "v57869nbdnya", 425 "mbmbmb": "viuyenbdnya", 426 "mbzzaamb": "viunya", 427 "zozzz": "vooouyenbdnya", 428 } 429 430 for key, value := range data { 431 record := &store.Record{ 432 Key: key, 433 Value: []byte(value), 434 Expiry: time.Second * 1000, 435 } 436 // write option will override the record data, TTL takes precedence 437 _ = cache.Write(record, store.WriteTTL(20*time.Second), store.WriteExpiry(time.Now().Add(time.Hour))) 438 } 439 440 records, _ := cache.Read("zzaz") 441 if len(records) != 1 { 442 t.Fatalf("Failed read for \"zzaz\" returned %d records, expected 1", len(records)) 443 } 444 record := records[0] 445 if record.Expiry < 19*time.Second || record.Expiry > 20*time.Second { 446 // The expiry will be adjusted on retrieval 447 t.Errorf("Abnormal expiry range: expected %d-%d, got %d", 19*time.Second, 20*time.Second, record.Expiry) 448 } 449 } 450 451 func TestDelete(t *testing.T) { 452 cache := NewMemStore() 453 record := &store.Record{ 454 Key: "record", 455 Value: []byte("value for record"), 456 } 457 458 records, err := cache.Read("record") 459 if err != store.ErrNotFound && len(records) > 0 { 460 t.Fatal("Found key in cache but it shouldn't be there") 461 } 462 463 _ = cache.Write(record) 464 records, err = cache.Read("record") 465 if err != nil { 466 t.Fatal("Key not found in cache after inserting it") 467 } 468 if len(records) != 1 { 469 t.Fatal("Multiple keys found in cache after inserting it") 470 } 471 if records[0].Key != "record" && string(records[0].Value) != "value for record" { 472 t.Fatal("Wrong record retrieved") 473 } 474 475 err = cache.Delete("record") 476 if err != nil { 477 t.Fatal("Error deleting the record") 478 } 479 480 records, err = cache.Read("record") 481 if err != store.ErrNotFound && len(records) > 0 { 482 t.Fatal("Found key in cache but it shouldn't be there") 483 } 484 } 485 486 func TestList(t *testing.T) { 487 cache := NewMemStore() 488 data := map[string]string{ 489 "abaya": "v329487", 490 "abaaz": "v398342", 491 "abayakjdkj": "v989898", 492 "zzzz": "viaooouyenbdnya", 493 "abazzz": "v57869nbdnya", 494 "mbmbmb": "viuyenbdnya", 495 "zozzz": "vooouyenbdnya", 496 "aboyo": "v889487", 497 "zzaaaz": "v999487", 498 } 499 500 for key, value := range data { 501 record := &store.Record{ 502 Key: key, 503 Value: []byte(value), 504 } 505 _ = cache.Write(record) 506 } 507 508 t.Run("Plain", func(t *testing.T) { 509 listPlain(t, cache) 510 }) 511 t.Run("Prefix", func(t *testing.T) { 512 listPrefix(t, cache) 513 }) 514 t.Run("Suffix", func(t *testing.T) { 515 listSuffix(t, cache) 516 }) 517 t.Run("PrefixSuffix", func(t *testing.T) { 518 listPrefixSuffix(t, cache) 519 }) 520 t.Run("LimitOffset", func(t *testing.T) { 521 listLimitOffset(t, cache) 522 }) 523 t.Run("PrefixLimitOffset", func(t *testing.T) { 524 listPrefixLimitOffset(t, cache) 525 }) 526 t.Run("SuffixLimitOffset", func(t *testing.T) { 527 listSuffixLimitOffset(t, cache) 528 }) 529 t.Run("PrefixSuffixLimitOffset", func(t *testing.T) { 530 listPrefixSuffixLimitOffset(t, cache) 531 }) 532 } 533 534 func listPlain(t *testing.T, cache store.Store) { 535 keys, _ := cache.List() 536 expectedKeys := []string{"abaaz", "abaya", "abayakjdkj", "abazzz", "aboyo", "mbmbmb", "zozzz", "zzaaaz", "zzzz"} 537 if len(keys) != len(expectedKeys) { 538 t.Fatalf("Wrong number of keys, expected %d, got %d", len(expectedKeys), len(keys)) 539 } 540 541 for index, key := range keys { 542 if key != expectedKeys[index] { 543 t.Errorf("Wrong key in the list in index %d, expected %s, got %s", index, expectedKeys[index], key) 544 } 545 } 546 } 547 548 func listPrefix(t *testing.T, cache store.Store) { 549 keys, _ := cache.List(store.ListPrefix("aba")) 550 expectedKeys := []string{"abaaz", "abaya", "abayakjdkj", "abazzz"} 551 if len(keys) != len(expectedKeys) { 552 t.Fatalf("Wrong number of keys, expected %d, got %d", len(expectedKeys), len(keys)) 553 } 554 555 for index, key := range keys { 556 if key != expectedKeys[index] { 557 t.Errorf("Wrong key in the list in index %d, expected %s, got %s", index, expectedKeys[index], key) 558 } 559 } 560 } 561 562 func listSuffix(t *testing.T, cache store.Store) { 563 keys, _ := cache.List(store.ListSuffix("z")) 564 expectedKeys := []string{"zzaaaz", "abaaz", "abazzz", "zozzz", "zzzz"} 565 if len(keys) != len(expectedKeys) { 566 t.Fatalf("Wrong number of keys, expected %d, got %d", len(expectedKeys), len(keys)) 567 } 568 569 for index, key := range keys { 570 if key != expectedKeys[index] { 571 t.Errorf("Wrong key in the list in index %d, expected %s, got %s", index, expectedKeys[index], key) 572 } 573 } 574 } 575 576 func listPrefixSuffix(t *testing.T, cache store.Store) { 577 keys, _ := cache.List(store.ListPrefix("ab"), store.ListSuffix("z")) 578 expectedKeys := []string{"abaaz", "abazzz"} 579 if len(keys) != len(expectedKeys) { 580 t.Fatalf("Wrong number of keys, expected %d, got %d", len(expectedKeys), len(keys)) 581 } 582 583 for index, key := range keys { 584 if key != expectedKeys[index] { 585 t.Errorf("Wrong key in the list in index %d, expected %s, got %s", index, expectedKeys[index], key) 586 } 587 } 588 } 589 590 func listLimitOffset(t *testing.T, cache store.Store) { 591 keys, _ := cache.List(store.ListLimit(3), store.ListOffset(2)) 592 expectedKeys := []string{"abayakjdkj", "abazzz", "aboyo"} 593 if len(keys) != len(expectedKeys) { 594 t.Fatalf("Wrong number of keys, expected %d, got %d", len(expectedKeys), len(keys)) 595 } 596 597 for index, key := range keys { 598 if key != expectedKeys[index] { 599 t.Errorf("Wrong key in the list in index %d, expected %s, got %s", index, expectedKeys[index], key) 600 } 601 } 602 } 603 604 func listPrefixLimitOffset(t *testing.T, cache store.Store) { 605 keys, _ := cache.List(store.ListPrefix("aba"), store.ListLimit(2), store.ListOffset(1)) 606 expectedKeys := []string{"abaya", "abayakjdkj"} 607 if len(keys) != len(expectedKeys) { 608 t.Fatalf("Wrong number of keys, expected %d, got %d", len(expectedKeys), len(keys)) 609 } 610 611 for index, key := range keys { 612 if key != expectedKeys[index] { 613 t.Errorf("Wrong key in the list in index %d, expected %s, got %s", index, expectedKeys[index], key) 614 } 615 } 616 } 617 618 func listSuffixLimitOffset(t *testing.T, cache store.Store) { 619 keys, _ := cache.List(store.ListSuffix("z"), store.ListLimit(2), store.ListOffset(1)) 620 expectedKeys := []string{"abaaz", "abazzz"} 621 if len(keys) != len(expectedKeys) { 622 t.Fatalf("Wrong number of keys, expected %d, got %d", len(expectedKeys), len(keys)) 623 } 624 625 for index, key := range keys { 626 if key != expectedKeys[index] { 627 t.Errorf("Wrong key in the list in index %d, expected %s, got %s", index, expectedKeys[index], key) 628 } 629 } 630 } 631 632 func listPrefixSuffixLimitOffset(t *testing.T, cache store.Store) { 633 keys, _ := cache.List(store.ListPrefix("a"), store.ListSuffix("z"), store.ListLimit(2), store.ListOffset(1)) 634 expectedKeys := []string{"abazzz"} // only 2 available, and we skip the first one 635 if len(keys) != len(expectedKeys) { 636 t.Fatalf("Wrong number of keys, expected %d, got %d", len(expectedKeys), len(keys)) 637 } 638 639 for index, key := range keys { 640 if key != expectedKeys[index] { 641 t.Errorf("Wrong key in the list in index %d, expected %s, got %s", index, expectedKeys[index], key) 642 } 643 } 644 } 645 646 func TestEvictWriteUpdate(t *testing.T) { 647 cache := NewMemStore( 648 store.WithContext( 649 NewContext( 650 context.Background(), 651 map[string]interface{}{ 652 "maxCap": 3, 653 }, 654 )), 655 ) 656 657 for i := 0; i < 3; i++ { 658 v := strconv.Itoa(i) 659 record := &store.Record{ 660 Key: v, 661 Value: []byte(v), 662 } 663 _ = cache.Write(record) 664 } 665 666 // update first item 667 updatedRecord := &store.Record{ 668 Key: "0", 669 Value: []byte("zero"), 670 } 671 _ = cache.Write(updatedRecord) 672 673 // new record, to force eviction 674 newRecord := &store.Record{ 675 Key: "new", 676 Value: []byte("newNew"), 677 } 678 _ = cache.Write(newRecord) 679 680 records, _ := cache.Read("", store.ReadPrefix()) 681 if len(records) != 3 { 682 t.Fatalf("Wrong number of record returned, expected 3, got %d", len(records)) 683 } 684 685 expectedKV := []struct { 686 Key string 687 Value string 688 }{ 689 {Key: "0", Value: "zero"}, 690 {Key: "2", Value: "2"}, 691 {Key: "new", Value: "newNew"}, 692 } 693 694 for index, record := range records { 695 if record.Key != expectedKV[index].Key { 696 t.Errorf("Wrong key for index %d, expected %s, got %s", index, expectedKV[index].Key, record.Key) 697 } 698 if string(record.Value) != expectedKV[index].Value { 699 t.Errorf("Wrong value for index %d, expected %s, got %s", index, expectedKV[index].Value, string(record.Value)) 700 } 701 } 702 } 703 704 func TestEvictRead(t *testing.T) { 705 cache := NewMemStore( 706 store.WithContext( 707 NewContext( 708 context.Background(), 709 map[string]interface{}{ 710 "maxCap": 3, 711 }, 712 )), 713 ) 714 715 for i := 0; i < 3; i++ { 716 v := strconv.Itoa(i) 717 record := &store.Record{ 718 Key: v, 719 Value: []byte(v), 720 } 721 _ = cache.Write(record) 722 } 723 724 // Read first item 725 _, _ = cache.Read("0") 726 727 // new record, to force eviction 728 newRecord := &store.Record{ 729 Key: "new", 730 Value: []byte("newNew"), 731 } 732 _ = cache.Write(newRecord) 733 734 records, _ := cache.Read("", store.ReadPrefix()) 735 if len(records) != 3 { 736 t.Fatalf("Wrong number of record returned, expected 3, got %d", len(records)) 737 } 738 739 expectedKV := []struct { 740 Key string 741 Value string 742 }{ 743 {Key: "0", Value: "0"}, 744 {Key: "2", Value: "2"}, 745 {Key: "new", Value: "newNew"}, 746 } 747 748 for index, record := range records { 749 if record.Key != expectedKV[index].Key { 750 t.Errorf("Wrong key for index %d, expected %s, got %s", index, expectedKV[index].Key, record.Key) 751 } 752 if string(record.Value) != expectedKV[index].Value { 753 t.Errorf("Wrong value for index %d, expected %s, got %s", index, expectedKV[index].Value, string(record.Value)) 754 } 755 } 756 } 757 758 func TestEvictReadPrefix(t *testing.T) { 759 cache := NewMemStore( 760 store.WithContext( 761 NewContext( 762 context.Background(), 763 map[string]interface{}{ 764 "maxCap": 3, 765 }, 766 )), 767 ) 768 769 for i := 0; i < 3; i++ { 770 v := strconv.Itoa(i) 771 record := &store.Record{ 772 Key: v, 773 Value: []byte(v), 774 } 775 _ = cache.Write(record) 776 } 777 778 // Read prefix won't change evcition list 779 _, _ = cache.Read("0", store.ReadPrefix()) 780 781 // new record, to force eviction 782 newRecord := &store.Record{ 783 Key: "new", 784 Value: []byte("newNew"), 785 } 786 _ = cache.Write(newRecord) 787 788 records, _ := cache.Read("", store.ReadPrefix()) 789 if len(records) != 3 { 790 t.Fatalf("Wrong number of record returned, expected 3, got %d", len(records)) 791 } 792 793 expectedKV := []struct { 794 Key string 795 Value string 796 }{ 797 {Key: "1", Value: "1"}, 798 {Key: "2", Value: "2"}, 799 {Key: "new", Value: "newNew"}, 800 } 801 802 for index, record := range records { 803 if record.Key != expectedKV[index].Key { 804 t.Errorf("Wrong key for index %d, expected %s, got %s", index, expectedKV[index].Key, record.Key) 805 } 806 if string(record.Value) != expectedKV[index].Value { 807 t.Errorf("Wrong value for index %d, expected %s, got %s", index, expectedKV[index].Value, string(record.Value)) 808 } 809 } 810 } 811 812 func TestEvictReadSuffix(t *testing.T) { 813 cache := NewMemStore( 814 store.WithContext( 815 NewContext( 816 context.Background(), 817 map[string]interface{}{ 818 "maxCap": 3, 819 }, 820 )), 821 ) 822 823 for i := 0; i < 3; i++ { 824 v := strconv.Itoa(i) 825 record := &store.Record{ 826 Key: v, 827 Value: []byte(v), 828 } 829 _ = cache.Write(record) 830 } 831 832 // Read suffix won't change evcition list 833 _, _ = cache.Read("0", store.ReadSuffix()) 834 835 // new record, to force eviction 836 newRecord := &store.Record{ 837 Key: "new", 838 Value: []byte("newNew"), 839 } 840 _ = cache.Write(newRecord) 841 842 records, _ := cache.Read("", store.ReadPrefix()) 843 if len(records) != 3 { 844 t.Fatalf("Wrong number of record returned, expected 3, got %d", len(records)) 845 } 846 847 expectedKV := []struct { 848 Key string 849 Value string 850 }{ 851 {Key: "1", Value: "1"}, 852 {Key: "2", Value: "2"}, 853 {Key: "new", Value: "newNew"}, 854 } 855 856 for index, record := range records { 857 if record.Key != expectedKV[index].Key { 858 t.Errorf("Wrong key for index %d, expected %s, got %s", index, expectedKV[index].Key, record.Key) 859 } 860 if string(record.Value) != expectedKV[index].Value { 861 t.Errorf("Wrong value for index %d, expected %s, got %s", index, expectedKV[index].Value, string(record.Value)) 862 } 863 } 864 } 865 866 func TestEvictList(t *testing.T) { 867 cache := NewMemStore( 868 store.WithContext( 869 NewContext( 870 context.Background(), 871 map[string]interface{}{ 872 "maxCap": 3, 873 }, 874 )), 875 ) 876 877 for i := 0; i < 3; i++ { 878 v := strconv.Itoa(i) 879 record := &store.Record{ 880 Key: v, 881 Value: []byte(v), 882 } 883 _ = cache.Write(record) 884 } 885 886 // List won't change evcition list 887 _, _ = cache.List() 888 889 // new record, to force eviction 890 newRecord := &store.Record{ 891 Key: "new", 892 Value: []byte("newNew"), 893 } 894 _ = cache.Write(newRecord) 895 896 records, _ := cache.Read("", store.ReadPrefix()) 897 if len(records) != 3 { 898 t.Fatalf("Wrong number of record returned, expected 3, got %d", len(records)) 899 } 900 901 expectedKV := []struct { 902 Key string 903 Value string 904 }{ 905 {Key: "1", Value: "1"}, 906 {Key: "2", Value: "2"}, 907 {Key: "new", Value: "newNew"}, 908 } 909 910 for index, record := range records { 911 if record.Key != expectedKV[index].Key { 912 t.Errorf("Wrong key for index %d, expected %s, got %s", index, expectedKV[index].Key, record.Key) 913 } 914 if string(record.Value) != expectedKV[index].Value { 915 t.Errorf("Wrong value for index %d, expected %s, got %s", index, expectedKV[index].Value, string(record.Value)) 916 } 917 } 918 } 919 920 func TestExpireReadPrefix(t *testing.T) { 921 cache := NewMemStore() 922 923 record := &store.Record{} 924 for i := 0; i < 20; i++ { 925 v := strconv.Itoa(i) 926 record.Key = v 927 record.Value = []byte(v) 928 if i%2 == 0 { 929 record.Expiry = time.Duration(i) * time.Minute 930 } else { 931 record.Expiry = time.Duration(-i) * time.Minute 932 } 933 _ = cache.Write(record) 934 } 935 936 records, _ := cache.Read("", store.ReadPrefix()) 937 if len(records) != 10 { 938 t.Fatalf("Wrong number of records, expected 10, got %d", len(records)) 939 } 940 941 var expKeys []string 942 for i := 0; i < 20; i++ { 943 if i%2 == 0 { 944 expKeys = append(expKeys, strconv.Itoa(i)) 945 } 946 } 947 sort.Strings(expKeys) 948 949 expKeyIndex := 0 950 for _, record := range records { 951 if record.Key != expKeys[expKeyIndex] { 952 t.Fatalf("Wrong expected key, expected %s, got %s", expKeys[expKeyIndex], record.Key) 953 } 954 expKeyIndex++ 955 } 956 } 957 958 func TestExpireReadSuffix(t *testing.T) { 959 cache := NewMemStore() 960 961 record := &store.Record{} 962 for i := 0; i < 20; i++ { 963 v := strconv.Itoa(i) 964 record.Key = v 965 record.Value = []byte(v) 966 if i%2 == 0 { 967 record.Expiry = time.Duration(i) * time.Minute 968 } else { 969 record.Expiry = time.Duration(-i) * time.Minute 970 } 971 _ = cache.Write(record) 972 } 973 974 records, _ := cache.Read("", store.ReadSuffix()) 975 if len(records) != 10 { 976 t.Fatalf("Wrong number of records, expected 10, got %d", len(records)) 977 } 978 979 var expKeys []string 980 for i := 0; i < 20; i++ { 981 if i%2 == 0 { 982 expKeys = append(expKeys, strconv.Itoa(i)) 983 } 984 } 985 sort.Slice(expKeys, func(i, j int) bool { 986 return reverseString(expKeys[i]) < reverseString(expKeys[j]) 987 }) 988 989 expKeyIndex := 0 990 for _, record := range records { 991 if record.Key != expKeys[expKeyIndex] { 992 t.Fatalf("Wrong expected key, expected %s, got %s", expKeys[expKeyIndex], record.Key) 993 } 994 expKeyIndex++ 995 } 996 } 997 998 func TestExpireList(t *testing.T) { 999 cache := NewMemStore() 1000 1001 record := &store.Record{} 1002 for i := 0; i < 20; i++ { 1003 v := strconv.Itoa(i) 1004 record.Key = v 1005 record.Value = []byte(v) 1006 if i%2 == 0 { 1007 record.Expiry = time.Duration(i) * time.Minute 1008 } else { 1009 record.Expiry = time.Duration(-i) * time.Minute 1010 } 1011 _ = cache.Write(record) 1012 } 1013 1014 keys, _ := cache.List() 1015 if len(keys) != 10 { 1016 t.Fatalf("Wrong number of records, expected 10, got %d", len(keys)) 1017 } 1018 1019 var expKeys []string 1020 for i := 0; i < 20; i++ { 1021 if i%2 == 0 { 1022 expKeys = append(expKeys, strconv.Itoa(i)) 1023 } 1024 } 1025 sort.Strings(expKeys) 1026 1027 expKeyIndex := 0 1028 for _, key := range keys { 1029 if key != expKeys[expKeyIndex] { 1030 t.Fatalf("Wrong expected key, expected %s, got %s", expKeys[expKeyIndex], key) 1031 } 1032 expKeyIndex++ 1033 } 1034 } 1035 1036 func TestExpireListPrefix(t *testing.T) { 1037 cache := NewMemStore() 1038 1039 record := &store.Record{} 1040 for i := 0; i < 20; i++ { 1041 v := strconv.Itoa(i) 1042 record.Key = v 1043 record.Value = []byte(v) 1044 if i%2 == 0 { 1045 record.Expiry = time.Duration(i) * time.Minute 1046 } else { 1047 record.Expiry = time.Duration(-i) * time.Minute 1048 } 1049 _ = cache.Write(record) 1050 } 1051 1052 keys, _ := cache.List(store.ListPrefix("1")) 1053 if len(keys) != 5 { 1054 t.Fatalf("Wrong number of records, expected 5, got %d", len(keys)) 1055 } 1056 1057 var expKeys []string 1058 for i := 0; i < 20; i++ { 1059 v := strconv.Itoa(i) 1060 if i%2 == 0 && strings.HasPrefix(v, "1") { 1061 expKeys = append(expKeys, v) 1062 } 1063 } 1064 sort.Strings(expKeys) 1065 1066 expKeyIndex := 0 1067 for _, key := range keys { 1068 if key != expKeys[expKeyIndex] { 1069 t.Fatalf("Wrong expected key, expected %s, got %s", expKeys[expKeyIndex], key) 1070 } 1071 expKeyIndex++ 1072 } 1073 } 1074 1075 func TestExpireListSuffix(t *testing.T) { 1076 cache := NewMemStore() 1077 1078 record := &store.Record{} 1079 for i := 0; i < 20; i++ { 1080 v := strconv.Itoa(i) 1081 record.Key = v 1082 record.Value = []byte(v) 1083 if i%2 == 0 { 1084 record.Expiry = time.Duration(i) * time.Minute 1085 } else { 1086 record.Expiry = time.Duration(-i) * time.Minute 1087 } 1088 _ = cache.Write(record) 1089 } 1090 1091 keys, _ := cache.List(store.ListSuffix("8")) 1092 if len(keys) != 2 { 1093 t.Fatalf("Wrong number of records, expected 2, got %d", len(keys)) 1094 } 1095 1096 var expKeys []string 1097 for i := 0; i < 20; i++ { 1098 v := strconv.Itoa(i) 1099 if i%2 == 0 && strings.HasSuffix(v, "8") { 1100 expKeys = append(expKeys, v) 1101 } 1102 } 1103 sort.Slice(expKeys, func(i, j int) bool { 1104 return reverseString(expKeys[i]) < reverseString(expKeys[j]) 1105 }) 1106 1107 expKeyIndex := 0 1108 for _, key := range keys { 1109 if key != expKeys[expKeyIndex] { 1110 t.Fatalf("Wrong expected key, expected %s, got %s", expKeys[expKeyIndex], key) 1111 } 1112 expKeyIndex++ 1113 } 1114 } 1115 1116 func TestConcurrentWrite(t *testing.T) { 1117 nThreads := []int{3, 10, 50} 1118 1119 for _, threads := range nThreads { 1120 t.Run("T"+strconv.Itoa(threads), func(t *testing.T) { 1121 cache := NewMemStore( 1122 store.WithContext( 1123 NewContext( 1124 context.Background(), 1125 map[string]interface{}{ 1126 "maxCap": 50000, 1127 }, 1128 )), 1129 ) 1130 1131 var wg sync.WaitGroup 1132 var index int64 1133 1134 wg.Add(threads) 1135 for i := 0; i < threads; i++ { 1136 go func(cache store.Store, ind *int64) { 1137 j := atomic.AddInt64(ind, 1) - 1 1138 for j < 100000 { 1139 v := strconv.FormatInt(j, 10) 1140 record := &store.Record{ 1141 Key: v, 1142 Value: []byte(v), 1143 } 1144 _ = cache.Write(record) 1145 j = atomic.AddInt64(ind, 1) - 1 1146 } 1147 wg.Done() 1148 }(cache, &index) 1149 } 1150 wg.Wait() 1151 1152 records, _ := cache.Read("", store.ReadPrefix()) 1153 if len(records) != 50000 { 1154 t.Fatalf("Wrong number of records, expected 50000, got %d", len(records)) 1155 } 1156 for _, record := range records { 1157 if record.Key != string(record.Value) { 1158 t.Fatalf("Wrong record found, key %s, value %s", record.Key, string(record.Value)) 1159 } 1160 } 1161 }) 1162 } 1163 } 1164 1165 func BenchmarkWrite(b *testing.B) { 1166 cacheSizes := []int{512, 1024, 10000, 50000, 1000000} 1167 1168 for _, size := range cacheSizes { 1169 cache := NewMemStore( 1170 store.WithContext( 1171 NewContext( 1172 context.Background(), 1173 map[string]interface{}{ 1174 "maxCap": size, 1175 }, 1176 )), 1177 ) 1178 record := &store.Record{} 1179 1180 b.Run("CacheSize"+strconv.Itoa(size), func(b *testing.B) { 1181 b.ResetTimer() 1182 for i := 0; i < b.N; i++ { 1183 // records will be copied, so it's safe to overwrite the previous record 1184 v := strconv.Itoa(i) 1185 record.Key = v 1186 record.Value = []byte(v) 1187 _ = cache.Write(record) 1188 } 1189 }) 1190 } 1191 } 1192 1193 func BenchmarkRead(b *testing.B) { 1194 cacheSizes := []int{512, 1024, 10000, 50000, 1000000} 1195 1196 for _, size := range cacheSizes { 1197 cache := NewMemStore( 1198 store.WithContext( 1199 NewContext( 1200 context.Background(), 1201 map[string]interface{}{ 1202 "maxCap": size, 1203 }, 1204 )), 1205 ) 1206 record := &store.Record{} 1207 1208 for i := 0; i < size; i++ { 1209 // records will be copied, so it's safe to overwrite the previous record 1210 v := strconv.Itoa(i) 1211 record.Key = v 1212 record.Value = []byte(v) 1213 _ = cache.Write(record) 1214 } 1215 b.Run("CacheSize"+strconv.Itoa(size), func(b *testing.B) { 1216 b.ResetTimer() 1217 for i := 0; i < b.N; i++ { 1218 v := strconv.Itoa(i) 1219 _, _ = cache.Read(v) 1220 } 1221 }) 1222 } 1223 } 1224 1225 func BenchmarkWriteMedKey(b *testing.B) { 1226 cacheSizes := []int{512, 1024, 10000, 50000, 1000000} 1227 1228 h := fnv.New128() 1229 for _, size := range cacheSizes { 1230 cache := NewMemStore( 1231 store.WithContext( 1232 NewContext( 1233 context.Background(), 1234 map[string]interface{}{ 1235 "maxCap": size, 1236 }, 1237 )), 1238 ) 1239 record := &store.Record{} 1240 1241 b.Run("CacheSize"+strconv.Itoa(size), func(b *testing.B) { 1242 b.ResetTimer() 1243 for i := 0; i < b.N; i++ { 1244 h.Reset() 1245 v := strconv.Itoa(i) 1246 bys := []byte(v) 1247 h.Write(bys) 1248 // records will be copied, so it's safe to overwrite the previous record 1249 record.Key = hex.EncodeToString(h.Sum(nil)) 1250 record.Value = bys 1251 _ = cache.Write(record) 1252 } 1253 }) 1254 } 1255 } 1256 1257 func BenchmarkReadMedKey(b *testing.B) { 1258 cacheSizes := []int{512, 1024, 10000, 50000, 1000000} 1259 1260 h := fnv.New128() 1261 for _, size := range cacheSizes { 1262 cache := NewMemStore( 1263 store.WithContext( 1264 NewContext( 1265 context.Background(), 1266 map[string]interface{}{ 1267 "maxCap": size, 1268 }, 1269 )), 1270 ) 1271 record := &store.Record{} 1272 1273 for i := 0; i < size; i++ { 1274 h.Reset() 1275 v := strconv.Itoa(i) 1276 bys := []byte(v) 1277 h.Write(bys) 1278 // records will be copied, so it's safe to overwrite the previous record 1279 record.Key = hex.EncodeToString(h.Sum(nil)) 1280 record.Value = bys 1281 _ = cache.Write(record) 1282 } 1283 b.Run("CacheSize"+strconv.Itoa(size), func(b *testing.B) { 1284 b.ResetTimer() 1285 for i := 0; i < b.N; i++ { 1286 h.Reset() 1287 v := strconv.Itoa(i) 1288 bys := []byte(v) 1289 h.Write(bys) 1290 _, _ = cache.Read(hex.EncodeToString(h.Sum(nil))) 1291 } 1292 }) 1293 } 1294 } 1295 1296 func BenchmarkReadMedKeyPrefix(b *testing.B) { 1297 cacheSizes := []int{512, 1024, 10000, 50000, 1000000} 1298 1299 h := fnv.New128() 1300 for _, size := range cacheSizes { 1301 cache := NewMemStore( 1302 store.WithContext( 1303 NewContext( 1304 context.Background(), 1305 map[string]interface{}{ 1306 "maxCap": size, 1307 }, 1308 )), 1309 ) 1310 record := &store.Record{} 1311 1312 for i := 0; i < size; i++ { 1313 h.Reset() 1314 v := strconv.Itoa(i) 1315 bys := []byte(v) 1316 h.Write(bys) 1317 // records will be copied, so it's safe to overwrite the previous record 1318 record.Key = hex.EncodeToString(h.Sum(nil)) 1319 record.Value = bys 1320 _ = cache.Write(record) 1321 } 1322 b.Run("CacheSize"+strconv.Itoa(size), func(b *testing.B) { 1323 b.ResetTimer() 1324 for i := 0; i < b.N; i++ { 1325 h.Reset() 1326 v := strconv.Itoa(i) 1327 bys := []byte(v) 1328 h.Write(bys) 1329 _, _ = cache.Read(hex.EncodeToString(h.Sum(nil))[:10], store.ReadPrefix(), store.ReadLimit(50)) 1330 } 1331 }) 1332 } 1333 } 1334 1335 func BenchmarkReadMedKeySuffix(b *testing.B) { 1336 cacheSizes := []int{512, 1024, 10000, 50000, 1000000} 1337 1338 h := fnv.New128() 1339 for _, size := range cacheSizes { 1340 cache := NewMemStore( 1341 store.WithContext( 1342 NewContext( 1343 context.Background(), 1344 map[string]interface{}{ 1345 "maxCap": size, 1346 }, 1347 )), 1348 ) 1349 record := &store.Record{} 1350 1351 for i := 0; i < size; i++ { 1352 h.Reset() 1353 v := strconv.Itoa(i) 1354 bys := []byte(v) 1355 h.Write(bys) 1356 // records will be copied, so it's safe to overwrite the previous record 1357 record.Key = hex.EncodeToString(h.Sum(nil)) 1358 record.Value = bys 1359 _ = cache.Write(record) 1360 } 1361 b.Run("CacheSize"+strconv.Itoa(size), func(b *testing.B) { 1362 b.ResetTimer() 1363 for i := 0; i < b.N; i++ { 1364 h.Reset() 1365 v := strconv.Itoa(i) 1366 bys := []byte(v) 1367 h.Write(bys) 1368 _, _ = cache.Read(hex.EncodeToString(h.Sum(nil))[23:], store.ReadSuffix(), store.ReadLimit(50)) 1369 } 1370 }) 1371 } 1372 } 1373 1374 func concurrentStoreBench(b *testing.B, threads int) { 1375 benchTest := map[string]int{ 1376 "DefCap": 512, 1377 "LimCap": 3, 1378 "BigCap": 1000000, 1379 } 1380 for testname, size := range benchTest { 1381 b.Run(testname, func(b *testing.B) { 1382 cache := NewMemStore( 1383 store.WithContext( 1384 NewContext( 1385 context.Background(), 1386 map[string]interface{}{ 1387 "maxCap": size, 1388 }, 1389 )), 1390 ) 1391 1392 b.SetParallelism(threads) 1393 b.ResetTimer() 1394 b.RunParallel(func(pb *testing.PB) { 1395 h := fnv.New128() 1396 record := &store.Record{} 1397 for pb.Next() { 1398 h.Reset() 1399 v := strconv.Itoa(rand.Int()) //nolint:gosec 1400 bys := []byte(v) 1401 h.Write(bys) 1402 // records will be copied, so it's safe to overwrite the previous record 1403 record.Key = hex.EncodeToString(h.Sum(nil)) 1404 record.Value = bys 1405 _ = cache.Write(record) 1406 } 1407 }) 1408 }) 1409 } 1410 } 1411 1412 func concurrentRetrieveBench(b *testing.B, threads int) { 1413 benchTest := map[string]int{ 1414 "DefCap": 512, 1415 "LimCap": 3, 1416 "BigCap": 1000000, 1417 } 1418 for testname, size := range benchTest { 1419 b.Run(testname, func(b *testing.B) { 1420 cache := NewMemStore( 1421 store.WithContext( 1422 NewContext( 1423 context.Background(), 1424 map[string]interface{}{ 1425 "maxCap": size, 1426 }, 1427 )), 1428 ) 1429 1430 record := &store.Record{} 1431 for i := 0; i < size; i++ { 1432 v := strconv.Itoa(i) 1433 record.Key = v 1434 record.Value = []byte(v) 1435 _ = cache.Write(record) 1436 } 1437 1438 b.SetParallelism(threads) 1439 b.ResetTimer() 1440 b.RunParallel(func(pb *testing.PB) { 1441 for pb.Next() { 1442 v := strconv.Itoa(rand.Intn(size * 2)) //nolint:gosec 1443 _, _ = cache.Read(v) 1444 } 1445 }) 1446 }) 1447 } 1448 } 1449 1450 func concurrentRemoveBench(b *testing.B, threads int) { 1451 benchTest := map[string]int{ 1452 "DefCap": 512, 1453 "LimCap": 3, 1454 "BigCap": 1000000, 1455 } 1456 for testname, size := range benchTest { 1457 b.Run(testname, func(b *testing.B) { 1458 cache := NewMemStore( 1459 store.WithContext( 1460 NewContext( 1461 context.Background(), 1462 map[string]interface{}{ 1463 "maxCap": size, 1464 }, 1465 )), 1466 ) 1467 1468 record := &store.Record{} 1469 for i := 0; i < size; i++ { 1470 v := strconv.Itoa(i) 1471 record.Key = v 1472 record.Value = []byte(v) 1473 _ = cache.Write(record) 1474 } 1475 1476 b.SetParallelism(threads) 1477 b.ResetTimer() 1478 b.RunParallel(func(pb *testing.PB) { 1479 record := &store.Record{} 1480 for pb.Next() { 1481 v := strconv.Itoa(rand.Intn(size * 2)) //nolint:gosec 1482 _ = cache.Delete(v) 1483 record.Key = v 1484 record.Value = []byte(v) 1485 _ = cache.Write(record) 1486 } 1487 }) 1488 }) 1489 } 1490 } 1491 1492 func BenchmarkConcurrent(b *testing.B) { 1493 threads := []int{3, 10, 50} 1494 for _, nThreads := range threads { 1495 nt := strconv.Itoa(nThreads) 1496 b.Run("StoreT"+nt, func(b *testing.B) { 1497 concurrentStoreBench(b, nThreads) 1498 }) 1499 b.Run("RetrieveT"+nt, func(b *testing.B) { 1500 concurrentRetrieveBench(b, nThreads) 1501 }) 1502 b.Run("RemoveT"+nt, func(b *testing.B) { 1503 concurrentRemoveBench(b, nThreads) 1504 }) 1505 } 1506 }