github.com/cockroachdb/pebble@v1.1.1-0.20240513155919-3622ade60459/internal/batchskl/skl_test.go (about)

     1  /*
     2   * Copyright 2017 Dgraph Labs, Inc. and Contributors
     3   * Modifications copyright (C) 2017 Andy Kimball and Contributors
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package batchskl
    19  
    20  import (
    21  	"bytes"
    22  	"encoding/binary"
    23  	"fmt"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/cockroachdb/errors"
    28  	"github.com/cockroachdb/pebble/internal/base"
    29  	"github.com/stretchr/testify/require"
    30  	"golang.org/x/exp/rand"
    31  )
    32  
    33  // iterAdapter adapts the new Iterator API which returns the key and value from
    34  // positioning methods (Seek*, First, Last, Next, Prev) to the old API which
    35  // returned a boolean corresponding to Valid. Only used by test code.
    36  type iterAdapter struct {
    37  	Iterator
    38  }
    39  
    40  func (i *iterAdapter) verify(key *base.InternalKey) bool {
    41  	valid := key != nil
    42  	if valid != i.Valid() {
    43  		panic(fmt.Sprintf("inconsistent valid: %t != %t", valid, i.Valid()))
    44  	}
    45  	if valid {
    46  		if base.InternalCompare(bytes.Compare, *key, i.Key()) != 0 {
    47  			panic(fmt.Sprintf("inconsistent key: %s != %s", *key, i.Key()))
    48  		}
    49  	}
    50  	return valid
    51  }
    52  
    53  func (i *iterAdapter) SeekGE(key []byte) bool {
    54  	return i.verify(i.Iterator.SeekGE(key, base.SeekGEFlagsNone))
    55  }
    56  
    57  func (i *iterAdapter) SeekLT(key []byte) bool {
    58  	return i.verify(i.Iterator.SeekLT(key))
    59  }
    60  
    61  func (i *iterAdapter) First() bool {
    62  	return i.verify(i.Iterator.First())
    63  }
    64  
    65  func (i *iterAdapter) Last() bool {
    66  	return i.verify(i.Iterator.Last())
    67  }
    68  
    69  func (i *iterAdapter) Next() bool {
    70  	return i.verify(i.Iterator.Next())
    71  }
    72  
    73  func (i *iterAdapter) Prev() bool {
    74  	return i.verify(i.Iterator.Prev())
    75  }
    76  
    77  func (i *iterAdapter) Key() base.InternalKey {
    78  	return *i.Iterator.Key()
    79  }
    80  
    81  // length iterates over skiplist to give exact size.
    82  func length(s *Skiplist) int {
    83  	count := 0
    84  
    85  	it := iterAdapter{s.NewIter(nil, nil)}
    86  	for valid := it.First(); valid; valid = it.Next() {
    87  		count++
    88  	}
    89  
    90  	return count
    91  }
    92  
    93  // length iterates over skiplist in reverse order to give exact size.
    94  func lengthRev(s *Skiplist) int {
    95  	count := 0
    96  
    97  	it := iterAdapter{s.NewIter(nil, nil)}
    98  	for valid := it.Last(); valid; valid = it.Prev() {
    99  		count++
   100  	}
   101  
   102  	return count
   103  }
   104  
   105  func makeKey(s string) []byte {
   106  	return []byte(s)
   107  }
   108  
   109  type testStorage struct {
   110  	data []byte
   111  }
   112  
   113  func (d *testStorage) add(key string) uint32 {
   114  	offset := uint32(len(d.data))
   115  	d.data = append(d.data, uint8(base.InternalKeyKindSet))
   116  	var buf [binary.MaxVarintLen64]byte
   117  	n := binary.PutUvarint(buf[:], uint64(len(key)))
   118  	d.data = append(d.data, buf[:n]...)
   119  	d.data = append(d.data, key...)
   120  	return offset
   121  }
   122  
   123  func (d *testStorage) addBytes(key []byte) uint32 {
   124  	offset := uint32(len(d.data))
   125  	d.data = append(d.data, uint8(base.InternalKeyKindSet))
   126  	var buf [binary.MaxVarintLen64]byte
   127  	n := binary.PutUvarint(buf[:], uint64(len(key)))
   128  	d.data = append(d.data, buf[:n]...)
   129  	d.data = append(d.data, key...)
   130  	return offset
   131  }
   132  
   133  func newTestSkiplist(storage *testStorage) *Skiplist {
   134  	return NewSkiplist(&storage.data, base.DefaultComparer.Compare,
   135  		base.DefaultComparer.AbbreviatedKey)
   136  }
   137  
   138  func TestEmpty(t *testing.T) {
   139  	key := makeKey("aaa")
   140  	l := newTestSkiplist(&testStorage{})
   141  	it := iterAdapter{l.NewIter(nil, nil)}
   142  
   143  	require.False(t, it.Valid())
   144  
   145  	it.First()
   146  	require.False(t, it.Valid())
   147  
   148  	it.Last()
   149  	require.False(t, it.Valid())
   150  
   151  	require.False(t, it.SeekGE(key))
   152  	require.False(t, it.Valid())
   153  }
   154  
   155  // TestBasic tests seeks and adds.
   156  func TestBasic(t *testing.T) {
   157  	d := &testStorage{}
   158  	l := newTestSkiplist(d)
   159  	it := iterAdapter{l.NewIter(nil, nil)}
   160  
   161  	// Try adding values.
   162  	require.Nil(t, l.Add(d.add("key1")))
   163  	require.Nil(t, l.Add(d.add("key2")))
   164  	require.Nil(t, l.Add(d.add("key3")))
   165  
   166  	require.True(t, it.SeekGE(makeKey("key")))
   167  	require.EqualValues(t, "key1", it.Key().UserKey)
   168  
   169  	require.True(t, it.SeekGE(makeKey("key1")))
   170  	require.EqualValues(t, "key1", it.Key().UserKey)
   171  
   172  	require.True(t, it.SeekGE(makeKey("key2")))
   173  	require.EqualValues(t, "key2", it.Key().UserKey)
   174  
   175  	require.True(t, it.SeekGE(makeKey("key3")))
   176  	require.EqualValues(t, "key3", it.Key().UserKey)
   177  
   178  	require.True(t, it.SeekGE(makeKey("key2")))
   179  	require.True(t, it.SeekGE(makeKey("key3")))
   180  }
   181  
   182  func TestSkiplistAdd(t *testing.T) {
   183  	d := &testStorage{}
   184  	l := newTestSkiplist(d)
   185  	it := iterAdapter{l.NewIter(nil, nil)}
   186  
   187  	// Add empty key.
   188  	require.Nil(t, l.Add(d.add("")))
   189  	require.EqualValues(t, []byte(nil), it.Key().UserKey)
   190  	require.True(t, it.First())
   191  	require.EqualValues(t, []byte{}, it.Key().UserKey)
   192  
   193  	// Add to empty list.
   194  	require.Nil(t, l.Add(d.add("00002")))
   195  	require.True(t, it.SeekGE(makeKey("00002")))
   196  	require.EqualValues(t, "00002", it.Key().UserKey)
   197  
   198  	// Add first element in non-empty list.
   199  	require.Nil(t, l.Add(d.add("00001")))
   200  	require.True(t, it.SeekGE(makeKey("00001")))
   201  	require.EqualValues(t, "00001", it.Key().UserKey)
   202  
   203  	// Add last element in non-empty list.
   204  	require.Nil(t, l.Add(d.add("00004")))
   205  	require.True(t, it.SeekGE(makeKey("00004")))
   206  	require.EqualValues(t, "00004", it.Key().UserKey)
   207  
   208  	// Add element in middle of list.
   209  	require.Nil(t, l.Add(d.add("00003")))
   210  	require.True(t, it.SeekGE(makeKey("00003")))
   211  	require.EqualValues(t, "00003", it.Key().UserKey)
   212  
   213  	// Try to add element that already exists.
   214  	require.Nil(t, l.Add(d.add("00002")))
   215  	require.Equal(t, 6, length(l))
   216  	require.Equal(t, 6, lengthRev(l))
   217  }
   218  
   219  func TestSkiplistAdd_Overflow(t *testing.T) {
   220  	// Regression test for cockroachdb/pebble#1258. The length of the nodes buffer
   221  	// cannot exceed the maximum allowable size.
   222  	d := &testStorage{}
   223  	l := newTestSkiplist(d)
   224  
   225  	// Simulate a full nodes slice. This speeds up the test significantly, as
   226  	// opposed to adding data to the list.
   227  	l.nodes = make([]byte, maxNodesSize)
   228  
   229  	// Adding a new node to the list would overflow the nodes slice. Note that it
   230  	// is the size of a new node struct that is relevant here, rather than the
   231  	// size of the data being added to the list.
   232  	err := l.Add(d.add("too much!"))
   233  	require.Error(t, err)
   234  	require.True(t, errors.Is(err, ErrTooManyRecords))
   235  }
   236  
   237  // TestIteratorNext tests a basic iteration over all nodes from the beginning.
   238  func TestIteratorNext(t *testing.T) {
   239  	const n = 100
   240  	d := &testStorage{}
   241  	l := newTestSkiplist(d)
   242  	it := iterAdapter{l.NewIter(nil, nil)}
   243  
   244  	require.False(t, it.Valid())
   245  
   246  	it.First()
   247  	require.False(t, it.Valid())
   248  
   249  	for i := n - 1; i >= 0; i-- {
   250  		require.Nil(t, l.Add(d.add(fmt.Sprintf("%05d", i))))
   251  	}
   252  
   253  	it.First()
   254  	for i := 0; i < n; i++ {
   255  		require.True(t, it.Valid())
   256  		require.EqualValues(t, fmt.Sprintf("%05d", i), it.Key().UserKey)
   257  		it.Next()
   258  	}
   259  	require.False(t, it.Valid())
   260  }
   261  
   262  // // TestIteratorPrev tests a basic iteration over all nodes from the end.
   263  func TestIteratorPrev(t *testing.T) {
   264  	const n = 100
   265  	d := &testStorage{}
   266  	l := newTestSkiplist(d)
   267  	it := iterAdapter{l.NewIter(nil, nil)}
   268  
   269  	require.False(t, it.Valid())
   270  
   271  	it.Last()
   272  	require.False(t, it.Valid())
   273  
   274  	for i := 0; i < n; i++ {
   275  		l.Add(d.add(fmt.Sprintf("%05d", i)))
   276  	}
   277  
   278  	it.Last()
   279  	for i := n - 1; i >= 0; i-- {
   280  		require.True(t, it.Valid())
   281  		require.EqualValues(t, fmt.Sprintf("%05d", i), string(it.Key().UserKey))
   282  		it.Prev()
   283  	}
   284  	require.False(t, it.Valid())
   285  }
   286  
   287  func TestIteratorSeekGE(t *testing.T) {
   288  	const n = 1000
   289  	d := &testStorage{}
   290  	l := newTestSkiplist(d)
   291  	it := iterAdapter{l.NewIter(nil, nil)}
   292  
   293  	require.False(t, it.Valid())
   294  	it.First()
   295  	require.False(t, it.Valid())
   296  	// 1000, 1010, 1020, ..., 1990.
   297  	for i := n - 1; i >= 0; i-- {
   298  		require.Nil(t, l.Add(d.add(fmt.Sprintf("%05d", i*10+1000))))
   299  	}
   300  
   301  	require.True(t, it.SeekGE(makeKey("")))
   302  	require.True(t, it.Valid())
   303  	require.EqualValues(t, "01000", it.Key().UserKey)
   304  
   305  	require.True(t, it.SeekGE(makeKey("01000")))
   306  	require.True(t, it.Valid())
   307  	require.EqualValues(t, "01000", it.Key().UserKey)
   308  
   309  	require.True(t, it.SeekGE(makeKey("01005")))
   310  	require.True(t, it.Valid())
   311  	require.EqualValues(t, "01010", it.Key().UserKey)
   312  
   313  	require.True(t, it.SeekGE(makeKey("01010")))
   314  	require.True(t, it.Valid())
   315  	require.EqualValues(t, "01010", it.Key().UserKey)
   316  
   317  	require.False(t, it.SeekGE(makeKey("99999")))
   318  	require.False(t, it.Valid())
   319  
   320  	// Test seek for empty key.
   321  	require.Nil(t, l.Add(d.add("")))
   322  	require.True(t, it.SeekGE([]byte{}))
   323  	require.True(t, it.Valid())
   324  
   325  	require.True(t, it.SeekGE(makeKey("")))
   326  	require.True(t, it.Valid())
   327  }
   328  
   329  func TestIteratorSeekLT(t *testing.T) {
   330  	const n = 100
   331  	d := &testStorage{}
   332  	l := newTestSkiplist(d)
   333  	it := iterAdapter{l.NewIter(nil, nil)}
   334  
   335  	require.False(t, it.Valid())
   336  	it.First()
   337  	require.False(t, it.Valid())
   338  	// 1000, 1010, 1020, ..., 1990.
   339  	for i := n - 1; i >= 0; i-- {
   340  		require.Nil(t, l.Add(d.add(fmt.Sprintf("%05d", i*10+1000))))
   341  	}
   342  
   343  	require.False(t, it.SeekLT(makeKey("")))
   344  	require.False(t, it.Valid())
   345  
   346  	require.False(t, it.SeekLT(makeKey("01000")))
   347  	require.False(t, it.Valid())
   348  
   349  	require.True(t, it.SeekLT(makeKey("01001")))
   350  	require.EqualValues(t, "01000", it.Key().UserKey)
   351  	require.True(t, it.Valid())
   352  
   353  	require.True(t, it.SeekLT(makeKey("01005")))
   354  	require.EqualValues(t, "01000", it.Key().UserKey)
   355  	require.True(t, it.Valid())
   356  
   357  	require.True(t, it.SeekLT(makeKey("01991")))
   358  	require.EqualValues(t, "01990", it.Key().UserKey)
   359  	require.True(t, it.Valid())
   360  
   361  	require.True(t, it.SeekLT(makeKey("99999")))
   362  	require.True(t, it.Valid())
   363  	require.EqualValues(t, "01990", it.Key().UserKey)
   364  
   365  	// Test seek for empty key.
   366  	require.Nil(t, l.Add(d.add("")))
   367  	require.False(t, it.SeekLT([]byte{}))
   368  	require.False(t, it.Valid())
   369  	require.True(t, it.SeekLT(makeKey("\x01")))
   370  	require.True(t, it.Valid())
   371  	require.EqualValues(t, "", it.Key().UserKey)
   372  }
   373  
   374  // TODO(peter): test First and Last.
   375  func TestIteratorBounds(t *testing.T) {
   376  	d := &testStorage{}
   377  	l := newTestSkiplist(d)
   378  	for i := 1; i < 10; i++ {
   379  		require.NoError(t, l.Add(d.add(fmt.Sprintf("%05d", i))))
   380  	}
   381  
   382  	it := iterAdapter{l.NewIter(makeKey("00003"), makeKey("00007"))}
   383  
   384  	// SeekGE within the lower and upper bound succeeds.
   385  	for i := 3; i <= 6; i++ {
   386  		key := makeKey(fmt.Sprintf("%05d", i))
   387  		require.True(t, it.SeekGE(key))
   388  		require.EqualValues(t, string(key), string(it.Key().UserKey))
   389  	}
   390  
   391  	// SeekGE before the lower bound still succeeds (only the upper bound is
   392  	// checked).
   393  	for i := 1; i < 3; i++ {
   394  		key := makeKey(fmt.Sprintf("%05d", i))
   395  		require.True(t, it.SeekGE(key))
   396  		require.EqualValues(t, string(key), string(it.Key().UserKey))
   397  	}
   398  
   399  	// SeekGE beyond the upper bound fails.
   400  	for i := 7; i < 10; i++ {
   401  		key := makeKey(fmt.Sprintf("%05d", i))
   402  		require.False(t, it.SeekGE(key))
   403  	}
   404  
   405  	require.True(t, it.SeekGE(makeKey("00006")))
   406  	require.EqualValues(t, "00006", it.Key().UserKey)
   407  
   408  	// Next into the upper bound fails.
   409  	require.False(t, it.Next())
   410  
   411  	// SeekLT within the lower and upper bound succeeds.
   412  	for i := 4; i <= 7; i++ {
   413  		key := makeKey(fmt.Sprintf("%05d", i))
   414  		require.True(t, it.SeekLT(key))
   415  		require.EqualValues(t, fmt.Sprintf("%05d", i-1), string(it.Key().UserKey))
   416  	}
   417  
   418  	// SeekLT beyond the upper bound still succeeds (only the lower bound is
   419  	// checked).
   420  	for i := 8; i < 9; i++ {
   421  		key := makeKey(fmt.Sprintf("%05d", i))
   422  		require.True(t, it.SeekLT(key))
   423  		require.EqualValues(t, fmt.Sprintf("%05d", i-1), string(it.Key().UserKey))
   424  	}
   425  
   426  	// SeekLT before the lower bound fails.
   427  	for i := 1; i < 4; i++ {
   428  		key := makeKey(fmt.Sprintf("%05d", i))
   429  		require.False(t, it.SeekLT(key))
   430  	}
   431  
   432  	require.True(t, it.SeekLT(makeKey("00004")))
   433  	require.EqualValues(t, "00003", it.Key().UserKey)
   434  
   435  	// Prev into the lower bound fails.
   436  	require.False(t, it.Prev())
   437  }
   438  
   439  func randomKey(rng *rand.Rand, b []byte) []byte {
   440  	key := rng.Uint32()
   441  	key2 := rng.Uint32()
   442  	binary.LittleEndian.PutUint32(b, key)
   443  	binary.LittleEndian.PutUint32(b[4:], key2)
   444  	return b
   445  }
   446  
   447  // Standard test. Some fraction is read. Some fraction is write. Writes have
   448  // to go through mutex lock.
   449  func BenchmarkReadWrite(b *testing.B) {
   450  	for i := 0; i <= 10; i++ {
   451  		readFrac := float32(i) / 10.0
   452  		b.Run(fmt.Sprintf("frac_%d", i*10), func(b *testing.B) {
   453  			var buf [8]byte
   454  			d := &testStorage{
   455  				data: make([]byte, 0, b.N*10),
   456  			}
   457  			l := newTestSkiplist(d)
   458  			it := l.NewIter(nil, nil)
   459  			rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano())))
   460  
   461  			b.ResetTimer()
   462  			for i := 0; i < b.N; i++ {
   463  				key := randomKey(rng, buf[:])
   464  				if rng.Float32() < readFrac {
   465  					_ = it.SeekGE(key, base.SeekGEFlagsNone)
   466  				} else {
   467  					offset := d.addBytes(buf[:])
   468  					_ = l.Add(offset)
   469  				}
   470  			}
   471  			b.StopTimer()
   472  		})
   473  	}
   474  }
   475  
   476  func BenchmarkOrderedWrite(b *testing.B) {
   477  	var buf [8]byte
   478  	d := &testStorage{
   479  		data: make([]byte, 0, b.N*10),
   480  	}
   481  	l := newTestSkiplist(d)
   482  
   483  	b.ResetTimer()
   484  	for i := 0; i < b.N; i++ {
   485  		binary.BigEndian.PutUint64(buf[:], uint64(i))
   486  		offset := d.addBytes(buf[:])
   487  		_ = l.Add(offset)
   488  	}
   489  }
   490  
   491  func BenchmarkIterNext(b *testing.B) {
   492  	var buf [8]byte
   493  	d := &testStorage{
   494  		data: make([]byte, 0, 64<<10),
   495  	}
   496  	l := newTestSkiplist(d)
   497  
   498  	rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano())))
   499  	for len(d.data)+20 < cap(d.data) {
   500  		key := randomKey(rng, buf[:])
   501  		offset := d.addBytes(key)
   502  		err := l.Add(offset)
   503  		require.NoError(b, err)
   504  	}
   505  
   506  	it := l.NewIter(nil, nil)
   507  	b.ResetTimer()
   508  	for i := 0; i < b.N; i++ {
   509  		if !it.Valid() {
   510  			it.First()
   511  		}
   512  		it.Next()
   513  	}
   514  }
   515  
   516  func BenchmarkIterPrev(b *testing.B) {
   517  	var buf [8]byte
   518  	d := &testStorage{
   519  		data: make([]byte, 0, 64<<10),
   520  	}
   521  	l := newTestSkiplist(d)
   522  
   523  	rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano())))
   524  	for len(d.data)+20 < cap(d.data) {
   525  		key := randomKey(rng, buf[:])
   526  		offset := d.addBytes(key)
   527  		err := l.Add(offset)
   528  		require.NoError(b, err)
   529  	}
   530  
   531  	it := l.NewIter(nil, nil)
   532  	b.ResetTimer()
   533  	for i := 0; i < b.N; i++ {
   534  		if !it.Valid() {
   535  			it.Last()
   536  		}
   537  		it.Prev()
   538  	}
   539  }