mirror of
				https://source.quilibrium.com/quilibrium/ceremonyclient.git
				synced 2025-11-04 03:07:28 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			540 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			540 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
 * Copyright 2017 Dgraph Labs, Inc. and Contributors
 | 
						|
 * Modifications copyright (C) 2017 Andy Kimball and Contributors
 | 
						|
 *
 | 
						|
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
 * you may not use this file except in compliance with the License.
 | 
						|
 * You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 * Unless required by applicable law or agreed to in writing, software
 | 
						|
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 * See the License for the specific language governing permissions and
 | 
						|
 * limitations under the License.
 | 
						|
 */
 | 
						|
 | 
						|
package batchskl
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"encoding/binary"
 | 
						|
	"fmt"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/cockroachdb/errors"
 | 
						|
	"github.com/cockroachdb/pebble/internal/base"
 | 
						|
	"github.com/stretchr/testify/require"
 | 
						|
	"golang.org/x/exp/rand"
 | 
						|
)
 | 
						|
 | 
						|
// iterAdapter adapts the new Iterator API which returns the key and value from
 | 
						|
// positioning methods (Seek*, First, Last, Next, Prev) to the old API which
 | 
						|
// returned a boolean corresponding to Valid. Only used by test code.
 | 
						|
type iterAdapter struct {
 | 
						|
	Iterator
 | 
						|
}
 | 
						|
 | 
						|
func (i *iterAdapter) verify(key *base.InternalKey) bool {
 | 
						|
	valid := key != nil
 | 
						|
	if valid != i.Valid() {
 | 
						|
		panic(fmt.Sprintf("inconsistent valid: %t != %t", valid, i.Valid()))
 | 
						|
	}
 | 
						|
	if valid {
 | 
						|
		if base.InternalCompare(bytes.Compare, *key, i.Key()) != 0 {
 | 
						|
			panic(fmt.Sprintf("inconsistent key: %s != %s", *key, i.Key()))
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return valid
 | 
						|
}
 | 
						|
 | 
						|
func (i *iterAdapter) SeekGE(key []byte) bool {
 | 
						|
	return i.verify(i.Iterator.SeekGE(key, base.SeekGEFlagsNone))
 | 
						|
}
 | 
						|
 | 
						|
func (i *iterAdapter) SeekLT(key []byte) bool {
 | 
						|
	return i.verify(i.Iterator.SeekLT(key))
 | 
						|
}
 | 
						|
 | 
						|
func (i *iterAdapter) First() bool {
 | 
						|
	return i.verify(i.Iterator.First())
 | 
						|
}
 | 
						|
 | 
						|
func (i *iterAdapter) Last() bool {
 | 
						|
	return i.verify(i.Iterator.Last())
 | 
						|
}
 | 
						|
 | 
						|
func (i *iterAdapter) Next() bool {
 | 
						|
	return i.verify(i.Iterator.Next())
 | 
						|
}
 | 
						|
 | 
						|
func (i *iterAdapter) Prev() bool {
 | 
						|
	return i.verify(i.Iterator.Prev())
 | 
						|
}
 | 
						|
 | 
						|
func (i *iterAdapter) Key() base.InternalKey {
 | 
						|
	return *i.Iterator.Key()
 | 
						|
}
 | 
						|
 | 
						|
// length iterates over skiplist to give exact size.
 | 
						|
func length(s *Skiplist) int {
 | 
						|
	count := 0
 | 
						|
 | 
						|
	it := iterAdapter{s.NewIter(nil, nil)}
 | 
						|
	for valid := it.First(); valid; valid = it.Next() {
 | 
						|
		count++
 | 
						|
	}
 | 
						|
 | 
						|
	return count
 | 
						|
}
 | 
						|
 | 
						|
// length iterates over skiplist in reverse order to give exact size.
 | 
						|
func lengthRev(s *Skiplist) int {
 | 
						|
	count := 0
 | 
						|
 | 
						|
	it := iterAdapter{s.NewIter(nil, nil)}
 | 
						|
	for valid := it.Last(); valid; valid = it.Prev() {
 | 
						|
		count++
 | 
						|
	}
 | 
						|
 | 
						|
	return count
 | 
						|
}
 | 
						|
 | 
						|
func makeKey(s string) []byte {
 | 
						|
	return []byte(s)
 | 
						|
}
 | 
						|
 | 
						|
type testStorage struct {
 | 
						|
	data []byte
 | 
						|
}
 | 
						|
 | 
						|
func (d *testStorage) add(key string) uint32 {
 | 
						|
	offset := uint32(len(d.data))
 | 
						|
	d.data = append(d.data, uint8(base.InternalKeyKindSet))
 | 
						|
	var buf [binary.MaxVarintLen64]byte
 | 
						|
	n := binary.PutUvarint(buf[:], uint64(len(key)))
 | 
						|
	d.data = append(d.data, buf[:n]...)
 | 
						|
	d.data = append(d.data, key...)
 | 
						|
	return offset
 | 
						|
}
 | 
						|
 | 
						|
func (d *testStorage) addBytes(key []byte) uint32 {
 | 
						|
	offset := uint32(len(d.data))
 | 
						|
	d.data = append(d.data, uint8(base.InternalKeyKindSet))
 | 
						|
	var buf [binary.MaxVarintLen64]byte
 | 
						|
	n := binary.PutUvarint(buf[:], uint64(len(key)))
 | 
						|
	d.data = append(d.data, buf[:n]...)
 | 
						|
	d.data = append(d.data, key...)
 | 
						|
	return offset
 | 
						|
}
 | 
						|
 | 
						|
func newTestSkiplist(storage *testStorage) *Skiplist {
 | 
						|
	return NewSkiplist(&storage.data, base.DefaultComparer.Compare,
 | 
						|
		base.DefaultComparer.AbbreviatedKey)
 | 
						|
}
 | 
						|
 | 
						|
func TestEmpty(t *testing.T) {
 | 
						|
	key := makeKey("aaa")
 | 
						|
	l := newTestSkiplist(&testStorage{})
 | 
						|
	it := iterAdapter{l.NewIter(nil, nil)}
 | 
						|
 | 
						|
	require.False(t, it.Valid())
 | 
						|
 | 
						|
	it.First()
 | 
						|
	require.False(t, it.Valid())
 | 
						|
 | 
						|
	it.Last()
 | 
						|
	require.False(t, it.Valid())
 | 
						|
 | 
						|
	require.False(t, it.SeekGE(key))
 | 
						|
	require.False(t, it.Valid())
 | 
						|
}
 | 
						|
 | 
						|
// TestBasic tests seeks and adds.
 | 
						|
func TestBasic(t *testing.T) {
 | 
						|
	d := &testStorage{}
 | 
						|
	l := newTestSkiplist(d)
 | 
						|
	it := iterAdapter{l.NewIter(nil, nil)}
 | 
						|
 | 
						|
	// Try adding values.
 | 
						|
	require.Nil(t, l.Add(d.add("key1")))
 | 
						|
	require.Nil(t, l.Add(d.add("key2")))
 | 
						|
	require.Nil(t, l.Add(d.add("key3")))
 | 
						|
 | 
						|
	require.True(t, it.SeekGE(makeKey("key")))
 | 
						|
	require.EqualValues(t, "key1", it.Key().UserKey)
 | 
						|
 | 
						|
	require.True(t, it.SeekGE(makeKey("key1")))
 | 
						|
	require.EqualValues(t, "key1", it.Key().UserKey)
 | 
						|
 | 
						|
	require.True(t, it.SeekGE(makeKey("key2")))
 | 
						|
	require.EqualValues(t, "key2", it.Key().UserKey)
 | 
						|
 | 
						|
	require.True(t, it.SeekGE(makeKey("key3")))
 | 
						|
	require.EqualValues(t, "key3", it.Key().UserKey)
 | 
						|
 | 
						|
	require.True(t, it.SeekGE(makeKey("key2")))
 | 
						|
	require.True(t, it.SeekGE(makeKey("key3")))
 | 
						|
}
 | 
						|
 | 
						|
func TestSkiplistAdd(t *testing.T) {
 | 
						|
	d := &testStorage{}
 | 
						|
	l := newTestSkiplist(d)
 | 
						|
	it := iterAdapter{l.NewIter(nil, nil)}
 | 
						|
 | 
						|
	// Add empty key.
 | 
						|
	require.Nil(t, l.Add(d.add("")))
 | 
						|
	require.EqualValues(t, []byte(nil), it.Key().UserKey)
 | 
						|
	require.True(t, it.First())
 | 
						|
	require.EqualValues(t, []byte{}, it.Key().UserKey)
 | 
						|
 | 
						|
	// Add to empty list.
 | 
						|
	require.Nil(t, l.Add(d.add("00002")))
 | 
						|
	require.True(t, it.SeekGE(makeKey("00002")))
 | 
						|
	require.EqualValues(t, "00002", it.Key().UserKey)
 | 
						|
 | 
						|
	// Add first element in non-empty list.
 | 
						|
	require.Nil(t, l.Add(d.add("00001")))
 | 
						|
	require.True(t, it.SeekGE(makeKey("00001")))
 | 
						|
	require.EqualValues(t, "00001", it.Key().UserKey)
 | 
						|
 | 
						|
	// Add last element in non-empty list.
 | 
						|
	require.Nil(t, l.Add(d.add("00004")))
 | 
						|
	require.True(t, it.SeekGE(makeKey("00004")))
 | 
						|
	require.EqualValues(t, "00004", it.Key().UserKey)
 | 
						|
 | 
						|
	// Add element in middle of list.
 | 
						|
	require.Nil(t, l.Add(d.add("00003")))
 | 
						|
	require.True(t, it.SeekGE(makeKey("00003")))
 | 
						|
	require.EqualValues(t, "00003", it.Key().UserKey)
 | 
						|
 | 
						|
	// Try to add element that already exists.
 | 
						|
	require.Nil(t, l.Add(d.add("00002")))
 | 
						|
	require.Equal(t, 6, length(l))
 | 
						|
	require.Equal(t, 6, lengthRev(l))
 | 
						|
}
 | 
						|
 | 
						|
func TestSkiplistAdd_Overflow(t *testing.T) {
 | 
						|
	// Regression test for cockroachdb/pebble#1258. The length of the nodes buffer
 | 
						|
	// cannot exceed the maximum allowable size.
 | 
						|
	d := &testStorage{}
 | 
						|
	l := newTestSkiplist(d)
 | 
						|
 | 
						|
	// Simulate a full nodes slice. This speeds up the test significantly, as
 | 
						|
	// opposed to adding data to the list.
 | 
						|
	l.nodes = make([]byte, maxNodesSize)
 | 
						|
 | 
						|
	// Adding a new node to the list would overflow the nodes slice. Note that it
 | 
						|
	// is the size of a new node struct that is relevant here, rather than the
 | 
						|
	// size of the data being added to the list.
 | 
						|
	err := l.Add(d.add("too much!"))
 | 
						|
	require.Error(t, err)
 | 
						|
	require.True(t, errors.Is(err, ErrTooManyRecords))
 | 
						|
}
 | 
						|
 | 
						|
// TestIteratorNext tests a basic iteration over all nodes from the beginning.
 | 
						|
func TestIteratorNext(t *testing.T) {
 | 
						|
	const n = 100
 | 
						|
	d := &testStorage{}
 | 
						|
	l := newTestSkiplist(d)
 | 
						|
	it := iterAdapter{l.NewIter(nil, nil)}
 | 
						|
 | 
						|
	require.False(t, it.Valid())
 | 
						|
 | 
						|
	it.First()
 | 
						|
	require.False(t, it.Valid())
 | 
						|
 | 
						|
	for i := n - 1; i >= 0; i-- {
 | 
						|
		require.Nil(t, l.Add(d.add(fmt.Sprintf("%05d", i))))
 | 
						|
	}
 | 
						|
 | 
						|
	it.First()
 | 
						|
	for i := 0; i < n; i++ {
 | 
						|
		require.True(t, it.Valid())
 | 
						|
		require.EqualValues(t, fmt.Sprintf("%05d", i), it.Key().UserKey)
 | 
						|
		it.Next()
 | 
						|
	}
 | 
						|
	require.False(t, it.Valid())
 | 
						|
}
 | 
						|
 | 
						|
// // TestIteratorPrev tests a basic iteration over all nodes from the end.
 | 
						|
func TestIteratorPrev(t *testing.T) {
 | 
						|
	const n = 100
 | 
						|
	d := &testStorage{}
 | 
						|
	l := newTestSkiplist(d)
 | 
						|
	it := iterAdapter{l.NewIter(nil, nil)}
 | 
						|
 | 
						|
	require.False(t, it.Valid())
 | 
						|
 | 
						|
	it.Last()
 | 
						|
	require.False(t, it.Valid())
 | 
						|
 | 
						|
	for i := 0; i < n; i++ {
 | 
						|
		l.Add(d.add(fmt.Sprintf("%05d", i)))
 | 
						|
	}
 | 
						|
 | 
						|
	it.Last()
 | 
						|
	for i := n - 1; i >= 0; i-- {
 | 
						|
		require.True(t, it.Valid())
 | 
						|
		require.EqualValues(t, fmt.Sprintf("%05d", i), string(it.Key().UserKey))
 | 
						|
		it.Prev()
 | 
						|
	}
 | 
						|
	require.False(t, it.Valid())
 | 
						|
}
 | 
						|
 | 
						|
func TestIteratorSeekGE(t *testing.T) {
 | 
						|
	const n = 1000
 | 
						|
	d := &testStorage{}
 | 
						|
	l := newTestSkiplist(d)
 | 
						|
	it := iterAdapter{l.NewIter(nil, nil)}
 | 
						|
 | 
						|
	require.False(t, it.Valid())
 | 
						|
	it.First()
 | 
						|
	require.False(t, it.Valid())
 | 
						|
	// 1000, 1010, 1020, ..., 1990.
 | 
						|
	for i := n - 1; i >= 0; i-- {
 | 
						|
		require.Nil(t, l.Add(d.add(fmt.Sprintf("%05d", i*10+1000))))
 | 
						|
	}
 | 
						|
 | 
						|
	require.True(t, it.SeekGE(makeKey("")))
 | 
						|
	require.True(t, it.Valid())
 | 
						|
	require.EqualValues(t, "01000", it.Key().UserKey)
 | 
						|
 | 
						|
	require.True(t, it.SeekGE(makeKey("01000")))
 | 
						|
	require.True(t, it.Valid())
 | 
						|
	require.EqualValues(t, "01000", it.Key().UserKey)
 | 
						|
 | 
						|
	require.True(t, it.SeekGE(makeKey("01005")))
 | 
						|
	require.True(t, it.Valid())
 | 
						|
	require.EqualValues(t, "01010", it.Key().UserKey)
 | 
						|
 | 
						|
	require.True(t, it.SeekGE(makeKey("01010")))
 | 
						|
	require.True(t, it.Valid())
 | 
						|
	require.EqualValues(t, "01010", it.Key().UserKey)
 | 
						|
 | 
						|
	require.False(t, it.SeekGE(makeKey("99999")))
 | 
						|
	require.False(t, it.Valid())
 | 
						|
 | 
						|
	// Test seek for empty key.
 | 
						|
	require.Nil(t, l.Add(d.add("")))
 | 
						|
	require.True(t, it.SeekGE([]byte{}))
 | 
						|
	require.True(t, it.Valid())
 | 
						|
 | 
						|
	require.True(t, it.SeekGE(makeKey("")))
 | 
						|
	require.True(t, it.Valid())
 | 
						|
}
 | 
						|
 | 
						|
func TestIteratorSeekLT(t *testing.T) {
 | 
						|
	const n = 100
 | 
						|
	d := &testStorage{}
 | 
						|
	l := newTestSkiplist(d)
 | 
						|
	it := iterAdapter{l.NewIter(nil, nil)}
 | 
						|
 | 
						|
	require.False(t, it.Valid())
 | 
						|
	it.First()
 | 
						|
	require.False(t, it.Valid())
 | 
						|
	// 1000, 1010, 1020, ..., 1990.
 | 
						|
	for i := n - 1; i >= 0; i-- {
 | 
						|
		require.Nil(t, l.Add(d.add(fmt.Sprintf("%05d", i*10+1000))))
 | 
						|
	}
 | 
						|
 | 
						|
	require.False(t, it.SeekLT(makeKey("")))
 | 
						|
	require.False(t, it.Valid())
 | 
						|
 | 
						|
	require.False(t, it.SeekLT(makeKey("01000")))
 | 
						|
	require.False(t, it.Valid())
 | 
						|
 | 
						|
	require.True(t, it.SeekLT(makeKey("01001")))
 | 
						|
	require.EqualValues(t, "01000", it.Key().UserKey)
 | 
						|
	require.True(t, it.Valid())
 | 
						|
 | 
						|
	require.True(t, it.SeekLT(makeKey("01005")))
 | 
						|
	require.EqualValues(t, "01000", it.Key().UserKey)
 | 
						|
	require.True(t, it.Valid())
 | 
						|
 | 
						|
	require.True(t, it.SeekLT(makeKey("01991")))
 | 
						|
	require.EqualValues(t, "01990", it.Key().UserKey)
 | 
						|
	require.True(t, it.Valid())
 | 
						|
 | 
						|
	require.True(t, it.SeekLT(makeKey("99999")))
 | 
						|
	require.True(t, it.Valid())
 | 
						|
	require.EqualValues(t, "01990", it.Key().UserKey)
 | 
						|
 | 
						|
	// Test seek for empty key.
 | 
						|
	require.Nil(t, l.Add(d.add("")))
 | 
						|
	require.False(t, it.SeekLT([]byte{}))
 | 
						|
	require.False(t, it.Valid())
 | 
						|
	require.True(t, it.SeekLT(makeKey("\x01")))
 | 
						|
	require.True(t, it.Valid())
 | 
						|
	require.EqualValues(t, "", it.Key().UserKey)
 | 
						|
}
 | 
						|
 | 
						|
// TODO(peter): test First and Last.
 | 
						|
func TestIteratorBounds(t *testing.T) {
 | 
						|
	d := &testStorage{}
 | 
						|
	l := newTestSkiplist(d)
 | 
						|
	for i := 1; i < 10; i++ {
 | 
						|
		require.NoError(t, l.Add(d.add(fmt.Sprintf("%05d", i))))
 | 
						|
	}
 | 
						|
 | 
						|
	it := iterAdapter{l.NewIter(makeKey("00003"), makeKey("00007"))}
 | 
						|
 | 
						|
	// SeekGE within the lower and upper bound succeeds.
 | 
						|
	for i := 3; i <= 6; i++ {
 | 
						|
		key := makeKey(fmt.Sprintf("%05d", i))
 | 
						|
		require.True(t, it.SeekGE(key))
 | 
						|
		require.EqualValues(t, string(key), string(it.Key().UserKey))
 | 
						|
	}
 | 
						|
 | 
						|
	// SeekGE before the lower bound still succeeds (only the upper bound is
 | 
						|
	// checked).
 | 
						|
	for i := 1; i < 3; i++ {
 | 
						|
		key := makeKey(fmt.Sprintf("%05d", i))
 | 
						|
		require.True(t, it.SeekGE(key))
 | 
						|
		require.EqualValues(t, string(key), string(it.Key().UserKey))
 | 
						|
	}
 | 
						|
 | 
						|
	// SeekGE beyond the upper bound fails.
 | 
						|
	for i := 7; i < 10; i++ {
 | 
						|
		key := makeKey(fmt.Sprintf("%05d", i))
 | 
						|
		require.False(t, it.SeekGE(key))
 | 
						|
	}
 | 
						|
 | 
						|
	require.True(t, it.SeekGE(makeKey("00006")))
 | 
						|
	require.EqualValues(t, "00006", it.Key().UserKey)
 | 
						|
 | 
						|
	// Next into the upper bound fails.
 | 
						|
	require.False(t, it.Next())
 | 
						|
 | 
						|
	// SeekLT within the lower and upper bound succeeds.
 | 
						|
	for i := 4; i <= 7; i++ {
 | 
						|
		key := makeKey(fmt.Sprintf("%05d", i))
 | 
						|
		require.True(t, it.SeekLT(key))
 | 
						|
		require.EqualValues(t, fmt.Sprintf("%05d", i-1), string(it.Key().UserKey))
 | 
						|
	}
 | 
						|
 | 
						|
	// SeekLT beyond the upper bound still succeeds (only the lower bound is
 | 
						|
	// checked).
 | 
						|
	for i := 8; i < 9; i++ {
 | 
						|
		key := makeKey(fmt.Sprintf("%05d", i))
 | 
						|
		require.True(t, it.SeekLT(key))
 | 
						|
		require.EqualValues(t, fmt.Sprintf("%05d", i-1), string(it.Key().UserKey))
 | 
						|
	}
 | 
						|
 | 
						|
	// SeekLT before the lower bound fails.
 | 
						|
	for i := 1; i < 4; i++ {
 | 
						|
		key := makeKey(fmt.Sprintf("%05d", i))
 | 
						|
		require.False(t, it.SeekLT(key))
 | 
						|
	}
 | 
						|
 | 
						|
	require.True(t, it.SeekLT(makeKey("00004")))
 | 
						|
	require.EqualValues(t, "00003", it.Key().UserKey)
 | 
						|
 | 
						|
	// Prev into the lower bound fails.
 | 
						|
	require.False(t, it.Prev())
 | 
						|
}
 | 
						|
 | 
						|
func randomKey(rng *rand.Rand, b []byte) []byte {
 | 
						|
	key := rng.Uint32()
 | 
						|
	key2 := rng.Uint32()
 | 
						|
	binary.LittleEndian.PutUint32(b, key)
 | 
						|
	binary.LittleEndian.PutUint32(b[4:], key2)
 | 
						|
	return b
 | 
						|
}
 | 
						|
 | 
						|
// Standard test. Some fraction is read. Some fraction is write. Writes have
 | 
						|
// to go through mutex lock.
 | 
						|
func BenchmarkReadWrite(b *testing.B) {
 | 
						|
	for i := 0; i <= 10; i++ {
 | 
						|
		readFrac := float32(i) / 10.0
 | 
						|
		b.Run(fmt.Sprintf("frac_%d", i*10), func(b *testing.B) {
 | 
						|
			var buf [8]byte
 | 
						|
			d := &testStorage{
 | 
						|
				data: make([]byte, 0, b.N*10),
 | 
						|
			}
 | 
						|
			l := newTestSkiplist(d)
 | 
						|
			it := l.NewIter(nil, nil)
 | 
						|
			rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano())))
 | 
						|
 | 
						|
			b.ResetTimer()
 | 
						|
			for i := 0; i < b.N; i++ {
 | 
						|
				key := randomKey(rng, buf[:])
 | 
						|
				if rng.Float32() < readFrac {
 | 
						|
					_ = it.SeekGE(key, base.SeekGEFlagsNone)
 | 
						|
				} else {
 | 
						|
					offset := d.addBytes(buf[:])
 | 
						|
					_ = l.Add(offset)
 | 
						|
				}
 | 
						|
			}
 | 
						|
			b.StopTimer()
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkOrderedWrite(b *testing.B) {
 | 
						|
	var buf [8]byte
 | 
						|
	d := &testStorage{
 | 
						|
		data: make([]byte, 0, b.N*10),
 | 
						|
	}
 | 
						|
	l := newTestSkiplist(d)
 | 
						|
 | 
						|
	b.ResetTimer()
 | 
						|
	for i := 0; i < b.N; i++ {
 | 
						|
		binary.BigEndian.PutUint64(buf[:], uint64(i))
 | 
						|
		offset := d.addBytes(buf[:])
 | 
						|
		_ = l.Add(offset)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkIterNext(b *testing.B) {
 | 
						|
	var buf [8]byte
 | 
						|
	d := &testStorage{
 | 
						|
		data: make([]byte, 0, 64<<10),
 | 
						|
	}
 | 
						|
	l := newTestSkiplist(d)
 | 
						|
 | 
						|
	rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano())))
 | 
						|
	for len(d.data)+20 < cap(d.data) {
 | 
						|
		key := randomKey(rng, buf[:])
 | 
						|
		offset := d.addBytes(key)
 | 
						|
		err := l.Add(offset)
 | 
						|
		require.NoError(b, err)
 | 
						|
	}
 | 
						|
 | 
						|
	it := l.NewIter(nil, nil)
 | 
						|
	b.ResetTimer()
 | 
						|
	for i := 0; i < b.N; i++ {
 | 
						|
		if !it.Valid() {
 | 
						|
			it.First()
 | 
						|
		}
 | 
						|
		it.Next()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkIterPrev(b *testing.B) {
 | 
						|
	var buf [8]byte
 | 
						|
	d := &testStorage{
 | 
						|
		data: make([]byte, 0, 64<<10),
 | 
						|
	}
 | 
						|
	l := newTestSkiplist(d)
 | 
						|
 | 
						|
	rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano())))
 | 
						|
	for len(d.data)+20 < cap(d.data) {
 | 
						|
		key := randomKey(rng, buf[:])
 | 
						|
		offset := d.addBytes(key)
 | 
						|
		err := l.Add(offset)
 | 
						|
		require.NoError(b, err)
 | 
						|
	}
 | 
						|
 | 
						|
	it := l.NewIter(nil, nil)
 | 
						|
	b.ResetTimer()
 | 
						|
	for i := 0; i < b.N; i++ {
 | 
						|
		if !it.Valid() {
 | 
						|
			it.Last()
 | 
						|
		}
 | 
						|
		it.Prev()
 | 
						|
	}
 | 
						|
}
 |