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  }