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