github.com/xgzlucario/GigaCache@v0.0.0-20240508025442-54204e9c8a6b/bucket_test.go (about)

     1  package cache
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  )
     9  
    10  var (
    11  	nilBytes []byte
    12  )
    13  
    14  func getBucket(options ...Options) *bucket {
    15  	var opt Options
    16  	if len(options) > 0 {
    17  		opt = options[0]
    18  	} else {
    19  		opt = DefaultOptions
    20  		opt.EvictInterval = 1
    21  	}
    22  	m := newBucket(opt)
    23  
    24  	for i := 0; i < 100; i++ {
    25  		k, v := genKV(i)
    26  		key := Key(i / 10)
    27  		m.set(key, []byte(k), v, 0)
    28  	}
    29  	return m
    30  }
    31  
    32  func TestBucket(t *testing.T) {
    33  	assert := assert.New(t)
    34  
    35  	testHashFn := func(s string) uint64 {
    36  		return 0
    37  	}
    38  
    39  	for i, hashFn := range []HashFn{MemHash, testHashFn} {
    40  		opt := DefaultOptions
    41  		opt.HashFn = hashFn
    42  
    43  		m := getBucket(opt)
    44  		scanCheck := func() {
    45  			var count int
    46  			m.scan(func(key, val []byte, ttl int64) bool {
    47  				count++
    48  				return true
    49  			})
    50  			assert.Equal(100, count)
    51  		}
    52  
    53  		assert.Equal(10, len(m.index))
    54  		assert.Equal(90, len(m.cmap))
    55  
    56  		m.eliminate()
    57  		scanCheck()
    58  		m.migrate()
    59  
    60  		if i == 0 {
    61  			assert.Equal(100, len(m.index)) // migrate use memhash and migrate all keys to index.
    62  			assert.Equal(0, len(m.cmap))
    63  		} else {
    64  			assert.Equal(10, len(m.index))
    65  			assert.Equal(90, len(m.cmap))
    66  		}
    67  		scanCheck()
    68  	}
    69  }
    70  
    71  func TestBucketExpired(t *testing.T) {
    72  	assert := assert.New(t)
    73  
    74  	t.Run("1", func(t *testing.T) {
    75  		m := getBucket()
    76  		ttl := time.Now().Add(time.Second).UnixNano()
    77  		for i := 0; i < 100; i++ {
    78  			k, v := genKV(i)
    79  			key := Key(i / 10)
    80  			// set
    81  			m.set(key, []byte(k), v, ttl)
    82  			// get
    83  			val, ts, ok := m.get(k, key)
    84  			assert.True(ok)
    85  			assert.Equal(val, v)
    86  			assert.Equal(ts, ttl/timeCarry*timeCarry)
    87  		}
    88  
    89  		assert.Equal(90, len(m.cmap))
    90  		assert.Equal(10, len(m.index))
    91  
    92  		// expired
    93  		time.Sleep(time.Second * 2)
    94  
    95  		var count int
    96  		m.scan(func(key, val []byte, ttl int64) (next bool) {
    97  			count++
    98  			return true
    99  		})
   100  		assert.Equal(count, 0)
   101  
   102  		m.eliminate()
   103  		assert.Equal(0, len(m.cmap))
   104  		assert.Equal(0, len(m.index))
   105  	})
   106  }
   107  
   108  func TestBucketMigrate(t *testing.T) {
   109  	assert := assert.New(t)
   110  
   111  	m := getBucket()
   112  	ttl := time.Now().Add(time.Second).UnixNano()
   113  	for i := 0; i < 100; i++ {
   114  		k, v := genKV(i)
   115  		key := Key(i / 10)
   116  		// setTTL
   117  		ok := m.setTTL(key, k, ttl)
   118  		assert.True(ok)
   119  		// get
   120  		val, ts, ok := m.get(k, key)
   121  		assert.True(ok)
   122  		assert.Equal(val, v)
   123  		assert.Equal(ts, ttl/timeCarry*timeCarry)
   124  	}
   125  
   126  	time.Sleep(time.Second * 2)
   127  	assert.Equal(90, len(m.cmap))
   128  	assert.Equal(10, len(m.index))
   129  	m.migrate()
   130  	assert.Equal(0, len(m.cmap))
   131  	assert.Equal(0, len(m.index))
   132  }
   133  
   134  func TestBucketRemove(t *testing.T) {
   135  	assert := assert.New(t)
   136  
   137  	t.Run("remove", func(t *testing.T) {
   138  		m := getBucket()
   139  		for i := 0; i < 100; i++ {
   140  			k, _ := genKV(i)
   141  			key := Key(i / 10)
   142  			// remove
   143  			m.remove(key, k)
   144  			// get
   145  			val, ts, ok := m.get(k, key)
   146  			assert.False(ok)
   147  			assert.Equal(val, nilBytes)
   148  			assert.Equal(ts, int64(0))
   149  		}
   150  		assert.Equal(0, len(m.cmap))
   151  		assert.Equal(0, len(m.index))
   152  	})
   153  
   154  	t.Run("remove-ttl", func(t *testing.T) {
   155  		options := DefaultOptions
   156  		options.EvictInterval = 1
   157  		m := newBucket(options)
   158  
   159  		ts1 := time.Now().Add(time.Hour).UnixNano()
   160  		for i := 0; i < 100; i++ {
   161  			k, v := genKV(i)
   162  			key := Key(i / 10)
   163  			m.set(key, []byte(k), v, ts1)
   164  		}
   165  		ts2 := time.Now().UnixNano()
   166  		for i := 100; i < 200; i++ {
   167  			k, v := genKV(i)
   168  			key := Key(i / 10)
   169  			m.set(key, []byte(k), v, ts2)
   170  		}
   171  
   172  		time.Sleep(time.Second)
   173  
   174  		// remove
   175  		for i := 0; i < 100; i++ {
   176  			k, _ := genKV(i)
   177  			key := Key(i / 10)
   178  			ok := m.remove(key, k)
   179  			assert.True(ok)
   180  		}
   181  		for i := 100; i < 200; i++ {
   182  			k, _ := genKV(i)
   183  			key := Key(i / 10)
   184  			ok := m.remove(key, k)
   185  			assert.False(ok) // false because of expired.
   186  		}
   187  	})
   188  }
   189  
   190  func TestBucketScan(t *testing.T) {
   191  	assert := assert.New(t)
   192  	m := getBucket()
   193  
   194  	t.Run("scan", func(t *testing.T) {
   195  		var count int
   196  		m.scan(func(key, val []byte, _ int64) bool {
   197  			assert.Equal(key, val)
   198  			count++
   199  			return true
   200  		})
   201  		assert.Equal(100, count)
   202  	})
   203  
   204  	t.Run("scan-break", func(t *testing.T) {
   205  		var count int
   206  		m.scan(func(_, _ []byte, _ int64) bool {
   207  			count++
   208  			return count < 50
   209  		})
   210  		assert.Equal(50, count)
   211  	})
   212  }