github.com/zuoyebang/bitalostable@v1.0.1-0.20240229032404-e3b99a834294/sstable/block_test.go (about)

     1  // Copyright 2018 The LevelDB-Go and Pebble Authors. All rights reserved. Use
     2  // of this source code is governed by a BSD-style license that can be found in
     3  // the LICENSE file.
     4  
     5  package sstable
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"strconv"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  	"unsafe"
    15  
    16  	"github.com/stretchr/testify/require"
    17  	"github.com/zuoyebang/bitalostable/internal/base"
    18  	"github.com/zuoyebang/bitalostable/internal/datadriven"
    19  	"golang.org/x/exp/rand"
    20  )
    21  
    22  func ikey(s string) InternalKey {
    23  	return InternalKey{UserKey: []byte(s)}
    24  }
    25  
    26  func TestBlockWriter(t *testing.T) {
    27  	w := &rawBlockWriter{
    28  		blockWriter: blockWriter{restartInterval: 16},
    29  	}
    30  	w.add(ikey("apple"), nil)
    31  	w.add(ikey("apricot"), nil)
    32  	w.add(ikey("banana"), nil)
    33  	block := w.finish()
    34  
    35  	expected := []byte(
    36  		"\x00\x05\x00apple" +
    37  			"\x02\x05\x00ricot" +
    38  			"\x00\x06\x00banana" +
    39  			"\x00\x00\x00\x00\x01\x00\x00\x00")
    40  	if !bytes.Equal(expected, block) {
    41  		t.Fatalf("expected\n%q\nfound\n%q", expected, block)
    42  	}
    43  }
    44  
    45  func testBlockCleared(t *testing.T, w, b *blockWriter) {
    46  	require.Equal(t, w.restartInterval, b.restartInterval)
    47  	require.Equal(t, w.nEntries, b.nEntries)
    48  	require.Equal(t, w.nextRestart, b.nextRestart)
    49  	require.Equal(t, len(w.buf), len(b.buf))
    50  	require.Equal(t, len(w.restarts), len(b.restarts))
    51  	require.Equal(t, len(w.curKey), len(b.curKey))
    52  	require.Equal(t, len(w.prevKey), len(b.prevKey))
    53  	require.Equal(t, len(w.curValue), len(b.curValue))
    54  	require.Equal(t, w.tmp, b.tmp)
    55  
    56  	// Make sure that we didn't lose the allocated byte slices.
    57  	require.True(t, cap(w.buf) > 0 && cap(b.buf) == 0)
    58  	require.True(t, cap(w.restarts) > 0 && cap(b.restarts) == 0)
    59  	require.True(t, cap(w.curKey) > 0 && cap(b.curKey) == 0)
    60  	require.True(t, cap(w.prevKey) > 0 && cap(b.prevKey) == 0)
    61  	require.True(t, cap(w.curValue) > 0 && cap(b.curValue) == 0)
    62  }
    63  
    64  func TestBlockClear(t *testing.T) {
    65  	w := blockWriter{restartInterval: 16}
    66  	w.add(ikey("apple"), nil)
    67  	w.add(ikey("apricot"), nil)
    68  	w.add(ikey("banana"), nil)
    69  
    70  	w.clear()
    71  
    72  	// Once a block is cleared, we expect its fields to be cleared, but we expect
    73  	// it to keep its allocated byte slices.
    74  	b := blockWriter{}
    75  	testBlockCleared(t, &w, &b)
    76  }
    77  
    78  func TestInvalidInternalKeyDecoding(t *testing.T) {
    79  	// Invalid keys since they don't have an 8 byte trailer.
    80  	testCases := []string{
    81  		"",
    82  		"\x01\x02\x03\x04\x05\x06\x07",
    83  		"foo",
    84  	}
    85  	for _, tc := range testCases {
    86  		i := blockIter{}
    87  		i.decodeInternalKey([]byte(tc))
    88  		require.Nil(t, i.ikey.UserKey)
    89  		require.Equal(t, uint64(InternalKeyKindInvalid), i.ikey.Trailer)
    90  	}
    91  }
    92  
    93  func TestBlockIter(t *testing.T) {
    94  	// k is a block that maps three keys "apple", "apricot", "banana" to empty strings.
    95  	k := block([]byte(
    96  		"\x00\x05\x00apple" +
    97  			"\x02\x05\x00ricot" +
    98  			"\x00\x06\x00banana" +
    99  			"\x00\x00\x00\x00\x01\x00\x00\x00"))
   100  	var testcases = []struct {
   101  		index int
   102  		key   string
   103  	}{
   104  		{0, ""},
   105  		{0, "a"},
   106  		{0, "aaaaaaaaaaaaaaa"},
   107  		{0, "app"},
   108  		{0, "apple"},
   109  		{1, "appliance"},
   110  		{1, "apricos"},
   111  		{1, "apricot"},
   112  		{2, "azzzzzzzzzzzzzz"},
   113  		{2, "b"},
   114  		{2, "banan"},
   115  		{2, "banana"},
   116  		{3, "banana\x00"},
   117  		{3, "c"},
   118  	}
   119  	for _, tc := range testcases {
   120  		i, err := newRawBlockIter(bytes.Compare, k)
   121  		require.NoError(t, err)
   122  		i.SeekGE([]byte(tc.key))
   123  		for j, keyWant := range []string{"apple", "apricot", "banana"}[tc.index:] {
   124  			if !i.Valid() {
   125  				t.Fatalf("key=%q, index=%d, j=%d: Valid got false, keyWant true", tc.key, tc.index, j)
   126  			}
   127  			if keyGot := string(i.Key().UserKey); keyGot != keyWant {
   128  				t.Fatalf("key=%q, index=%d, j=%d: got %q, keyWant %q", tc.key, tc.index, j, keyGot, keyWant)
   129  			}
   130  			i.Next()
   131  		}
   132  		if i.Valid() {
   133  			t.Fatalf("key=%q, index=%d: Valid got true, keyWant false", tc.key, tc.index)
   134  		}
   135  		if err := i.Close(); err != nil {
   136  			t.Fatalf("key=%q, index=%d: got err=%v", tc.key, tc.index, err)
   137  		}
   138  	}
   139  
   140  	{
   141  		i, err := newRawBlockIter(bytes.Compare, k)
   142  		require.NoError(t, err)
   143  		i.Last()
   144  		for j, keyWant := range []string{"banana", "apricot", "apple"} {
   145  			if !i.Valid() {
   146  				t.Fatalf("j=%d: Valid got false, want true", j)
   147  			}
   148  			if keyGot := string(i.Key().UserKey); keyGot != keyWant {
   149  				t.Fatalf("j=%d: got %q, want %q", j, keyGot, keyWant)
   150  			}
   151  			i.Prev()
   152  		}
   153  		if i.Valid() {
   154  			t.Fatalf("Valid got true, want false")
   155  		}
   156  		if err := i.Close(); err != nil {
   157  			t.Fatalf("got err=%v", err)
   158  		}
   159  	}
   160  }
   161  
   162  func TestBlockIter2(t *testing.T) {
   163  	makeIkey := func(s string) InternalKey {
   164  		j := strings.Index(s, ":")
   165  		seqNum, err := strconv.Atoi(s[j+1:])
   166  		if err != nil {
   167  			panic(err)
   168  		}
   169  		return base.MakeInternalKey([]byte(s[:j]), uint64(seqNum), InternalKeyKindSet)
   170  	}
   171  
   172  	var block []byte
   173  
   174  	for _, r := range []int{1, 2, 3, 4} {
   175  		t.Run(fmt.Sprintf("restart=%d", r), func(t *testing.T) {
   176  			datadriven.RunTest(t, "testdata/block", func(d *datadriven.TestData) string {
   177  				switch d.Cmd {
   178  				case "build":
   179  					w := &blockWriter{restartInterval: r}
   180  					for _, e := range strings.Split(strings.TrimSpace(d.Input), ",") {
   181  						w.add(makeIkey(e), nil)
   182  					}
   183  					block = w.finish()
   184  					return ""
   185  
   186  				case "iter":
   187  					iter, err := newBlockIter(bytes.Compare, block)
   188  					if err != nil {
   189  						return err.Error()
   190  					}
   191  
   192  					iter.globalSeqNum, err = scanGlobalSeqNum(d)
   193  					if err != nil {
   194  						return err.Error()
   195  					}
   196  
   197  					var b bytes.Buffer
   198  					for _, line := range strings.Split(d.Input, "\n") {
   199  						parts := strings.Fields(line)
   200  						if len(parts) == 0 {
   201  							continue
   202  						}
   203  						switch parts[0] {
   204  						case "seek-ge":
   205  							if len(parts) != 2 {
   206  								return "seek-ge <key>\n"
   207  							}
   208  							iter.SeekGE([]byte(strings.TrimSpace(parts[1])), base.SeekGEFlagsNone)
   209  						case "seek-lt":
   210  							if len(parts) != 2 {
   211  								return "seek-lt <key>\n"
   212  							}
   213  							iter.SeekLT([]byte(strings.TrimSpace(parts[1])), base.SeekLTFlagsNone)
   214  						case "first":
   215  							iter.First()
   216  						case "last":
   217  							iter.Last()
   218  						case "next":
   219  							iter.Next()
   220  						case "prev":
   221  							iter.Prev()
   222  						}
   223  						if iter.valid() {
   224  							fmt.Fprintf(&b, "<%s:%d>", iter.Key().UserKey, iter.Key().SeqNum())
   225  						} else if err := iter.Error(); err != nil {
   226  							fmt.Fprintf(&b, "<err=%v>", err)
   227  						} else {
   228  							fmt.Fprintf(&b, ".")
   229  						}
   230  					}
   231  					b.WriteString("\n")
   232  					return b.String()
   233  
   234  				default:
   235  					return fmt.Sprintf("unknown command: %s", d.Cmd)
   236  				}
   237  			})
   238  		})
   239  	}
   240  }
   241  
   242  func TestBlockIterKeyStability(t *testing.T) {
   243  	w := &blockWriter{restartInterval: 1}
   244  	expected := [][]byte{
   245  		[]byte("apple"),
   246  		[]byte("apricot"),
   247  		[]byte("banana"),
   248  	}
   249  	for i := range expected {
   250  		w.add(InternalKey{UserKey: expected[i]}, nil)
   251  	}
   252  	block := w.finish()
   253  
   254  	i, err := newBlockIter(bytes.Compare, block)
   255  	require.NoError(t, err)
   256  
   257  	// Check that the supplied slice resides within the bounds of the block.
   258  	check := func(v []byte) {
   259  		t.Helper()
   260  		begin := unsafe.Pointer(&v[0])
   261  		end := unsafe.Pointer(uintptr(begin) + uintptr(len(v)))
   262  		blockBegin := unsafe.Pointer(&block[0])
   263  		blockEnd := unsafe.Pointer(uintptr(blockBegin) + uintptr(len(block)))
   264  		if uintptr(begin) < uintptr(blockBegin) || uintptr(end) > uintptr(blockEnd) {
   265  			t.Fatalf("key %p-%p resides outside of block %p-%p", begin, end, blockBegin, blockEnd)
   266  		}
   267  	}
   268  
   269  	// Check that various means of iterating over the data match our expected
   270  	// values. Note that this is only guaranteed because of the usage of a
   271  	// restart-interval of 1 so that prefix compression was not performed.
   272  	for j := range expected {
   273  		keys := [][]byte{}
   274  		for key, _ := i.SeekGE(expected[j], base.SeekGEFlagsNone); key != nil; key, _ = i.Next() {
   275  			check(key.UserKey)
   276  			keys = append(keys, key.UserKey)
   277  		}
   278  		require.EqualValues(t, expected[j:], keys)
   279  	}
   280  
   281  	for j := range expected {
   282  		keys := [][]byte{}
   283  		for key, _ := i.SeekLT(expected[j], base.SeekLTFlagsNone); key != nil; key, _ = i.Prev() {
   284  			check(key.UserKey)
   285  			keys = append(keys, key.UserKey)
   286  		}
   287  		for i, j := 0, len(keys)-1; i < j; i, j = i+1, j-1 {
   288  			keys[i], keys[j] = keys[j], keys[i]
   289  		}
   290  		require.EqualValues(t, expected[:j], keys)
   291  	}
   292  }
   293  
   294  // Regression test for a bug in blockIter.Next where it was failing to handle
   295  // the case where it is switching from reverse to forward iteration. When that
   296  // switch occurs we need to populate blockIter.fullKey so that prefix
   297  // decompression works properly.
   298  func TestBlockIterReverseDirections(t *testing.T) {
   299  	w := &blockWriter{restartInterval: 4}
   300  	keys := [][]byte{
   301  		[]byte("apple0"),
   302  		[]byte("apple1"),
   303  		[]byte("apple2"),
   304  		[]byte("banana"),
   305  		[]byte("carrot"),
   306  	}
   307  	for i := range keys {
   308  		w.add(InternalKey{UserKey: keys[i]}, nil)
   309  	}
   310  	block := w.finish()
   311  
   312  	for targetPos := 0; targetPos < w.restartInterval; targetPos++ {
   313  		t.Run("", func(t *testing.T) {
   314  			i, err := newBlockIter(bytes.Compare, block)
   315  			require.NoError(t, err)
   316  
   317  			pos := 3
   318  			if key, _ := i.SeekLT([]byte("carrot"), base.SeekLTFlagsNone); !bytes.Equal(keys[pos], key.UserKey) {
   319  				t.Fatalf("expected %s, but found %s", keys[pos], key.UserKey)
   320  			}
   321  			for pos > targetPos {
   322  				pos--
   323  				if key, _ := i.Prev(); !bytes.Equal(keys[pos], key.UserKey) {
   324  					t.Fatalf("expected %s, but found %s", keys[pos], key.UserKey)
   325  				}
   326  			}
   327  			pos++
   328  			if key, _ := i.Next(); !bytes.Equal(keys[pos], key.UserKey) {
   329  				t.Fatalf("expected %s, but found %s", keys[pos], key.UserKey)
   330  			}
   331  		})
   332  	}
   333  }
   334  
   335  func BenchmarkBlockIterSeekGE(b *testing.B) {
   336  	const blockSize = 32 << 10
   337  
   338  	for _, restartInterval := range []int{16} {
   339  		b.Run(fmt.Sprintf("restart=%d", restartInterval),
   340  			func(b *testing.B) {
   341  				w := &blockWriter{
   342  					restartInterval: restartInterval,
   343  				}
   344  
   345  				var ikey InternalKey
   346  				var keys [][]byte
   347  				for i := 0; w.estimatedSize() < blockSize; i++ {
   348  					key := []byte(fmt.Sprintf("%05d", i))
   349  					keys = append(keys, key)
   350  					ikey.UserKey = key
   351  					w.add(ikey, nil)
   352  				}
   353  
   354  				it, err := newBlockIter(bytes.Compare, w.finish())
   355  				if err != nil {
   356  					b.Fatal(err)
   357  				}
   358  				rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano())))
   359  
   360  				b.ResetTimer()
   361  				for i := 0; i < b.N; i++ {
   362  					k := keys[rng.Intn(len(keys))]
   363  					it.SeekGE(k, base.SeekGEFlagsNone)
   364  					if testing.Verbose() {
   365  						if !it.valid() {
   366  							b.Fatal("expected to find key")
   367  						}
   368  						if !bytes.Equal(k, it.Key().UserKey) {
   369  							b.Fatalf("expected %s, but found %s", k, it.Key().UserKey)
   370  						}
   371  					}
   372  				}
   373  			})
   374  	}
   375  }
   376  
   377  func BenchmarkBlockIterSeekLT(b *testing.B) {
   378  	const blockSize = 32 << 10
   379  
   380  	for _, restartInterval := range []int{16} {
   381  		b.Run(fmt.Sprintf("restart=%d", restartInterval),
   382  			func(b *testing.B) {
   383  				w := &blockWriter{
   384  					restartInterval: restartInterval,
   385  				}
   386  
   387  				var ikey InternalKey
   388  				var keys [][]byte
   389  				for i := 0; w.estimatedSize() < blockSize; i++ {
   390  					key := []byte(fmt.Sprintf("%05d", i))
   391  					keys = append(keys, key)
   392  					ikey.UserKey = key
   393  					w.add(ikey, nil)
   394  				}
   395  
   396  				it, err := newBlockIter(bytes.Compare, w.finish())
   397  				if err != nil {
   398  					b.Fatal(err)
   399  				}
   400  				rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano())))
   401  
   402  				b.ResetTimer()
   403  				for i := 0; i < b.N; i++ {
   404  					j := rng.Intn(len(keys))
   405  					it.SeekLT(keys[j], base.SeekLTFlagsNone)
   406  					if testing.Verbose() {
   407  						if j == 0 {
   408  							if it.valid() {
   409  								b.Fatal("unexpected key")
   410  							}
   411  						} else {
   412  							if !it.valid() {
   413  								b.Fatal("expected to find key")
   414  							}
   415  							k := keys[j-1]
   416  							if !bytes.Equal(k, it.Key().UserKey) {
   417  								b.Fatalf("expected %s, but found %s", k, it.Key().UserKey)
   418  							}
   419  						}
   420  					}
   421  				}
   422  			})
   423  	}
   424  }
   425  
   426  func BenchmarkBlockIterNext(b *testing.B) {
   427  	const blockSize = 32 << 10
   428  
   429  	for _, restartInterval := range []int{16} {
   430  		b.Run(fmt.Sprintf("restart=%d", restartInterval),
   431  			func(b *testing.B) {
   432  				w := &blockWriter{
   433  					restartInterval: restartInterval,
   434  				}
   435  
   436  				var ikey InternalKey
   437  				for i := 0; w.estimatedSize() < blockSize; i++ {
   438  					ikey.UserKey = []byte(fmt.Sprintf("%05d", i))
   439  					w.add(ikey, nil)
   440  				}
   441  
   442  				it, err := newBlockIter(bytes.Compare, w.finish())
   443  				if err != nil {
   444  					b.Fatal(err)
   445  				}
   446  
   447  				b.ResetTimer()
   448  				for i := 0; i < b.N; i++ {
   449  					if !it.valid() {
   450  						it.First()
   451  					}
   452  					it.Next()
   453  				}
   454  			})
   455  	}
   456  }
   457  
   458  func BenchmarkBlockIterPrev(b *testing.B) {
   459  	const blockSize = 32 << 10
   460  
   461  	for _, restartInterval := range []int{16} {
   462  		b.Run(fmt.Sprintf("restart=%d", restartInterval),
   463  			func(b *testing.B) {
   464  				w := &blockWriter{
   465  					restartInterval: restartInterval,
   466  				}
   467  
   468  				var ikey InternalKey
   469  				for i := 0; w.estimatedSize() < blockSize; i++ {
   470  					ikey.UserKey = []byte(fmt.Sprintf("%05d", i))
   471  					w.add(ikey, nil)
   472  				}
   473  
   474  				it, err := newBlockIter(bytes.Compare, w.finish())
   475  				if err != nil {
   476  					b.Fatal(err)
   477  				}
   478  
   479  				b.ResetTimer()
   480  				for i := 0; i < b.N; i++ {
   481  					if !it.valid() {
   482  						it.Last()
   483  					}
   484  					it.Prev()
   485  				}
   486  			})
   487  	}
   488  }