github.com/pingcap/badger@v1.5.1-0.20230103063557-828f39b09b6d/table/memtable/skl_test.go (about)

     1  /*
     2   * Copyright 2017 Dgraph Labs, Inc. and Contributors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package memtable
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/binary"
    22  	"fmt"
    23  	"math/rand"
    24  	"sort"
    25  	"sync"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/pingcap/badger/cache/z"
    30  	"github.com/pingcap/badger/y"
    31  	"github.com/stretchr/testify/require"
    32  )
    33  
    34  const arenaSize = 1 << 20
    35  
    36  func newValue(v int) []byte {
    37  	return []byte(fmt.Sprintf("%05d", v))
    38  }
    39  
    40  // length iterates over skiplist to give exact size.
    41  func length(s *skiplist) int {
    42  	x := s.getNext(s.head, 0)
    43  	count := 0
    44  	for x != nil {
    45  		count++
    46  		x = s.getNext(x, 0)
    47  	}
    48  	return count
    49  }
    50  
    51  func TestEmpty(t *testing.T) {
    52  	key := []byte("aaa")
    53  	l := newSkiplist(arenaSize)
    54  
    55  	v := l.Get(key, 1)
    56  	require.True(t, v.Value == nil) // Cannot use require.Nil for unsafe.Pointer nil.
    57  
    58  	for _, less := range []bool{true, false} {
    59  		for _, allowEqual := range []bool{true, false} {
    60  			n, found := l.findNear(key, less, allowEqual)
    61  			require.Nil(t, n)
    62  			require.False(t, found)
    63  		}
    64  	}
    65  
    66  	it := l.NewIterator()
    67  	require.False(t, it.Valid())
    68  
    69  	it.SeekToFirst()
    70  	require.False(t, it.Valid())
    71  
    72  	it.SeekToLast()
    73  	require.False(t, it.Valid())
    74  
    75  	it.Seek(key)
    76  	require.False(t, it.Valid())
    77  	it.Close()
    78  }
    79  
    80  // TestBasic tests single-threaded inserts and updates and gets.
    81  func TestBasic(t *testing.T) {
    82  	l := newSkiplist(arenaSize)
    83  	val1 := newValue(42)
    84  	val2 := newValue(52)
    85  	val3 := newValue(62)
    86  	val4 := newValue(72)
    87  
    88  	// Try inserting values.
    89  	// Somehow require.Nil doesn't work when checking for unsafe.Pointer(nil).
    90  	l.Put([]byte("key1"), y.ValueStruct{Value: val1, Meta: 55, UserMeta: []byte{0}})
    91  	l.Put([]byte("key2"), y.ValueStruct{Value: val2, Meta: 56, UserMeta: []byte{0}, Version: 2})
    92  	l.Put([]byte("key3"), y.ValueStruct{Value: val3, Meta: 57, UserMeta: []byte{0}})
    93  
    94  	v := l.Get([]byte("key"), 0)
    95  	require.True(t, v.Value == nil)
    96  
    97  	v = l.Get([]byte("key1"), 0)
    98  	require.True(t, v.Value != nil)
    99  	require.EqualValues(t, "00042", string(v.Value))
   100  	require.EqualValues(t, 55, v.Meta)
   101  
   102  	v = l.Get([]byte("key2"), 0)
   103  	require.True(t, v.Value == nil)
   104  
   105  	v = l.Get([]byte("key3"), 0)
   106  	require.True(t, v.Value != nil)
   107  	require.EqualValues(t, "00062", string(v.Value))
   108  	require.EqualValues(t, 57, v.Meta)
   109  
   110  	l.Put([]byte("key3"), y.ValueStruct{Value: val4, Meta: 12, UserMeta: []byte{0}, Version: 1})
   111  	v = l.Get([]byte("key3"), 1)
   112  	require.True(t, v.Value != nil)
   113  	require.EqualValues(t, "00072", string(v.Value))
   114  	require.EqualValues(t, 12, v.Meta)
   115  }
   116  
   117  // TestConcurrentBasic tests concurrent writes followed by concurrent reads.
   118  func TestConcurrentBasic(t *testing.T) {
   119  	const n = 1000
   120  	l := newSkiplist(arenaSize)
   121  	var wg sync.WaitGroup
   122  	key := func(i int) []byte {
   123  		return []byte(fmt.Sprintf("%05d", i))
   124  	}
   125  	for i := 0; i < n; i++ {
   126  		wg.Add(1)
   127  		go func(i int) {
   128  			defer wg.Done()
   129  			l.Put(key(i),
   130  				y.ValueStruct{Value: newValue(i), Meta: 0, UserMeta: []byte{0}})
   131  		}(i)
   132  	}
   133  	wg.Wait()
   134  	// Check values. Concurrent reads.
   135  	for i := 0; i < n; i++ {
   136  		wg.Add(1)
   137  		go func(i int) {
   138  			defer wg.Done()
   139  			v := l.Get(key(i), 0)
   140  			require.True(t, v.Value != nil)
   141  			require.EqualValues(t, newValue(i), v.Value)
   142  		}(i)
   143  	}
   144  	wg.Wait()
   145  	require.EqualValues(t, n, length(l))
   146  }
   147  
   148  func TestFindNear(t *testing.T) {
   149  	l := newSkiplist(arenaSize)
   150  	defer l.Delete()
   151  	for i := 0; i < 1000; i++ {
   152  		key := fmt.Sprintf("%05d", i*10+5)
   153  		l.Put([]byte(key), y.ValueStruct{Value: newValue(i), Meta: 0, UserMeta: []byte{0}})
   154  	}
   155  
   156  	n, eq := l.findNear([]byte("00001"), false, false)
   157  	require.NotNil(t, n)
   158  	require.EqualValues(t, []byte("00005"), n.key(l.arena))
   159  	require.False(t, eq)
   160  	n, eq = l.findNear([]byte("00001"), false, true)
   161  	require.NotNil(t, n)
   162  	require.EqualValues(t, []byte("00005"), n.key(l.arena))
   163  	require.False(t, eq)
   164  	n, eq = l.findNear([]byte("00001"), true, false)
   165  	require.Nil(t, n)
   166  	require.False(t, eq)
   167  	n, eq = l.findNear([]byte("00001"), true, true)
   168  	require.Nil(t, n)
   169  	require.False(t, eq)
   170  
   171  	n, eq = l.findNear([]byte("00005"), false, false)
   172  	require.NotNil(t, n)
   173  	require.EqualValues(t, []byte("00015"), n.key(l.arena))
   174  	require.False(t, eq)
   175  	n, eq = l.findNear([]byte("00005"), false, true)
   176  	require.NotNil(t, n)
   177  	require.EqualValues(t, []byte("00005"), n.key(l.arena))
   178  	require.True(t, eq)
   179  	n, eq = l.findNear([]byte("00005"), true, false)
   180  	require.Nil(t, n)
   181  	require.False(t, eq)
   182  	n, eq = l.findNear([]byte("00005"), true, true)
   183  	require.NotNil(t, n)
   184  	require.EqualValues(t, []byte("00005"), n.key(l.arena))
   185  	require.True(t, eq)
   186  
   187  	n, eq = l.findNear([]byte("05555"), false, false)
   188  	require.NotNil(t, n)
   189  	require.EqualValues(t, []byte("05565"), n.key(l.arena))
   190  	require.False(t, eq)
   191  	n, eq = l.findNear([]byte("05555"), false, true)
   192  	require.NotNil(t, n)
   193  	require.EqualValues(t, []byte("05555"), n.key(l.arena))
   194  	require.True(t, eq)
   195  	n, eq = l.findNear([]byte("05555"), true, false)
   196  	require.NotNil(t, n)
   197  	require.EqualValues(t, []byte("05545"), n.key(l.arena))
   198  	require.False(t, eq)
   199  	n, eq = l.findNear([]byte("05555"), true, true)
   200  	require.NotNil(t, n)
   201  	require.EqualValues(t, []byte("05555"), n.key(l.arena))
   202  	require.True(t, eq)
   203  
   204  	n, eq = l.findNear([]byte("05558"), false, false)
   205  	require.NotNil(t, n)
   206  	require.EqualValues(t, []byte("05565"), n.key(l.arena))
   207  	require.False(t, eq)
   208  	n, eq = l.findNear([]byte("05558"), false, true)
   209  	require.NotNil(t, n)
   210  	require.EqualValues(t, []byte("05565"), n.key(l.arena))
   211  	require.False(t, eq)
   212  	n, eq = l.findNear([]byte("05558"), true, false)
   213  	require.NotNil(t, n)
   214  	require.EqualValues(t, []byte("05555"), n.key(l.arena))
   215  	require.False(t, eq)
   216  	n, eq = l.findNear([]byte("05558"), true, true)
   217  	require.NotNil(t, n)
   218  	require.EqualValues(t, []byte("05555"), n.key(l.arena))
   219  	require.False(t, eq)
   220  
   221  	n, eq = l.findNear([]byte("09995"), false, false)
   222  	require.Nil(t, n)
   223  	require.False(t, eq)
   224  	n, eq = l.findNear([]byte("09995"), false, true)
   225  	require.NotNil(t, n)
   226  	require.EqualValues(t, []byte("09995"), n.key(l.arena))
   227  	require.True(t, eq)
   228  	n, eq = l.findNear([]byte("09995"), true, false)
   229  	require.NotNil(t, n)
   230  	require.EqualValues(t, []byte("09985"), n.key(l.arena))
   231  	require.False(t, eq)
   232  	n, eq = l.findNear([]byte("09995"), true, true)
   233  	require.NotNil(t, n)
   234  	require.EqualValues(t, []byte("09995"), n.key(l.arena))
   235  	require.True(t, eq)
   236  
   237  	n, eq = l.findNear([]byte("59995"), false, false)
   238  	require.Nil(t, n)
   239  	require.False(t, eq)
   240  	n, eq = l.findNear([]byte("59995"), false, true)
   241  	require.Nil(t, n)
   242  	require.False(t, eq)
   243  	n, eq = l.findNear([]byte("59995"), true, false)
   244  	require.NotNil(t, n)
   245  	require.EqualValues(t, []byte("09995"), n.key(l.arena))
   246  	require.False(t, eq)
   247  	n, eq = l.findNear([]byte("59995"), true, true)
   248  	require.NotNil(t, n)
   249  	require.EqualValues(t, []byte("09995"), n.key(l.arena))
   250  	require.False(t, eq)
   251  }
   252  
   253  // TestIteratorNext tests a basic iteration over all nodes from the beginning.
   254  func TestIteratorNext(t *testing.T) {
   255  	const n = 100
   256  	l := newSkiplist(arenaSize)
   257  	defer l.Delete()
   258  	it := l.NewIterator()
   259  	defer it.Close()
   260  	require.False(t, it.Valid())
   261  	it.SeekToFirst()
   262  	require.False(t, it.Valid())
   263  	for i := n - 1; i >= 0; i-- {
   264  		l.Put([]byte(fmt.Sprintf("%05d", i)),
   265  			y.ValueStruct{Value: newValue(i), Meta: 0, UserMeta: []byte{0}})
   266  	}
   267  	it.SeekToFirst()
   268  	for i := 0; i < n; i++ {
   269  		require.True(t, it.Valid())
   270  		v := it.Value()
   271  		require.EqualValues(t, newValue(i), v.Value)
   272  		it.Next()
   273  	}
   274  	require.False(t, it.Valid())
   275  }
   276  
   277  // TestIteratorPrev tests a basic iteration over all nodes from the end.
   278  func TestIteratorPrev(t *testing.T) {
   279  	const n = 100
   280  	l := newSkiplist(arenaSize)
   281  	defer l.Delete()
   282  	it := l.NewIterator()
   283  	defer it.Close()
   284  	require.False(t, it.Valid())
   285  	it.SeekToFirst()
   286  	require.False(t, it.Valid())
   287  	for i := 0; i < n; i++ {
   288  		l.Put([]byte(fmt.Sprintf("%05d", i)),
   289  			y.ValueStruct{Value: newValue(i), Meta: 0, UserMeta: []byte{0}})
   290  	}
   291  	it.SeekToLast()
   292  	for i := n - 1; i >= 0; i-- {
   293  		require.True(t, it.Valid())
   294  		v := it.Value()
   295  		require.EqualValues(t, newValue(i), v.Value)
   296  		it.Prev()
   297  	}
   298  	require.False(t, it.Valid())
   299  }
   300  
   301  // TestIteratorSeek tests Seek and SeekForPrev.
   302  func TestIteratorSeek(t *testing.T) {
   303  	const n = 100
   304  	l := newSkiplist(arenaSize)
   305  	defer l.Delete()
   306  
   307  	it := l.NewIterator()
   308  	defer it.Close()
   309  	require.False(t, it.Valid())
   310  	it.SeekToFirst()
   311  	require.False(t, it.Valid())
   312  	// 1000, 1010, 1020, ..., 1990.
   313  	for i := n - 1; i >= 0; i-- {
   314  		v := i*10 + 1000
   315  		l.Put([]byte(fmt.Sprintf("%05d", i*10+1000)),
   316  			y.ValueStruct{Value: newValue(v), Meta: 0, UserMeta: []byte{0}})
   317  	}
   318  	it.SeekToFirst()
   319  	require.True(t, it.Valid())
   320  	v := it.Value()
   321  	require.EqualValues(t, "01000", v.Value)
   322  
   323  	it.Seek([]byte("01000"))
   324  	require.True(t, it.Valid())
   325  	v = it.Value()
   326  	require.EqualValues(t, "01000", v.Value)
   327  
   328  	it.Seek([]byte("01005"))
   329  	require.True(t, it.Valid())
   330  	v = it.Value()
   331  	require.EqualValues(t, "01010", v.Value)
   332  
   333  	it.Seek([]byte("01010"))
   334  	require.True(t, it.Valid())
   335  	v = it.Value()
   336  	require.EqualValues(t, "01010", v.Value)
   337  
   338  	it.Seek([]byte("99999"))
   339  	require.False(t, it.Valid())
   340  
   341  	// Try SeekForPrev.
   342  	it.SeekForPrev([]byte("00"))
   343  	require.False(t, it.Valid())
   344  
   345  	it.SeekForPrev([]byte("01000"))
   346  	require.True(t, it.Valid())
   347  	v = it.Value()
   348  	require.EqualValues(t, "01000", v.Value)
   349  
   350  	it.SeekForPrev([]byte("01005"))
   351  	require.True(t, it.Valid())
   352  	v = it.Value()
   353  	require.EqualValues(t, "01000", v.Value)
   354  
   355  	it.SeekForPrev([]byte("01010"))
   356  	require.True(t, it.Valid())
   357  	v = it.Value()
   358  	require.EqualValues(t, "01010", v.Value)
   359  
   360  	it.SeekForPrev([]byte("99999"))
   361  	require.True(t, it.Valid())
   362  	v = it.Value()
   363  	require.EqualValues(t, "01990", v.Value)
   364  }
   365  
   366  func TestPutWithHint(t *testing.T) {
   367  	l := newSkiplist(arenaSize)
   368  	sp := new(hint)
   369  	cnt := 0
   370  	for {
   371  		if l.arena.size() > arenaSize-256 {
   372  			break
   373  		}
   374  		key := randomKey()
   375  		l.PutWithHint(key, y.ValueStruct{Value: key}, sp)
   376  		cnt++
   377  	}
   378  	it := l.NewIterator()
   379  	defer it.Close()
   380  	var lastKey y.Key
   381  	cntGot := 0
   382  	for it.SeekToFirst(); it.Valid(); it.Next() {
   383  		require.True(t, lastKey.Compare(it.Key()) <= 0)
   384  		require.True(t, bytes.Compare(it.Key().UserKey, it.Value().Value) == 0)
   385  		cntGot++
   386  		lastKey.Copy(it.Key())
   387  	}
   388  	require.True(t, cntGot == cnt)
   389  }
   390  
   391  func TestGetWithHint(t *testing.T) {
   392  	rand.Seed(time.Now().Unix())
   393  	l := newSkiplist(arenaSize)
   394  	var keys [][]byte
   395  	sp := new(hint)
   396  	for {
   397  		if l.arena.size() > arenaSize-256 {
   398  			break
   399  		}
   400  		key := randomKey()
   401  		keys = append(keys, key)
   402  		l.PutWithHint(key, y.ValueStruct{Value: key}, sp)
   403  	}
   404  	h := new(hint)
   405  	for _, key := range keys {
   406  		bytes.Equal(l.GetWithHint(key, 0, h).Value, key)
   407  	}
   408  	sort.Slice(keys, func(i, j int) bool {
   409  		return bytes.Compare(keys[i], keys[j]) < 0
   410  	})
   411  	for _, key := range keys {
   412  		bytes.Equal(l.GetWithHint(key, 0, h).Value, key)
   413  	}
   414  }
   415  
   416  func TestPutLargeValue(t *testing.T) {
   417  	l := newSkiplist(arenaSize)
   418  	key := randomKey()
   419  	val := make([]byte, 128*1024)
   420  	l.Put(key, y.ValueStruct{Value: val})
   421  	result := l.Get(key, 0)
   422  	require.Equal(t, val, result.Value)
   423  }
   424  
   425  func key(prefix string, i int) string {
   426  	return prefix + fmt.Sprintf("%04d", i)
   427  }
   428  
   429  func generateKeyValues(prefix string, n int) [][]string {
   430  	y.Assert(n <= 10000)
   431  	keyValues := make([][]string, n)
   432  	for i := 0; i < n; i++ {
   433  		k := key(prefix, i)
   434  		v := fmt.Sprintf("%d", i)
   435  		keyValues[i] = []string{k, v}
   436  	}
   437  	return keyValues
   438  }
   439  
   440  func buildMultiVersionSkiopList(keyValues [][]string) *skiplist {
   441  	sort.Slice(keyValues, func(i, j int) bool {
   442  		return keyValues[i][0] < keyValues[j][0]
   443  	})
   444  	skl := newSkiplist(arenaSize)
   445  	for _, kv := range keyValues {
   446  		y.Assert(len(kv) == 2)
   447  		val := fmt.Sprintf("%s_%d", kv[1], 9)
   448  		skl.Put([]byte(kv[0]), y.ValueStruct{Value: []byte(val), Meta: 'A', UserMeta: []byte{0}, Version: 9})
   449  		for i := uint64(8); i > 0; i-- {
   450  			if z.FastRand()%4 != 0 {
   451  				val = fmt.Sprintf("%s_%d", kv[1], i)
   452  				skl.Put([]byte(kv[0]), y.ValueStruct{Value: []byte(val), Meta: 'A', UserMeta: []byte{0}, Version: i})
   453  			}
   454  		}
   455  	}
   456  	return skl
   457  }
   458  
   459  func TestIterateMultiVersion(t *testing.T) {
   460  	keyVals := generateKeyValues("key", 4000)
   461  	skl := buildMultiVersionSkiopList(keyVals)
   462  	it := skl.NewIterator()
   463  	defer it.Close()
   464  	var lastKey y.Key
   465  	for it.SeekToFirst(); it.Valid(); it.Next() {
   466  		if !lastKey.IsEmpty() {
   467  			require.True(t, bytes.Compare(lastKey.UserKey, it.Key().UserKey) < 0)
   468  		}
   469  		lastKey.Copy(it.Key())
   470  	}
   471  	for i := 0; i < 1000; i++ {
   472  		id := int(z.FastRand() % 4000)
   473  		k := y.KeyWithTs([]byte(key("key", id)), uint64(5+z.FastRand()%5))
   474  		val := skl.Get(k.UserKey, k.Version)
   475  		if val.Valid() {
   476  			valStr := fmt.Sprintf("%d_%d", id, k.Version)
   477  			require.Equal(t, valStr, string(val.Value))
   478  		} else {
   479  			it.Seek(k.UserKey)
   480  			if it.Valid() {
   481  				require.True(t, bytes.Compare(it.Key().UserKey, k.UserKey) >= 0)
   482  				var cpKey y.Key
   483  				cpKey.Copy(it.Key())
   484  				it.Prev()
   485  				if it.Valid() {
   486  					require.True(t, bytes.Compare(it.Key().UserKey, k.UserKey) < 0, "%s %s %s", it.Key(), cpKey, k)
   487  				}
   488  			}
   489  		}
   490  	}
   491  	revIt := skl.NewUniIterator(true)
   492  	defer revIt.Close()
   493  	lastKey.Reset()
   494  	for revIt.Rewind(); revIt.Valid(); revIt.Next() {
   495  		if !lastKey.IsEmpty() {
   496  			require.Truef(t, bytes.Compare(lastKey.UserKey, revIt.Key().UserKey) > 0, "%v %v", lastKey.String(), revIt.Key().String())
   497  		}
   498  		lastKey.Copy(revIt.Key())
   499  	}
   500  	for i := 0; i < 1000; i++ {
   501  		k := y.KeyWithTs([]byte(key("key", int(z.FastRand()%4000))), uint64(5+z.FastRand()%5))
   502  		// reverse iterator never seek to the same key with smaller version.
   503  		revIt.Seek(k.UserKey)
   504  		if !revIt.Valid() {
   505  			continue
   506  		}
   507  		require.True(t, bytes.Compare(revIt.Key().UserKey, k.UserKey) <= 0, "%s %s", revIt.Key(), k)
   508  	}
   509  }
   510  
   511  func randomKey() []byte {
   512  	b := make([]byte, 8)
   513  	key := rand.Uint32()
   514  	key2 := rand.Uint32()
   515  	binary.LittleEndian.PutUint32(b, key)
   516  	binary.LittleEndian.PutUint32(b[4:], key2)
   517  	return b
   518  }
   519  
   520  // Standard test. Some fraction is read. Some fraction is write. Writes have
   521  // to go through mutex lock.
   522  func BenchmarkReadWrite(b *testing.B) {
   523  	value := newValue(123)
   524  	for i := 0; i <= 10; i++ {
   525  		readFrac := float32(i) / 10.0
   526  		b.Run(fmt.Sprintf("frac_%d", i), func(b *testing.B) {
   527  			l := newSkiplist(int64((b.N + 1) * MaxNodeSize))
   528  			defer l.Delete()
   529  			b.ResetTimer()
   530  			var count int
   531  			b.RunParallel(func(pb *testing.PB) {
   532  				rng := rand.New(rand.NewSource(time.Now().UnixNano()))
   533  				for pb.Next() {
   534  					if rng.Float32() < readFrac {
   535  						v := l.Get(randomKey(), 0)
   536  						if v.Value != nil {
   537  							count++
   538  						}
   539  					} else {
   540  						l.Put(randomKey(), y.ValueStruct{Value: value, Meta: 0, UserMeta: []byte{0}})
   541  					}
   542  				}
   543  			})
   544  		})
   545  	}
   546  }
   547  
   548  // Standard test. Some fraction is read. Some fraction is write. Writes have
   549  // to go through mutex lock.
   550  func BenchmarkReadWriteMap(b *testing.B) {
   551  	value := newValue(123)
   552  	for i := 0; i <= 10; i++ {
   553  		readFrac := float32(i) / 10.0
   554  		b.Run(fmt.Sprintf("frac_%d", i), func(b *testing.B) {
   555  			m := make(map[string][]byte)
   556  			var mutex sync.RWMutex
   557  			b.ResetTimer()
   558  			var count int
   559  			b.RunParallel(func(pb *testing.PB) {
   560  				for pb.Next() {
   561  					if rand.Float32() < readFrac {
   562  						mutex.RLock()
   563  						_, ok := m[string(randomKey())]
   564  						mutex.RUnlock()
   565  						if ok {
   566  							count++
   567  						}
   568  					} else {
   569  						mutex.Lock()
   570  						m[string(randomKey())] = value
   571  						mutex.Unlock()
   572  					}
   573  				}
   574  			})
   575  		})
   576  	}
   577  }
   578  
   579  // Standard test. Some fraction is read. Some fraction is write. Writes have
   580  // to go through mutex lock.
   581  func BenchmarkGetSequential(b *testing.B) {
   582  	size := 300000
   583  	keys, l, _ := buildKeysAndList(size)
   584  	b.ResetTimer()
   585  	for i := 0; i < b.N; i++ {
   586  		key := keys[i%size]
   587  		l.Get(key, 0)
   588  	}
   589  }
   590  
   591  func BenchmarkGetWithHintSequential(b *testing.B) {
   592  	size := 300000
   593  	keys, l, h := buildKeysAndList(size)
   594  	b.ResetTimer()
   595  	for i := 0; i < b.N; i++ {
   596  		key := keys[i%size]
   597  		l.GetWithHint(key, 0, h)
   598  	}
   599  }
   600  
   601  func buildKeysAndList(size int) ([][]byte, *skiplist, *hint) {
   602  	l := newSkiplist(32 * 1024 * 1024)
   603  	keys := make([][]byte, size)
   604  	h := new(hint)
   605  	for i := 0; i < size; i++ {
   606  		keys[i] = []byte(fmt.Sprintf("%05d", i))
   607  	}
   608  	for i := 0; i < size; i++ {
   609  		key := keys[i]
   610  		l.PutWithHint(key, y.ValueStruct{Value: []byte{byte(i)}}, h)
   611  	}
   612  	return keys, l, h
   613  }
   614  
   615  func BenchmarkGetRandom(b *testing.B) {
   616  	size := 300000
   617  	keys, l, _ := buildKeysAndList(size)
   618  	b.ResetTimer()
   619  	r := rand.New(rand.NewSource(1))
   620  	for i := 0; i < b.N; i++ {
   621  		key := keys[r.Int()%size]
   622  		l.Get(key, 0)
   623  	}
   624  }
   625  
   626  func BenchmarkGetWithHintRandom(b *testing.B) {
   627  	size := 300000
   628  	keys, l, h := buildKeysAndList(size)
   629  	b.ResetTimer()
   630  	r := rand.New(rand.NewSource(1))
   631  	for i := 0; i < b.N; i++ {
   632  		key := keys[r.Int()%size]
   633  		l.GetWithHint(key, 0, h)
   634  	}
   635  }
   636  
   637  func BenchmarkPutWithHint(b *testing.B) {
   638  	l := newSkiplist(16 * 1024 * 1024)
   639  	size := 100000
   640  	keys := make([][]byte, size)
   641  	for i := 0; i < size; i++ {
   642  		keys[i] = []byte(fmt.Sprintf("%05d", i))
   643  	}
   644  	b.ResetTimer()
   645  	for i := 0; i < b.N; i++ {
   646  		h := new(hint)
   647  		l = newSkiplist(16 * 1024 * 1024)
   648  		for j := 0; j < size; j++ {
   649  			key := keys[j]
   650  			l.PutWithHint(key, y.ValueStruct{Value: []byte{byte(j)}}, h)
   651  		}
   652  	}
   653  }