github.com/jxskiss/gopkg@v0.17.3/lru/cache_test.go (about)

     1  package lru
     2  
     3  import (
     4  	"math/rand"
     5  	"runtime"
     6  	"testing"
     7  	"time"
     8  )
     9  
    10  func createFilledCache(ttl time.Duration) *Cache {
    11  	c := NewCache(1000)
    12  	for i := 0; i < 1000; i++ {
    13  		key := int64(rand.Intn(5000))
    14  		c.Set(key, key, ttl)
    15  	}
    16  	return c
    17  }
    18  
    19  func createRandInts(size int) []int64 {
    20  	s := make([]int64, size)
    21  	for i := 0; i < size; i++ {
    22  		s[i] = rand.Int63n(5000)
    23  	}
    24  	return s
    25  }
    26  
    27  func TestBasicEviction(t *testing.T) {
    28  	t.Parallel()
    29  	c := NewCache(3)
    30  	if _, ok, _ := c.Get("a"); ok {
    31  		t.Error("a")
    32  	}
    33  
    34  	c.Set("b", "vb", 2*time.Second)
    35  	c.Set("a", "va", time.Second)
    36  	c.Set("c", "vc", 3*time.Second)
    37  
    38  	if v, _, _ := c.Get("a"); v != "va" {
    39  		t.Error("va")
    40  	}
    41  	if v, _, _ := c.Get("b"); v != "vb" {
    42  		t.Error("vb")
    43  	}
    44  	if v, _, _ := c.Get("c"); v != "vc" {
    45  		t.Error("vc")
    46  	}
    47  
    48  	c.Set("d", "vd", time.Second)
    49  	if _, ok, _ := c.Get("a"); ok {
    50  		t.Error("expecting element A to be evicted")
    51  	}
    52  	c.Set("e", "ve", time.Second)
    53  	if _, ok, _ := c.Get("b"); ok {
    54  		t.Error("expecting element B to be evicted")
    55  	}
    56  	c.Set("f", "vf", time.Second)
    57  	if _, ok, _ := c.Get("c"); ok {
    58  		t.Error("expecting element C to be evicted")
    59  	}
    60  
    61  	if v, _, _ := c.Get("d"); v != "vd" {
    62  		t.Error("expecting element D to not be evicted")
    63  	}
    64  
    65  	// e, f, d, [g]
    66  	c.Set("g", "vg", time.Second)
    67  	if _, ok, _ := c.Get("E"); ok {
    68  		t.Error("expecting element E to be evicted")
    69  	}
    70  
    71  	if l := c.Len(); l != 3 {
    72  		t.Errorf("invalid length, want= 3, got= %v", l)
    73  	}
    74  
    75  	c.Del("missing")
    76  	c.Del("g")
    77  	if l := c.Len(); l != 2 {
    78  		t.Errorf("invalid length, want= 2, got= %v", l)
    79  	}
    80  
    81  	// f, d, [h, i]
    82  	c.MSet(map[string]string{"h": "vh", "i": "vi"}, time.Second)
    83  	if _, ok, _ := c.Get("e"); ok {
    84  		t.Error("expecting element E to be evicted")
    85  	}
    86  	if _, ok, _ := c.Get("f"); ok {
    87  		t.Error("expecting element F to be evicted")
    88  	}
    89  	if v, _, _ := c.Get("d"); v != "vd" {
    90  		t.Error("expecting element D to not be evicted")
    91  	}
    92  
    93  	// h/i, i/h, d, [h, i]
    94  	m := c.MGetString("h", "i")
    95  	if m["h"] != "vh" {
    96  		t.Error("expecting MSetString and MGetString to work")
    97  	}
    98  	if m["i"] != "vi" {
    99  		t.Error("expecting MSetString and MGetString to work")
   100  	}
   101  
   102  	if v, _, _ := c.GetQuiet("d"); v != "vd" {
   103  		t.Error("expecting GetQuiet to work")
   104  	}
   105  
   106  	if v, _ := c.GetNotStale("d"); v != "vd" {
   107  		t.Error("expecting GetNotStale to work")
   108  	}
   109  }
   110  
   111  func TestConcurrentGet(t *testing.T) {
   112  	t.Parallel()
   113  	c := createFilledCache(time.Second)
   114  	s := createRandInts(50000)
   115  
   116  	done := make(chan bool)
   117  	worker := func() {
   118  		for i := 0; i < 5000; i++ {
   119  			key := s[i]
   120  			v, exists, _ := c.Get(key)
   121  			if exists && v.(int64) != key {
   122  				t.Errorf("value not match: want= %v, got= %v", key, v)
   123  			}
   124  		}
   125  		done <- true
   126  	}
   127  	workers := 4
   128  	for i := 0; i < workers; i++ {
   129  		go worker()
   130  	}
   131  	for i := 0; i < workers; i++ {
   132  		_ = <-done
   133  	}
   134  }
   135  
   136  func TestConcurrentSet(t *testing.T) {
   137  	t.Parallel()
   138  	c := createFilledCache(time.Second)
   139  	s := createRandInts(5000)
   140  
   141  	done := make(chan bool)
   142  	worker := func() {
   143  		ttl := 4 * time.Second
   144  		for i := 0; i < 5000; i++ {
   145  			key := s[i]
   146  			c.Set(key, key, ttl)
   147  		}
   148  		done <- true
   149  	}
   150  	workers := 4
   151  	for i := 0; i < workers; i++ {
   152  		go worker()
   153  	}
   154  	for i := 0; i < workers; i++ {
   155  		_ = <-done
   156  	}
   157  }
   158  
   159  func TestConcurrentGetSet(t *testing.T) {
   160  	t.Parallel()
   161  	c := createFilledCache(time.Second)
   162  	s := createRandInts(5000)
   163  
   164  	done := make(chan bool)
   165  	getWorker := func() {
   166  		for i := 0; i < 5000; i++ {
   167  			key := s[i]
   168  			v, exists, _ := c.Get(key)
   169  			if exists && v.(int64) != key {
   170  				t.Errorf("value not match: want= %v, got= %v", key, v)
   171  			}
   172  		}
   173  		done <- true
   174  	}
   175  	setWorker := func() {
   176  		ttl := 4 * time.Second
   177  		for i := 0; i < 5000; i++ {
   178  			key := s[i]
   179  			c.Set(key, key, ttl)
   180  		}
   181  		done <- true
   182  	}
   183  	workers := 4
   184  	for i := 0; i < workers; i++ {
   185  		go getWorker()
   186  		go setWorker()
   187  	}
   188  	for i := 0; i < workers*2; i++ {
   189  		_ = <-done
   190  	}
   191  }
   192  
   193  func BenchmarkConcurrentGetLRUCache(bb *testing.B) {
   194  	c := createFilledCache(time.Second)
   195  	s := createRandInts(5000)
   196  
   197  	bb.ReportAllocs()
   198  	bb.ResetTimer()
   199  	cpu := runtime.GOMAXPROCS(0)
   200  	ch := make(chan bool)
   201  	worker := func() {
   202  		for i := 0; i < bb.N/cpu; i++ {
   203  			c.Get(s[i%5000])
   204  		}
   205  		ch <- true
   206  	}
   207  	for i := 0; i < cpu; i++ {
   208  		go worker()
   209  	}
   210  	for i := 0; i < cpu; i++ {
   211  		_ = <-ch
   212  	}
   213  }
   214  
   215  func BenchmarkConcurrentSetLRUCache(bb *testing.B) {
   216  	c := createFilledCache(time.Second)
   217  	s := createRandInts(5000)
   218  
   219  	bb.ReportAllocs()
   220  	bb.ResetTimer()
   221  	cpu := runtime.GOMAXPROCS(0)
   222  	ch := make(chan bool)
   223  	worker := func() {
   224  		ttl := 4 * time.Second
   225  		for i := 0; i < bb.N/cpu; i++ {
   226  			key := s[i%5000]
   227  			c.Set(key, key, ttl)
   228  		}
   229  		ch <- true
   230  	}
   231  	for i := 0; i < cpu; i++ {
   232  		go worker()
   233  	}
   234  	for i := 0; i < cpu; i++ {
   235  		_ = <-ch
   236  	}
   237  }
   238  
   239  // No expiry
   240  func BenchmarkConcurrentSetNXLRUCache(bb *testing.B) {
   241  	c := createFilledCache(time.Second)
   242  	s := createRandInts(5000)
   243  
   244  	bb.ReportAllocs()
   245  	bb.ResetTimer()
   246  	cpu := runtime.GOMAXPROCS(0)
   247  	ch := make(chan bool)
   248  	worker := func() {
   249  		for i := 0; i < bb.N/cpu; i++ {
   250  			key := s[i%5000]
   251  			c.Set(key, key, 0)
   252  		}
   253  		ch <- true
   254  	}
   255  	for i := 0; i < cpu; i++ {
   256  		go worker()
   257  	}
   258  	for i := 0; i < cpu; i++ {
   259  		_ = <-ch
   260  	}
   261  }