github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/internal/base/comparer_test.go (about)

     1  // Copyright 2011 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 base
     6  
     7  import (
     8  	"fmt"
     9  	"slices"
    10  	"testing"
    11  	"time"
    12  
    13  	"golang.org/x/exp/rand"
    14  )
    15  
    16  func TestDefAppendSeparator(t *testing.T) {
    17  	testCases := []struct {
    18  		a, b, want string
    19  	}{
    20  		// Examples from the doc comments.
    21  		{"black", "blue", "blb"},
    22  		{"green", "", "green"},
    23  		// Non-empty b values. The C++ Level-DB code calls these separators.
    24  		{"", "2", ""},
    25  		{"1", "2", "1"},
    26  		{"1", "29", "2"},
    27  		{"13", "19", "14"},
    28  		{"13", "99", "2"},
    29  		{"135", "19", "14"},
    30  		{"1357", "19", "14"},
    31  		{"1357", "2", "14"},
    32  		{"13\xff", "14", "13\xff"},
    33  		{"13\xff", "19", "14"},
    34  		{"1\xff\xff", "19", "1\xff\xff"},
    35  		{"1\xff\xff", "2", "1\xff\xff"},
    36  		{"1\xff\xff", "9", "2"},
    37  		// Empty b values. The C++ Level-DB code calls these successors.
    38  		{"", "", ""},
    39  		{"1", "", "1"},
    40  		{"11", "", "11"},
    41  		{"11\xff", "", "11\xff"},
    42  		{"1\xff", "", "1\xff"},
    43  		{"1\xff\xff", "", "1\xff\xff"},
    44  		{"\xff", "", "\xff"},
    45  		{"\xff\xff", "", "\xff\xff"},
    46  		{"\xff\xff\xff", "", "\xff\xff\xff"},
    47  	}
    48  	for _, tc := range testCases {
    49  		t.Run("", func(t *testing.T) {
    50  			got := string(DefaultComparer.Separator(nil, []byte(tc.a), []byte(tc.b)))
    51  			if got != tc.want {
    52  				t.Errorf("a, b = %q, %q: got %q, want %q", tc.a, tc.b, got, tc.want)
    53  			}
    54  		})
    55  	}
    56  }
    57  
    58  func TestAbbreviatedKey(t *testing.T) {
    59  	rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano())))
    60  	randBytes := func(size int) []byte {
    61  		data := make([]byte, size)
    62  		for i := range data {
    63  			data[i] = byte(rng.Int() & 0xff)
    64  		}
    65  		return data
    66  	}
    67  
    68  	keys := make([][]byte, 10000)
    69  	for i := range keys {
    70  		keys[i] = randBytes(rng.Intn(16))
    71  	}
    72  	slices.SortFunc(keys, DefaultComparer.Compare)
    73  
    74  	for i := 1; i < len(keys); i++ {
    75  		last := DefaultComparer.AbbreviatedKey(keys[i-1])
    76  		cur := DefaultComparer.AbbreviatedKey(keys[i])
    77  		cmp := DefaultComparer.Compare(keys[i-1], keys[i])
    78  		if cmp == 0 {
    79  			if last != cur {
    80  				t.Fatalf("expected equal abbreviated keys: %x[%x] != %x[%x]",
    81  					last, keys[i-1], cur, keys[i])
    82  			}
    83  		} else {
    84  			if last > cur {
    85  				t.Fatalf("unexpected abbreviated key ordering: %x[%x] > %x[%x]",
    86  					last, keys[i-1], cur, keys[i])
    87  			}
    88  		}
    89  	}
    90  }
    91  
    92  func BenchmarkAbbreviatedKey(b *testing.B) {
    93  	rng := rand.New(rand.NewSource(1449168817))
    94  	randBytes := func(size int) []byte {
    95  		data := make([]byte, size)
    96  		for i := range data {
    97  			data[i] = byte(rng.Int() & 0xff)
    98  		}
    99  		return data
   100  	}
   101  	keys := make([][]byte, 10000)
   102  	for i := range keys {
   103  		keys[i] = randBytes(8)
   104  	}
   105  
   106  	b.ResetTimer()
   107  	var sum uint64
   108  	for i := 0; i < b.N; i++ {
   109  		j := i % len(keys)
   110  		sum += DefaultComparer.AbbreviatedKey(keys[j])
   111  	}
   112  
   113  	if testing.Verbose() {
   114  		// Ensure the compiler doesn't optimize away our benchmark.
   115  		fmt.Println(sum)
   116  	}
   117  }