github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/tscache/interval_skl_test.go (about)

     1  // Copyright 2017 Andy Kimball
     2  // Copyright 2017 The Cockroach Authors.
     3  //
     4  // Use of this software is governed by the Business Source License
     5  // included in the file licenses/BSL.txt.
     6  //
     7  // As of the Change Date specified in that file, in accordance with
     8  // the Business Source License, use of this software will be governed
     9  // by the Apache License, Version 2.0, included in the file
    10  // licenses/APL.txt.
    11  
    12  package tscache
    13  
    14  import (
    15  	"bytes"
    16  	"fmt"
    17  	"math"
    18  	"math/rand"
    19  	"runtime"
    20  	"sync"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/andy-kimball/arenaskl"
    25  	"github.com/cockroachdb/cockroach/pkg/testutils"
    26  	"github.com/cockroachdb/cockroach/pkg/util"
    27  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    28  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    29  	"github.com/cockroachdb/cockroach/pkg/util/timeutil"
    30  	"github.com/cockroachdb/cockroach/pkg/util/uuid"
    31  	"github.com/stretchr/testify/require"
    32  )
    33  
    34  var (
    35  	emptyVal = cacheValue{}
    36  	floorTS  = makeTS(100, 0)
    37  	floorVal = makeValWithoutID(floorTS)
    38  )
    39  
    40  func makeTS(walltime int64, logical int32) hlc.Timestamp {
    41  	return hlc.Timestamp{WallTime: walltime, Logical: logical}
    42  }
    43  
    44  func makeValWithoutID(ts hlc.Timestamp) cacheValue {
    45  	return cacheValue{ts: ts, txnID: noTxnID}
    46  }
    47  
    48  func makeVal(ts hlc.Timestamp, txnIDStr string) cacheValue {
    49  	txnIDBytes := []byte(txnIDStr)
    50  	if len(txnIDBytes) < 16 {
    51  		// If too short, pad front with zeros.
    52  		oldTxnIDBytes := txnIDBytes
    53  		txnIDBytes = make([]byte, 16)
    54  		copy(txnIDBytes[16-len(oldTxnIDBytes):], oldTxnIDBytes)
    55  	}
    56  	txnID, err := uuid.FromBytes(txnIDBytes)
    57  	if err != nil {
    58  		panic(err)
    59  	}
    60  	return cacheValue{ts: ts, txnID: txnID}
    61  }
    62  
    63  func makeSklMetrics() sklMetrics {
    64  	return makeMetrics().Skl
    65  }
    66  
    67  // setFixedPageSize sets the pageSize of the intervalSkl to a fixed value.
    68  func (s *intervalSkl) setFixedPageSize(pageSize uint32) {
    69  	s.pageSize = pageSize
    70  	s.pageSizeFixed = true
    71  	s.pages.Init() // clear
    72  	s.pushNewPage(0 /* maxWallTime */, nil /* arena */)
    73  }
    74  
    75  // setMinPages sets the minimum number of pages intervalSkl will evict down to.
    76  // This is only exposed as a testing method because there's no reason to use
    77  // this outside of testing.
    78  func (s *intervalSkl) setMinPages(minPages int) {
    79  	s.minPages = minPages
    80  }
    81  
    82  func TestIntervalSklAdd(t *testing.T) {
    83  	ts1 := makeTS(200, 0)
    84  	ts2 := makeTS(200, 201)
    85  	ts3Ceil := makeTS(201, 0)
    86  
    87  	val1 := makeVal(ts1, "1")
    88  	val2 := makeVal(ts2, "2")
    89  
    90  	s := newIntervalSkl(nil /* clock */, 0 /* minRet */, makeSklMetrics())
    91  
    92  	s.Add([]byte("apricot"), val1)
    93  	require.Equal(t, ts1.WallTime, s.frontPage().maxWallTime)
    94  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("apple")))
    95  	require.Equal(t, val1, s.LookupTimestamp([]byte("apricot")))
    96  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("banana")))
    97  
    98  	s.Add([]byte("banana"), val2)
    99  	require.Equal(t, ts3Ceil.WallTime, s.frontPage().maxWallTime)
   100  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("apple")))
   101  	require.Equal(t, val1, s.LookupTimestamp([]byte("apricot")))
   102  	require.Equal(t, val2, s.LookupTimestamp([]byte("banana")))
   103  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("cherry")))
   104  }
   105  
   106  func TestIntervalSklSingleRange(t *testing.T) {
   107  	val1 := makeVal(makeTS(100, 10), "1")
   108  	val2 := makeVal(makeTS(200, 50), "2")
   109  	val3 := makeVal(makeTS(300, 50), "3")
   110  	val4 := makeVal(makeTS(400, 50), "4")
   111  
   112  	s := newIntervalSkl(nil /* clock */, 0 /* minRet */, makeSklMetrics())
   113  
   114  	// val1:  [a--------------o]
   115  	s.AddRange([]byte("apricot"), []byte("orange"), 0, val1)
   116  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("apple")))
   117  	require.Equal(t, val1, s.LookupTimestamp([]byte("apricot")))
   118  	require.Equal(t, val1, s.LookupTimestamp([]byte("banana")))
   119  	require.Equal(t, val1, s.LookupTimestamp([]byte("orange")))
   120  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("raspberry")))
   121  
   122  	// Try again and make sure it's a no-op.
   123  	// val1:  [a--------------o]
   124  	s.AddRange([]byte("apricot"), []byte("orange"), 0, val1)
   125  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("apple")))
   126  	require.Equal(t, val1, s.LookupTimestamp([]byte("apricot")))
   127  	require.Equal(t, val1, s.LookupTimestamp([]byte("banana")))
   128  	require.Equal(t, val1, s.LookupTimestamp([]byte("orange")))
   129  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("raspberry")))
   130  
   131  	// Ratchet up the timestamps.
   132  	// val1:  [a--------------o]
   133  	// val2:  [a--------------o]
   134  	s.AddRange([]byte("apricot"), []byte("orange"), 0, val2)
   135  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("apple")))
   136  	require.Equal(t, val2, s.LookupTimestamp([]byte("apricot")))
   137  	require.Equal(t, val2, s.LookupTimestamp([]byte("banana")))
   138  	require.Equal(t, val2, s.LookupTimestamp([]byte("orange")))
   139  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("raspberry")))
   140  
   141  	// Add disjoint open range.
   142  	// val1:  [a--------------o]  (p--------------t)
   143  	// val2:  [a--------------o]
   144  	s.AddRange([]byte("pear"), []byte("tomato"), excludeFrom|excludeTo, val1)
   145  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("peach")))
   146  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("pear")))
   147  	require.Equal(t, val1, s.LookupTimestamp([]byte("raspberry")))
   148  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("tomato")))
   149  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("watermelon")))
   150  
   151  	// Try again and make sure it's a no-op.
   152  	// val1:  [a--------------o]  (p--------------t)
   153  	// val2:  [a--------------o]
   154  	s.AddRange([]byte("pear"), []byte("tomato"), excludeFrom|excludeTo, val1)
   155  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("peach")))
   156  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("pear")))
   157  	require.Equal(t, val1, s.LookupTimestamp([]byte("raspberry")))
   158  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("tomato")))
   159  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("watermelon")))
   160  
   161  	// Ratchet up the timestamps.
   162  	// val1:  [a--------------o]  (p--------------t)
   163  	// val2:  [a--------------o]  (p--------------t)
   164  	s.AddRange([]byte("pear"), []byte("tomato"), excludeFrom|excludeTo, val2)
   165  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("peach")))
   166  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("pear")))
   167  	require.Equal(t, val2, s.LookupTimestamp([]byte("raspberry")))
   168  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("tomato")))
   169  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("watermelon")))
   170  
   171  	// Add disjoint left-open range.
   172  	// val1:  [a--------------o]  (p--------------t)
   173  	// val2:  [a--------------o]  (p--------------t)
   174  	// val3:                                     (t--------------w]
   175  	s.AddRange([]byte("tomato"), []byte("watermelon"), excludeFrom, val3)
   176  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("peach")))
   177  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("pear")))
   178  	require.Equal(t, val2, s.LookupTimestamp([]byte("raspberry")))
   179  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("tomato")))
   180  	require.Equal(t, val3, s.LookupTimestamp([]byte("watermelon")))
   181  
   182  	// Add disjoint right-open range.
   183  	// val1:  [a--------------o]      (p--------------t)
   184  	// val2:  [a--------------o]      (p--------------t)
   185  	// val3:                                         (t--------------w]
   186  	// val4:                      [p--p)
   187  	s.AddRange([]byte("peach"), []byte("pear"), excludeTo, val4)
   188  	require.Equal(t, val4, s.LookupTimestamp([]byte("peach")))
   189  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("pear")))
   190  	require.Equal(t, val2, s.LookupTimestamp([]byte("raspberry")))
   191  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("tomato")))
   192  	require.Equal(t, val3, s.LookupTimestamp([]byte("watermelon")))
   193  }
   194  
   195  func TestIntervalSklKeyBoundaries(t *testing.T) {
   196  	val1 := makeVal(makeTS(200, 200), "1")
   197  	val2 := makeVal(makeTS(200, 201), "2")
   198  	val3 := makeVal(makeTS(300, 0), "3")
   199  	val4 := makeVal(makeTS(400, 0), "4")
   200  	val5 := makeVal(makeTS(500, 0), "5")
   201  
   202  	s := newIntervalSkl(nil /* clock */, 0 /* minRet */, makeSklMetrics())
   203  	s.floorTS = floorTS
   204  
   205  	// Can't insert a key at infinity.
   206  	require.Panics(t, func() { s.Add([]byte(nil), val1) })
   207  	require.Panics(t, func() { s.AddRange([]byte(nil), []byte(nil), 0, val1) })
   208  	require.Panics(t, func() { s.AddRange([]byte(nil), []byte(nil), excludeFrom, val1) })
   209  	require.Panics(t, func() { s.AddRange([]byte(nil), []byte(nil), excludeTo, val1) })
   210  	require.Panics(t, func() { s.AddRange([]byte(nil), []byte(nil), excludeFrom|excludeTo, val1) })
   211  
   212  	// Can't lookup a key at infinity.
   213  	require.Panics(t, func() { s.LookupTimestamp([]byte(nil)) })
   214  	require.Panics(t, func() { s.LookupTimestampRange([]byte(nil), []byte(nil), 0) })
   215  	require.Panics(t, func() { s.LookupTimestampRange([]byte(nil), []byte(nil), excludeFrom) })
   216  	require.Panics(t, func() { s.LookupTimestampRange([]byte(nil), []byte(nil), excludeTo) })
   217  	require.Panics(t, func() { s.LookupTimestampRange([]byte(nil), []byte(nil), excludeFrom|excludeTo) })
   218  
   219  	// Single timestamp at minimum key.
   220  	// val1:  [""]
   221  	s.Add([]byte(""), val1)
   222  	require.Equal(t, val1, s.LookupTimestamp([]byte("")))
   223  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("apple")))
   224  
   225  	// Range extending to infinity. excludeTo doesn't make a difference because
   226  	// the boundary is open.
   227  	// val1:  [""]
   228  	// val2:       [b----------->
   229  	s.AddRange([]byte("banana"), nil, excludeTo, val2)
   230  	require.Equal(t, val1, s.LookupTimestamp([]byte("")))
   231  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("apple")))
   232  	require.Equal(t, val2, s.LookupTimestamp([]byte("banana")))
   233  	require.Equal(t, val2, s.LookupTimestamp([]byte("orange")))
   234  
   235  	// val1:  [""]
   236  	// val2:       [b----------->
   237  	// val3:       [b----------->
   238  	s.AddRange([]byte("banana"), nil, 0, val3)
   239  	require.Equal(t, val1, s.LookupTimestamp([]byte("")))
   240  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("apple")))
   241  	require.Equal(t, val3, s.LookupTimestamp([]byte("banana")))
   242  	require.Equal(t, val3, s.LookupTimestamp([]byte("orange")))
   243  
   244  	// Range starting at the minimum key. excludeFrom makes a difference because
   245  	// the boundary is closed.
   246  	// val1:  [""]
   247  	// val2:       [b----------->
   248  	// val3:       [b----------->
   249  	// val4:  (""----------k]
   250  	s.AddRange([]byte(""), []byte("kiwi"), excludeFrom, val4)
   251  	require.Equal(t, val1, s.LookupTimestamp([]byte("")))
   252  	require.Equal(t, val4, s.LookupTimestamp([]byte("banana")))
   253  	require.Equal(t, val4, s.LookupTimestamp([]byte("kiwi")))
   254  	require.Equal(t, val3, s.LookupTimestamp([]byte("orange")))
   255  
   256  	// val1:  [""]
   257  	// val2:       [b----------->
   258  	// val3:       [b----------->
   259  	// val4:  (""----------k]
   260  	// val5:  [""----------k]
   261  	s.AddRange([]byte(""), []byte("kiwi"), 0, val5)
   262  	require.Equal(t, val5, s.LookupTimestamp([]byte("")))
   263  	require.Equal(t, val5, s.LookupTimestamp([]byte("banana")))
   264  	require.Equal(t, val5, s.LookupTimestamp([]byte("kiwi")))
   265  	require.Equal(t, val3, s.LookupTimestamp([]byte("orange")))
   266  }
   267  
   268  func TestIntervalSklSupersetRange(t *testing.T) {
   269  	val1 := makeVal(makeTS(200, 1), "1")
   270  	val2 := makeVal(makeTS(201, 0), "2")
   271  	val3 := makeVal(makeTS(300, 0), "3")
   272  	val4 := makeVal(makeTS(400, 0), "4")
   273  	val5 := makeVal(makeTS(500, 0), "5")
   274  	val6 := makeVal(makeTS(600, 0), "6")
   275  
   276  	s := newIntervalSkl(nil /* clock */, 0 /* minRet */, makeSklMetrics())
   277  	s.floorTS = floorTS
   278  
   279  	// Same range.
   280  	// val1:  [k---------o]
   281  	// val2:  [k---------o]
   282  	s.AddRange([]byte("kiwi"), []byte("orange"), 0, val1)
   283  	s.AddRange([]byte("kiwi"), []byte("orange"), 0, val2)
   284  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("apple")))
   285  	require.Equal(t, val2, s.LookupTimestamp([]byte("kiwi")))
   286  	require.Equal(t, val2, s.LookupTimestamp([]byte("mango")))
   287  	require.Equal(t, val2, s.LookupTimestamp([]byte("orange")))
   288  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("raspberry")))
   289  
   290  	// Superset range, but with lower timestamp.
   291  	// val1:  [g--------------p]
   292  	// val2:    [k---------o]
   293  	s.AddRange([]byte("grape"), []byte("pear"), 0, val1)
   294  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("apple")))
   295  	require.Equal(t, val1, s.LookupTimestamp([]byte("grape")))
   296  	require.Equal(t, val2, s.LookupTimestamp([]byte("kiwi")))
   297  	require.Equal(t, val2, s.LookupTimestamp([]byte("orange")))
   298  	require.Equal(t, val1, s.LookupTimestamp([]byte("pear")))
   299  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("watermelon")))
   300  
   301  	// Superset range, but with higher timestamp.
   302  	// val1:    [g--------------p]
   303  	// val2:      [k---------o]
   304  	// val3: [b-------------------r]
   305  	s.AddRange([]byte("banana"), []byte("raspberry"), 0, val3)
   306  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("apple")))
   307  	require.Equal(t, val3, s.LookupTimestamp([]byte("banana")))
   308  	require.Equal(t, val3, s.LookupTimestamp([]byte("grape")))
   309  	require.Equal(t, val3, s.LookupTimestamp([]byte("kiwi")))
   310  	require.Equal(t, val3, s.LookupTimestamp([]byte("orange")))
   311  	require.Equal(t, val3, s.LookupTimestamp([]byte("pear")))
   312  	require.Equal(t, val3, s.LookupTimestamp([]byte("raspberry")))
   313  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("watermelon")))
   314  
   315  	// Equal range but left-open.
   316  	// val1:    [g--------------p]
   317  	// val2:      [k---------o]
   318  	// val3: [b-------------------r]
   319  	// val4: (b-------------------r]
   320  	s.AddRange([]byte("banana"), []byte("raspberry"), excludeFrom, val4)
   321  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("apple")))
   322  	require.Equal(t, val3, s.LookupTimestamp([]byte("banana")))
   323  	require.Equal(t, val4, s.LookupTimestamp([]byte("grape")))
   324  	require.Equal(t, val4, s.LookupTimestamp([]byte("kiwi")))
   325  	require.Equal(t, val4, s.LookupTimestamp([]byte("orange")))
   326  	require.Equal(t, val4, s.LookupTimestamp([]byte("pear")))
   327  	require.Equal(t, val4, s.LookupTimestamp([]byte("raspberry")))
   328  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("watermelon")))
   329  
   330  	// Equal range but right-open.
   331  	// val1:    [g--------------p]
   332  	// val2:      [k---------o]
   333  	// val3: [b-------------------r]
   334  	// val4: (b-------------------r]
   335  	// val5: [b-------------------r)
   336  	s.AddRange([]byte("banana"), []byte("raspberry"), excludeTo, val5)
   337  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("apple")))
   338  	require.Equal(t, val5, s.LookupTimestamp([]byte("banana")))
   339  	require.Equal(t, val5, s.LookupTimestamp([]byte("grape")))
   340  	require.Equal(t, val5, s.LookupTimestamp([]byte("kiwi")))
   341  	require.Equal(t, val5, s.LookupTimestamp([]byte("orange")))
   342  	require.Equal(t, val5, s.LookupTimestamp([]byte("pear")))
   343  	require.Equal(t, val4, s.LookupTimestamp([]byte("raspberry")))
   344  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("watermelon")))
   345  
   346  	// Equal range but fully-open.
   347  	// val1:    [g--------------p]
   348  	// val2:      [k---------o]
   349  	// val3: [b-------------------r]
   350  	// val4: (b-------------------r]
   351  	// val5: [b-------------------r)
   352  	// val6: (b-------------------r)
   353  	s.AddRange([]byte("banana"), []byte("raspberry"), (excludeFrom | excludeTo), val6)
   354  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("apple")))
   355  	require.Equal(t, val5, s.LookupTimestamp([]byte("banana")))
   356  	require.Equal(t, val6, s.LookupTimestamp([]byte("grape")))
   357  	require.Equal(t, val6, s.LookupTimestamp([]byte("kiwi")))
   358  	require.Equal(t, val6, s.LookupTimestamp([]byte("orange")))
   359  	require.Equal(t, val6, s.LookupTimestamp([]byte("pear")))
   360  	require.Equal(t, val4, s.LookupTimestamp([]byte("raspberry")))
   361  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("watermelon")))
   362  }
   363  
   364  func TestIntervalSklContiguousRanges(t *testing.T) {
   365  	ts1 := makeTS(201, 0)
   366  
   367  	val1 := makeVal(ts1, "1")
   368  	val2 := makeVal(ts1, "2")
   369  	val2WithoutID := makeValWithoutID(ts1)
   370  
   371  	s := newIntervalSkl(nil /* clock */, 0 /* minRet */, makeSklMetrics())
   372  	s.floorTS = floorTS
   373  
   374  	// val1:  [b---------k)
   375  	// val2:            [k---------o)
   376  	s.AddRange([]byte("banana"), []byte("kiwi"), excludeTo, val1)
   377  	s.AddRange([]byte("kiwi"), []byte("orange"), excludeTo, val2)
   378  
   379  	// Test single-key lookups over the contiguous range.
   380  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("apple")))
   381  	require.Equal(t, val1, s.LookupTimestamp([]byte("banana")))
   382  	require.Equal(t, val2, s.LookupTimestamp([]byte("kiwi")))
   383  	require.Equal(t, val2, s.LookupTimestamp([]byte("mango")))
   384  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("orange")))
   385  
   386  	// Test range lookups over the contiguous range.
   387  	require.Equal(t, floorVal, s.LookupTimestampRange([]byte(""), []byte("banana"), excludeTo))
   388  	require.Equal(t, val1, s.LookupTimestampRange([]byte(""), []byte("kiwi"), excludeTo))
   389  	require.Equal(t, val2WithoutID, s.LookupTimestampRange([]byte(""), []byte("orange"), excludeTo))
   390  	require.Equal(t, val2WithoutID, s.LookupTimestampRange([]byte(""), []byte(nil), excludeTo))
   391  	require.Equal(t, val1, s.LookupTimestampRange([]byte("banana"), []byte("kiwi"), excludeTo))
   392  	require.Equal(t, val2, s.LookupTimestampRange([]byte("kiwi"), []byte("orange"), excludeTo))
   393  	require.Equal(t, val2, s.LookupTimestampRange([]byte("kiwi"), []byte(nil), excludeTo))
   394  	require.Equal(t, val2WithoutID, s.LookupTimestampRange([]byte("banana"), []byte("orange"), excludeTo))
   395  	require.Equal(t, val2WithoutID, s.LookupTimestampRange([]byte("banana"), []byte(nil), excludeTo))
   396  	require.Equal(t, floorVal, s.LookupTimestampRange([]byte("orange"), []byte(nil), excludeTo))
   397  }
   398  
   399  func TestIntervalSklOverlappingRanges(t *testing.T) {
   400  	val1 := makeVal(makeTS(200, 1), "1")
   401  	val2 := makeVal(makeTS(201, 0), "2")
   402  	val3 := makeVal(makeTS(300, 0), "3")
   403  	val4 := makeVal(makeTS(400, 0), "4")
   404  
   405  	s := newIntervalSkl(nil /* clock */, 0 /* minRet */, makeSklMetrics())
   406  	s.floorTS = floorTS
   407  
   408  	// val1:  [b---------k]
   409  	// val2:        [g------------r)
   410  	s.AddRange([]byte("banana"), []byte("kiwi"), 0, val1)
   411  	s.AddRange([]byte("grape"), []byte("raspberry"), excludeTo, val2)
   412  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("apple")))
   413  	require.Equal(t, val1, s.LookupTimestamp([]byte("banana")))
   414  	require.Equal(t, val2, s.LookupTimestamp([]byte("grape")))
   415  	require.Equal(t, val2, s.LookupTimestamp([]byte("kiwi")))
   416  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("raspberry")))
   417  
   418  	// val1:    [b---------k]
   419  	// val2:         [g------------r)
   420  	// val3:  [a---------------o]
   421  	s.AddRange([]byte("apricot"), []byte("orange"), 0, val3)
   422  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("apple")))
   423  	require.Equal(t, val3, s.LookupTimestamp([]byte("apricot")))
   424  	require.Equal(t, val3, s.LookupTimestamp([]byte("banana")))
   425  	require.Equal(t, val3, s.LookupTimestamp([]byte("grape")))
   426  	require.Equal(t, val3, s.LookupTimestamp([]byte("kiwi")))
   427  	require.Equal(t, val3, s.LookupTimestamp([]byte("orange")))
   428  	require.Equal(t, val2, s.LookupTimestamp([]byte("pear")))
   429  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("raspberry")))
   430  
   431  	// val1:    [b---------k]
   432  	// val2:          [g------------r)
   433  	// val3:  [a---------------o]
   434  	// val4:              (k------------->
   435  	s.AddRange([]byte("kiwi"), []byte(nil), excludeFrom, val4)
   436  	require.Equal(t, floorVal, s.LookupTimestamp([]byte("apple")))
   437  	require.Equal(t, val3, s.LookupTimestamp([]byte("apricot")))
   438  	require.Equal(t, val3, s.LookupTimestamp([]byte("banana")))
   439  	require.Equal(t, val3, s.LookupTimestamp([]byte("grape")))
   440  	require.Equal(t, val3, s.LookupTimestamp([]byte("kiwi")))
   441  	require.Equal(t, val4, s.LookupTimestamp([]byte("orange")))
   442  	require.Equal(t, val4, s.LookupTimestamp([]byte("pear")))
   443  	require.Equal(t, val4, s.LookupTimestamp([]byte("raspberry")))
   444  }
   445  
   446  func TestIntervalSklSingleKeyRanges(t *testing.T) {
   447  	val1 := makeVal(makeTS(100, 100), "1")
   448  
   449  	s := newIntervalSkl(nil /* clock */, 0 /* minRet */, makeSklMetrics())
   450  
   451  	// Don't allow inverted ranges.
   452  	require.Panics(t, func() { s.AddRange([]byte("kiwi"), []byte("apple"), 0, val1) })
   453  	require.Equal(t, int64(0), s.frontPage().maxWallTime)
   454  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("apple")))
   455  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("banana")))
   456  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("kiwi")))
   457  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("raspberry")))
   458  
   459  	// If from key is same as to key and both are excluded, then range is
   460  	// zero-length.
   461  	s.AddRange([]byte("banana"), []byte("banana"), excludeFrom|excludeTo, val1)
   462  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("apple")))
   463  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("banana")))
   464  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("kiwi")))
   465  
   466  	// If from key is same as to key and at least one endpoint is included, then
   467  	// range has length one.
   468  	s.AddRange([]byte("mango"), []byte("mango"), 0, val1)
   469  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("kiwi")))
   470  	require.Equal(t, val1, s.LookupTimestamp([]byte("mango")))
   471  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("banana")))
   472  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("cherry")))
   473  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("orange")))
   474  
   475  	s.AddRange([]byte("banana"), []byte("banana"), excludeFrom, val1)
   476  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("kiwi")))
   477  	require.Equal(t, val1, s.LookupTimestamp([]byte("mango")))
   478  	require.Equal(t, val1, s.LookupTimestamp([]byte("banana")))
   479  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("cherry")))
   480  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("orange")))
   481  
   482  	s.AddRange([]byte("cherry"), []byte("cherry"), excludeTo, val1)
   483  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("kiwi")))
   484  	require.Equal(t, val1, s.LookupTimestamp([]byte("mango")))
   485  	require.Equal(t, val1, s.LookupTimestamp([]byte("banana")))
   486  	require.Equal(t, val1, s.LookupTimestamp([]byte("cherry")))
   487  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("orange")))
   488  }
   489  
   490  func TestIntervalSklRatchetTxnIDs(t *testing.T) {
   491  	ts1 := makeTS(100, 100)
   492  	ts2 := makeTS(250, 50)
   493  	ts3 := makeTS(350, 50)
   494  
   495  	val1 := makeVal(ts1, "1")
   496  	val2 := makeVal(ts1, "2")
   497  	val2WithoutID := makeValWithoutID(ts1)
   498  	val3 := makeVal(ts2, "2") // same txn ID as tsVal2
   499  	val4 := makeVal(ts2, "3")
   500  	val4WithoutID := makeValWithoutID(ts2)
   501  	val5 := makeVal(ts3, "4")
   502  	val6 := makeVal(ts3, "5")
   503  	val6WithoutID := makeValWithoutID(ts3)
   504  
   505  	s := newIntervalSkl(nil /* clock */, 0 /* minRet */, makeSklMetrics())
   506  
   507  	s.AddRange([]byte("apricot"), []byte("raspberry"), 0, val1)
   508  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("apple")))
   509  	require.Equal(t, val1, s.LookupTimestamp([]byte("apricot")))
   510  	require.Equal(t, val1, s.LookupTimestamp([]byte("banana")))
   511  	require.Equal(t, val1, s.LookupTimestamp([]byte("raspberry")))
   512  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("tomato")))
   513  
   514  	// Ratchet up the txnID with the same timestamp; txnID should be removed.
   515  	s.AddRange([]byte("apricot"), []byte("tomato"), 0, val2)
   516  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("apple")))
   517  	require.Equal(t, val2WithoutID, s.LookupTimestamp([]byte("apricot")))
   518  	require.Equal(t, val2WithoutID, s.LookupTimestamp([]byte("banana")))
   519  	require.Equal(t, val2WithoutID, s.LookupTimestamp([]byte("raspberry")))
   520  	require.Equal(t, val2, s.LookupTimestamp([]byte("tomato")))
   521  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("watermelon")))
   522  
   523  	// Ratchet up the timestamp with the same txnID.
   524  	s.AddRange([]byte("apricot"), []byte("orange"), 0, val3)
   525  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("apple")))
   526  	require.Equal(t, val3, s.LookupTimestamp([]byte("apricot")))
   527  	require.Equal(t, val3, s.LookupTimestamp([]byte("banana")))
   528  	require.Equal(t, val3, s.LookupTimestamp([]byte("orange")))
   529  	require.Equal(t, val2WithoutID, s.LookupTimestamp([]byte("raspberry")))
   530  	require.Equal(t, val2, s.LookupTimestamp([]byte("tomato")))
   531  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("watermelon")))
   532  
   533  	// Ratchet up the txnID with the same timestamp; txnID should be removed.
   534  	s.AddRange([]byte("apricot"), []byte("banana"), 0, val4)
   535  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("apple")))
   536  	require.Equal(t, val4WithoutID, s.LookupTimestamp([]byte("apricot")))
   537  	require.Equal(t, val4WithoutID, s.LookupTimestamp([]byte("banana")))
   538  	require.Equal(t, val3, s.LookupTimestamp([]byte("orange")))
   539  	require.Equal(t, val2WithoutID, s.LookupTimestamp([]byte("raspberry")))
   540  	require.Equal(t, val2, s.LookupTimestamp([]byte("tomato")))
   541  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("watermelon")))
   542  
   543  	// Ratchet up the timestamp with a new txnID using excludeTo.
   544  	s.AddRange([]byte("apricot"), []byte("orange"), excludeTo, val5)
   545  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("apple")))
   546  	require.Equal(t, val5, s.LookupTimestamp([]byte("apricot")))
   547  	require.Equal(t, val5, s.LookupTimestamp([]byte("banana")))
   548  	require.Equal(t, val3, s.LookupTimestamp([]byte("orange")))
   549  	require.Equal(t, val2WithoutID, s.LookupTimestamp([]byte("raspberry")))
   550  
   551  	// Ratchet up the txnID with the same timestamp using excludeTo; txnID should be removed.
   552  	s.AddRange([]byte("apricot"), []byte("banana"), excludeTo, val6)
   553  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("apple")))
   554  	require.Equal(t, val6WithoutID, s.LookupTimestamp([]byte("apricot")))
   555  	require.Equal(t, val5, s.LookupTimestamp([]byte("banana")))
   556  	require.Equal(t, val3, s.LookupTimestamp([]byte("orange")))
   557  	require.Equal(t, val2WithoutID, s.LookupTimestamp([]byte("raspberry")))
   558  
   559  	// Ratchet up the txnID with the same timestamp using excludeFrom; txnID should be removed.
   560  	s.AddRange([]byte("banana"), []byte(nil), excludeFrom, val6)
   561  	require.Equal(t, emptyVal, s.LookupTimestamp([]byte("apple")))
   562  	require.Equal(t, val6WithoutID, s.LookupTimestamp([]byte("apricot")))
   563  	require.Equal(t, val5, s.LookupTimestamp([]byte("banana")))
   564  	require.Equal(t, val6, s.LookupTimestamp([]byte("orange")))
   565  	require.Equal(t, val6, s.LookupTimestamp([]byte("raspberry")))
   566  }
   567  
   568  func TestIntervalSklLookupRange(t *testing.T) {
   569  	ts1 := makeTS(100, 100)
   570  	ts2 := makeTS(200, 201)
   571  	ts3 := makeTS(300, 201)
   572  	ts4 := makeTS(400, 201)
   573  
   574  	val1 := makeVal(ts1, "1")
   575  	val2 := makeVal(ts2, "2")
   576  	val3 := makeVal(ts2, "3")
   577  	val3WithoutID := makeValWithoutID(ts2)
   578  	val4 := makeVal(ts3, "4")
   579  	val5 := makeVal(ts4, "5")
   580  
   581  	s := newIntervalSkl(nil /* clock */, 0 /* minRet */, makeSklMetrics())
   582  
   583  	// Perform range lookups over a single key.
   584  	s.Add([]byte("apricot"), val1)
   585  	// from = "" and to = nil means that we're scanning over all keys.
   586  	require.Equal(t, val1, s.LookupTimestampRange([]byte(""), []byte(nil), 0))
   587  	require.Equal(t, val1, s.LookupTimestampRange([]byte(""), []byte(nil), excludeFrom))
   588  	require.Equal(t, val1, s.LookupTimestampRange([]byte(""), []byte(nil), excludeTo))
   589  	require.Equal(t, val1, s.LookupTimestampRange([]byte(""), []byte(nil), (excludeFrom|excludeTo)))
   590  
   591  	require.Equal(t, emptyVal, s.LookupTimestampRange([]byte("apple"), []byte("apple"), 0))
   592  	require.Equal(t, val1, s.LookupTimestampRange([]byte("apple"), []byte("apricot"), 0))
   593  	require.Equal(t, val1, s.LookupTimestampRange([]byte("apple"), []byte("apricot"), excludeFrom))
   594  	require.Equal(t, emptyVal, s.LookupTimestampRange([]byte("apple"), []byte("apricot"), excludeTo))
   595  
   596  	require.Equal(t, val1, s.LookupTimestampRange([]byte("apricot"), []byte("apricot"), 0))
   597  	require.Equal(t, val1, s.LookupTimestampRange([]byte("apricot"), []byte("apricot"), excludeFrom))
   598  	require.Equal(t, val1, s.LookupTimestampRange([]byte("apricot"), []byte("apricot"), excludeTo))
   599  	require.Equal(t, emptyVal, s.LookupTimestampRange([]byte("apricot"), []byte("apricot"), (excludeFrom|excludeTo)))
   600  
   601  	// Perform range lookups over a series of keys.
   602  	s.Add([]byte("banana"), val2)
   603  	s.Add([]byte("cherry"), val3)
   604  	require.Equal(t, val2, s.LookupTimestampRange([]byte("apricot"), []byte("banana"), 0))
   605  	require.Equal(t, val2, s.LookupTimestampRange([]byte("apricot"), []byte("banana"), excludeFrom))
   606  	require.Equal(t, val1, s.LookupTimestampRange([]byte("apricot"), []byte("banana"), excludeTo))
   607  	require.Equal(t, emptyVal, s.LookupTimestampRange([]byte("apricot"), []byte("banana"), (excludeFrom|excludeTo)))
   608  
   609  	require.Equal(t, val3WithoutID, s.LookupTimestampRange([]byte("apricot"), []byte("cherry"), 0))
   610  	require.Equal(t, val3WithoutID, s.LookupTimestampRange([]byte("apricot"), []byte("cherry"), excludeFrom))
   611  	require.Equal(t, val2, s.LookupTimestampRange([]byte("apricot"), []byte("cherry"), excludeTo))
   612  	require.Equal(t, val2, s.LookupTimestampRange([]byte("apricot"), []byte("cherry"), (excludeFrom|excludeTo)))
   613  
   614  	require.Equal(t, val3WithoutID, s.LookupTimestampRange([]byte("banana"), []byte("cherry"), 0))
   615  	require.Equal(t, val3, s.LookupTimestampRange([]byte("banana"), []byte("cherry"), excludeFrom))
   616  	require.Equal(t, val2, s.LookupTimestampRange([]byte("banana"), []byte("cherry"), excludeTo))
   617  	require.Equal(t, emptyVal, s.LookupTimestampRange([]byte("banana"), []byte("cherry"), (excludeFrom|excludeTo)))
   618  
   619  	// Open ranges should scan until the last key.
   620  	require.Equal(t, val3WithoutID, s.LookupTimestampRange([]byte("apricot"), []byte(nil), 0))
   621  	require.Equal(t, val3WithoutID, s.LookupTimestampRange([]byte("banana"), []byte(nil), 0))
   622  	require.Equal(t, val3, s.LookupTimestampRange([]byte("cherry"), []byte(nil), 0))
   623  	require.Equal(t, emptyVal, s.LookupTimestampRange([]byte("tomato"), []byte(nil), 0))
   624  
   625  	// Subset lookup range.
   626  	s.AddRange([]byte("apple"), []byte("cherry"), excludeTo, val4)
   627  	require.Equal(t, val4, s.LookupTimestampRange([]byte("apple"), []byte("berry"), 0))
   628  	require.Equal(t, val4, s.LookupTimestampRange([]byte("apple"), []byte("berry"), excludeFrom))
   629  	require.Equal(t, val4, s.LookupTimestampRange([]byte("berry"), []byte("blueberry"), 0))
   630  	require.Equal(t, val4, s.LookupTimestampRange([]byte("berry"), []byte("cherry"), 0))
   631  	require.Equal(t, val4, s.LookupTimestampRange([]byte("berry"), []byte("cherry"), excludeTo))
   632  
   633  	// Overlapping range without endpoints.
   634  	s.AddRange([]byte("banana"), []byte("cherry"), (excludeFrom | excludeTo), val5)
   635  	require.Equal(t, val4, s.LookupTimestampRange([]byte("apple"), []byte("banana"), (excludeFrom|excludeTo)))
   636  	require.Equal(t, val5, s.LookupTimestampRange([]byte("banana"), []byte("cherry"), (excludeFrom|excludeTo)))
   637  	require.Equal(t, val5, s.LookupTimestampRange([]byte("apple"), []byte("cherry"), (excludeFrom|excludeTo)))
   638  }
   639  
   640  func TestIntervalSklLookupRangeSingleKeyRanges(t *testing.T) {
   641  	ts1 := makeTS(100, 100)
   642  	ts2 := makeTS(200, 201)
   643  
   644  	val1 := makeVal(ts1, "1")
   645  	val2 := makeVal(ts2, "2")
   646  	val3 := makeVal(ts2, "3")
   647  	val3WithoutID := makeValWithoutID(ts2)
   648  
   649  	key1 := []byte("a")
   650  	key2 := append(key1, 0x0)
   651  	key3 := append(key2, 0x0)
   652  	key4 := append(key3, 0x0)
   653  
   654  	// Perform range lookups over [key, key.Next()) ranges.
   655  	t.Run("[key, key.Next())", func(t *testing.T) {
   656  		s := newIntervalSkl(nil /* clock */, 0 /* minRet */, makeSklMetrics())
   657  
   658  		s.AddRange(key1, key2, excludeTo, val1)
   659  		s.AddRange(key2, key3, excludeTo, val2)
   660  		s.AddRange(key3, key4, excludeTo, val3)
   661  
   662  		require.Equal(t, val1, s.LookupTimestampRange([]byte(""), key1, 0))
   663  		require.Equal(t, emptyVal, s.LookupTimestampRange([]byte(""), key1, excludeTo))
   664  		require.Equal(t, val2, s.LookupTimestampRange([]byte(""), key2, 0))
   665  		require.Equal(t, val1, s.LookupTimestampRange([]byte(""), key2, excludeTo))
   666  
   667  		require.Equal(t, val2, s.LookupTimestampRange(key1, key2, 0))
   668  		require.Equal(t, val2, s.LookupTimestampRange(key1, key2, excludeFrom))
   669  		require.Equal(t, val1, s.LookupTimestampRange(key1, key2, excludeTo))
   670  		// This may be surprising. We actually return the gapVal of the first range
   671  		// even though there isn't a discrete byte value between key1 and key2 (this
   672  		// is a feature, not a bug!). It demonstrates the difference between the
   673  		// first two options (which behave exactly the same) and the third:
   674  		// a) Add(key, val)
   675  		// b) AddRange(key, key, 0, val)
   676  		// c) AddRange(key, key.Next(), excludeTo, val)
   677  		//
   678  		// NB: If the behavior is not needed, it's better to use one of the
   679  		// first two options because they allow us to avoid storing a gap value.
   680  		require.Equal(t, val1, s.LookupTimestampRange(key1, key2, (excludeFrom|excludeTo)))
   681  
   682  		// val1 and val2 both have the same timestamp but have different IDs, so
   683  		// the cacheValue ratcheting policy enforces that the result of scanning
   684  		// over both should be a value with their timestamp but with no txnID.
   685  		require.Equal(t, val3WithoutID, s.LookupTimestampRange(key1, key3, 0))
   686  		require.Equal(t, val3WithoutID, s.LookupTimestampRange(key1, key3, excludeFrom))
   687  		require.Equal(t, val2, s.LookupTimestampRange(key1, key3, excludeTo))
   688  		require.Equal(t, val2, s.LookupTimestampRange(key1, key3, (excludeFrom|excludeTo)))
   689  
   690  		require.Equal(t, val3WithoutID, s.LookupTimestampRange(key2, key3, 0))
   691  		// Again, this may be surprising. The logic is the same as above.
   692  		require.Equal(t, val3WithoutID, s.LookupTimestampRange(key2, key3, excludeFrom))
   693  		require.Equal(t, val2, s.LookupTimestampRange(key2, key3, excludeTo))
   694  		require.Equal(t, val2, s.LookupTimestampRange(key2, key3, (excludeFrom|excludeTo)))
   695  
   696  		require.Equal(t, val3, s.LookupTimestampRange(key3, []byte(nil), 0))
   697  		require.Equal(t, val3, s.LookupTimestampRange(key3, []byte(nil), excludeFrom))
   698  	})
   699  
   700  	// Perform the same lookups, but this time use single key ranges.
   701  	t.Run("[key, key]", func(t *testing.T) {
   702  		s := newIntervalSkl(nil /* clock */, 0 /* minRet */, makeSklMetrics())
   703  
   704  		s.AddRange(key1, key1, 0, val1) // same as Add(key1, val1)
   705  		s.AddRange(key2, key2, 0, val2) //   ...   Add(key2, val2)
   706  		s.AddRange(key3, key3, 0, val3) //   ...   Add(key3, val3)
   707  
   708  		require.Equal(t, val1, s.LookupTimestampRange([]byte(""), key1, 0))
   709  		require.Equal(t, emptyVal, s.LookupTimestampRange([]byte(""), key1, excludeTo))
   710  		require.Equal(t, val2, s.LookupTimestampRange([]byte(""), key2, 0))
   711  		require.Equal(t, val1, s.LookupTimestampRange([]byte(""), key2, excludeTo))
   712  
   713  		require.Equal(t, val2, s.LookupTimestampRange(key1, key2, 0))
   714  		require.Equal(t, val2, s.LookupTimestampRange(key1, key2, excludeFrom))
   715  		require.Equal(t, val1, s.LookupTimestampRange(key1, key2, excludeTo))
   716  		// DIFFERENT!
   717  		require.Equal(t, emptyVal, s.LookupTimestampRange(key1, key2, (excludeFrom|excludeTo)))
   718  
   719  		require.Equal(t, val3WithoutID, s.LookupTimestampRange(key1, key3, 0))
   720  		require.Equal(t, val3WithoutID, s.LookupTimestampRange(key1, key3, excludeFrom))
   721  		require.Equal(t, val2, s.LookupTimestampRange(key1, key3, excludeTo))
   722  		require.Equal(t, val2, s.LookupTimestampRange(key1, key3, (excludeFrom|excludeTo)))
   723  
   724  		require.Equal(t, val3WithoutID, s.LookupTimestampRange(key2, key3, 0))
   725  		// DIFFERENT!
   726  		require.Equal(t, val3, s.LookupTimestampRange(key2, key3, excludeFrom))
   727  		require.Equal(t, val2, s.LookupTimestampRange(key2, key3, excludeTo))
   728  		// DIFFERENT!
   729  		require.Equal(t, emptyVal, s.LookupTimestampRange(key2, key3, (excludeFrom|excludeTo)))
   730  
   731  		require.Equal(t, val3, s.LookupTimestampRange(key3, []byte(nil), 0))
   732  		// DIFFERENT!
   733  		require.Equal(t, emptyVal, s.LookupTimestampRange(key3, []byte(nil), excludeFrom))
   734  	})
   735  }
   736  
   737  // TestIntervalSklLookupEqualsEarlierMaxWallTime tests that we properly handle
   738  // the lookup when the timestamp for a range found in the later page is equal to
   739  // the maxWallTime of the earlier page.
   740  func TestIntervalSklLookupEqualsEarlierMaxWallTime(t *testing.T) {
   741  	ts1 := makeTS(200, 0) // without Logical part
   742  	ts2 := makeTS(200, 1) // with Logical part
   743  	ts2Ceil := makeTS(201, 0)
   744  
   745  	txnID1 := "1"
   746  	txnID2 := "2"
   747  
   748  	testutils.RunTrueAndFalse(t, "tsWithLogicalPart", func(t *testing.T, logicalPart bool) {
   749  		s := newIntervalSkl(nil /* clock */, 0 /* minRet */, makeSklMetrics())
   750  		s.floorTS = floorTS
   751  
   752  		// Insert an initial value into intervalSkl.
   753  		initTS := ts1
   754  		if logicalPart {
   755  			initTS = ts2
   756  		}
   757  		origVal := makeVal(initTS, txnID1)
   758  		s.AddRange([]byte("banana"), []byte("orange"), 0, origVal)
   759  
   760  		// Verify the later page's maxWallTime is what we expect.
   761  		expMaxTS := ts1
   762  		if logicalPart {
   763  			expMaxTS = ts2Ceil
   764  		}
   765  		require.Equal(t, expMaxTS.WallTime, s.frontPage().maxWallTime)
   766  
   767  		// Rotate the page so that new writes will go to a different page.
   768  		s.rotatePages(s.frontPage())
   769  
   770  		// Write to overlapping and non-overlapping parts of the new page with
   771  		// the values that have the same timestamp as the maxWallTime of the
   772  		// earlier page. One value has the same txnID as the previous write in
   773  		// the earlier page and one has a different txnID.
   774  		valSameID := makeVal(expMaxTS, txnID1)
   775  		valDiffID := makeVal(expMaxTS, txnID2)
   776  		valNoID := makeValWithoutID(expMaxTS)
   777  		s.Add([]byte("apricot"), valSameID)
   778  		s.Add([]byte("banana"), valSameID)
   779  		s.Add([]byte("orange"), valDiffID)
   780  		s.Add([]byte("raspberry"), valDiffID)
   781  
   782  		require.Equal(t, valSameID, s.LookupTimestamp([]byte("apricot")))
   783  		require.Equal(t, valSameID, s.LookupTimestamp([]byte("banana")))
   784  		if logicalPart {
   785  			// If the initial timestamp had a logical part then
   786  			// s.earlier.maxWallTime is inexact (see ratchetMaxTimestamp). When
   787  			// we search in the earlier page, we'll find the exact timestamp of
   788  			// the overlapping range and realize that its not the same as the
   789  			// timestamp of the range in the later page. Because of this,
   790  			// ratchetValue WON'T remove the txnID.
   791  			require.Equal(t, valDiffID, s.LookupTimestamp([]byte("orange")))
   792  		} else {
   793  			// If the initial timestamp did not have a logical part then
   794  			// s.earlier.maxWallTime is exact. When we search in the earlier
   795  			// page, we'll find the overlapping range and realize that it is the
   796  			// same as the timestamp of the range in the later page. Because of
   797  			// this, ratchetValue WILL remove the txnID.
   798  			require.Equal(t, valNoID, s.LookupTimestamp([]byte("orange")))
   799  		}
   800  		require.Equal(t, valDiffID, s.LookupTimestamp([]byte("raspberry")))
   801  		require.Equal(t, floorVal, s.LookupTimestamp([]byte("tomato")))
   802  	})
   803  }
   804  
   805  func TestIntervalSklFill(t *testing.T) {
   806  	const n = 200
   807  	const txnID = "123"
   808  
   809  	s := newIntervalSkl(nil /* clock */, 0 /* minRet */, makeSklMetrics())
   810  	s.setFixedPageSize(1500)
   811  
   812  	for i := 0; i < n; i++ {
   813  		key := []byte(fmt.Sprintf("%05d", i))
   814  		s.AddRange(key, key, 0, makeVal(makeTS(int64(100+i), int32(i)), txnID))
   815  	}
   816  
   817  	require.True(t, makeTS(100, 0).Less(s.floorTS))
   818  
   819  	// Verify that the last key inserted is still in the intervalSkl and has not
   820  	// been rotated out.
   821  	lastKey := []byte(fmt.Sprintf("%05d", n-1))
   822  	expVal := makeVal(makeTS(int64(100+n-1), int32(n-1)), txnID)
   823  	require.Equal(t, expVal, s.LookupTimestamp(lastKey))
   824  
   825  	// Verify that all keys inserted are either still in the intervalSkl or have
   826  	// been rotated out and used to ratchet the floorTS.
   827  	for i := 0; i < n; i++ {
   828  		key := []byte(fmt.Sprintf("%05d", i))
   829  		require.False(t, s.LookupTimestamp(key).ts.Less(s.floorTS))
   830  	}
   831  }
   832  
   833  // Repeatedly fill the structure and make sure timestamp lookups always increase.
   834  func TestIntervalSklFill2(t *testing.T) {
   835  	const n = 10000
   836  	const txnID = "123"
   837  
   838  	// n >> 1000 so the intervalSkl's pages will be filled.
   839  	s := newIntervalSkl(nil /* clock */, 0 /* minRet */, makeSklMetrics())
   840  	s.setFixedPageSize(1000)
   841  
   842  	key := []byte("some key")
   843  	for i := 0; i < n; i++ {
   844  		val := makeVal(makeTS(int64(i), int32(i)), txnID)
   845  		s.Add(key, val)
   846  		require.True(t, val.ts.LessEq(s.LookupTimestamp(key).ts))
   847  	}
   848  }
   849  
   850  // TestIntervalSklMinRetentionWindow tests that if a value is within the minimum
   851  // retention window, its page will never be evicted and it will never be subsumed
   852  // by the floor timestamp.
   853  func TestIntervalSklMinRetentionWindow(t *testing.T) {
   854  	manual := hlc.NewManualClock(200)
   855  	clock := hlc.NewClock(manual.UnixNano, time.Nanosecond)
   856  
   857  	const minRet = 500
   858  	s := newIntervalSkl(clock, minRet, makeSklMetrics())
   859  	s.setFixedPageSize(1500)
   860  	s.floorTS = floorTS
   861  
   862  	// Add an initial value. Rotate the page so it's alone.
   863  	origKey := []byte("banana")
   864  	origVal := makeVal(clock.Now(), "1")
   865  	s.Add(origKey, origVal)
   866  	s.rotatePages(s.frontPage())
   867  
   868  	// Add a large number of other values, forcing rotations. Continue until
   869  	// there are more pages than s.minPages.
   870  	manual.Increment(300)
   871  	for i := 0; s.pages.Len() <= s.minPages; i++ {
   872  		key := []byte(fmt.Sprintf("%05d", i))
   873  		s.Add(key, makeVal(clock.Now(), "2"))
   874  	}
   875  
   876  	// We should still be able to look up the initial value.
   877  	require.Equal(t, origVal, s.LookupTimestamp(origKey))
   878  
   879  	// Even if we rotate the pages, we should still be able to look up the
   880  	// value. No pages should be evicted.
   881  	pagesBefore := s.pages.Len()
   882  	s.rotatePages(s.frontPage())
   883  	require.Equal(t, pagesBefore+1, s.pages.Len(), "page should not be evicted")
   884  	require.Equal(t, origVal, s.LookupTimestamp(origKey))
   885  
   886  	// Increment the clock so that the original value is not in the minimum
   887  	// retention window. Rotate the pages and the back page should be evicted.
   888  	manual.Increment(300)
   889  	s.rotatePages(s.frontPage())
   890  
   891  	newVal := s.LookupTimestamp(origKey)
   892  	require.NotEqual(t, origVal, newVal, "the original value should be evicted")
   893  
   894  	_, update := ratchetValue(origVal, newVal)
   895  	require.True(t, update, "the original value should have been ratcheted to the new value")
   896  
   897  	// Increment the clock again so that all the other values can be evicted.
   898  	// The pages should collapse back down to s.minPages.
   899  	manual.Increment(300)
   900  	s.rotatePages(s.frontPage())
   901  	require.Equal(t, s.pages.Len(), s.minPages)
   902  }
   903  
   904  func TestIntervalSklConcurrency(t *testing.T) {
   905  	defer leaktest.AfterTest(t)()
   906  	defer util.EnableRacePreemptionPoints()()
   907  
   908  	testCases := []struct {
   909  		name     string
   910  		pageSize uint32
   911  		minPages int
   912  	}{
   913  		// Test concurrency with a small page size in order to force lots of
   914  		// page rotations.
   915  		{name: "Rotates", pageSize: 4096},
   916  		// Test concurrency with a small page size and a large number of pages
   917  		// in order to force lots of page growth.
   918  		{name: "Pages", pageSize: 4096, minPages: 16},
   919  		// Test concurrency with a larger page size in order to test slot
   920  		// concurrency without the added complication of page rotations.
   921  		{name: "Slots", pageSize: initialSklPageSize},
   922  	}
   923  	for _, tc := range testCases {
   924  		t.Run(tc.name, func(t *testing.T) {
   925  			// Run one subtest using a real clock to generate timestamps and one
   926  			// subtest using a fake clock to generate timestamps. The former is
   927  			// good for simulating real conditions while the latter is good for
   928  			// testing timestamp collisions.
   929  			testutils.RunTrueAndFalse(t, "useClock", func(t *testing.T, useClock bool) {
   930  				clock := hlc.NewClock(hlc.UnixNano, time.Nanosecond)
   931  				s := newIntervalSkl(clock, 0 /* minRet */, makeSklMetrics())
   932  				s.setFixedPageSize(tc.pageSize)
   933  				if tc.minPages != 0 {
   934  					s.setMinPages(tc.minPages)
   935  				}
   936  
   937  				// We run a goroutine for each slot. Goroutines insert new value
   938  				// over random intervals, but verify that the value in their
   939  				// slot always ratchets.
   940  				slots := 4 * runtime.NumCPU()
   941  				if util.RaceEnabled {
   942  					// We add in a lot of preemption points when race detection
   943  					// is enabled, so things will already be very slow. Reduce
   944  					// the concurrency to that we don't time out.
   945  					slots /= 2
   946  				}
   947  
   948  				var wg sync.WaitGroup
   949  				for i := 0; i < slots; i++ {
   950  					wg.Add(1)
   951  
   952  					// Each goroutine gets its own key to watch as it performs
   953  					// random operations.
   954  					go func(i int) {
   955  						defer wg.Done()
   956  
   957  						rng := rand.New(rand.NewSource(timeutil.Now().UnixNano()))
   958  						key := []byte(fmt.Sprintf("%05d", i))
   959  						txnID := uuid.MakeV4()
   960  						maxVal := cacheValue{}
   961  
   962  						rounds := 1000
   963  						if util.RaceEnabled {
   964  							// Reduce the number of rounds for race builds.
   965  							rounds /= 2
   966  						}
   967  						for j := 0; j < rounds; j++ {
   968  							// Choose a random range.
   969  							from, middle, to := randRange(rng, slots)
   970  							opt := randRangeOpt(rng)
   971  
   972  							// Add a new value to the range.
   973  							ts := hlc.Timestamp{WallTime: int64(j)}
   974  							if useClock {
   975  								ts = clock.Now()
   976  							}
   977  							nowVal := cacheValue{ts: ts, txnID: txnID}
   978  							s.AddRange(from, to, opt, nowVal)
   979  
   980  							// Test single-key lookup at from, if possible.
   981  							if (opt & excludeFrom) == 0 {
   982  								val := s.LookupTimestamp(from)
   983  								assertRatchet(t, nowVal, val)
   984  							}
   985  
   986  							// Test single-key lookup between from and to, if possible.
   987  							if middle != nil {
   988  								val := s.LookupTimestamp(middle)
   989  								assertRatchet(t, nowVal, val)
   990  							}
   991  
   992  							// Test single-key lookup at to, if possible.
   993  							if (opt & excludeTo) == 0 {
   994  								val := s.LookupTimestamp(to)
   995  								assertRatchet(t, nowVal, val)
   996  							}
   997  
   998  							// Test range lookup between from and to, if possible.
   999  							if !(bytes.Equal(from, to) && opt == (excludeFrom|excludeTo)) {
  1000  								val := s.LookupTimestampRange(from, to, opt)
  1001  								assertRatchet(t, nowVal, val)
  1002  							}
  1003  
  1004  							// Make sure the value at our key did not decrease.
  1005  							val := s.LookupTimestamp(key)
  1006  							assertRatchet(t, maxVal, val)
  1007  							maxVal = val
  1008  						}
  1009  					}(i)
  1010  				}
  1011  
  1012  				wg.Wait()
  1013  			})
  1014  		})
  1015  	}
  1016  }
  1017  
  1018  func TestIntervalSklConcurrentVsSequential(t *testing.T) {
  1019  	defer leaktest.AfterTest(t)()
  1020  	defer util.EnableRacePreemptionPoints()()
  1021  
  1022  	// Run one subtest using a real clock to generate timestamps and one subtest
  1023  	// using a fake clock to generate timestamps. The former is good for
  1024  	// simulating real conditions while the latter is good for testing timestamp
  1025  	// collisions.
  1026  	testutils.RunTrueAndFalse(t, "useClock", func(t *testing.T, useClock bool) {
  1027  		rng := rand.New(rand.NewSource(timeutil.Now().UnixNano()))
  1028  		clock := hlc.NewClock(hlc.UnixNano, time.Nanosecond)
  1029  
  1030  		const smallPageSize = 32 * 1024 // 32 KB
  1031  		const retainForever = math.MaxInt64
  1032  		sequentialS := newIntervalSkl(clock, retainForever, makeSklMetrics())
  1033  		sequentialS.setFixedPageSize(smallPageSize)
  1034  		concurrentS := newIntervalSkl(clock, retainForever, makeSklMetrics())
  1035  		concurrentS.setFixedPageSize(smallPageSize)
  1036  
  1037  		// We run a goroutine for each slot. Goroutines insert new value
  1038  		// over random intervals, but verify that the value in their
  1039  		// slot always ratchets.
  1040  		slots := 4 * runtime.NumCPU()
  1041  		if util.RaceEnabled {
  1042  			// We add in a lot of preemption points when race detection
  1043  			// is enabled, so things will already be very slow. Reduce
  1044  			// the concurrency to that we don't time out.
  1045  			slots /= 2
  1046  		}
  1047  
  1048  		txnIDs := make([]uuid.UUID, slots)
  1049  		for i := range txnIDs {
  1050  			txnIDs[i] = uuid.MakeV4()
  1051  		}
  1052  
  1053  		rounds := 1000
  1054  		if util.RaceEnabled {
  1055  			// Reduce the number of rounds for race builds.
  1056  			rounds /= 2
  1057  		}
  1058  		for j := 0; j < rounds; j++ {
  1059  			// This is a lot of log output so only un-comment to debug.
  1060  			// t.Logf("round %d", j)
  1061  
  1062  			// Create a set of actions to perform.
  1063  			type action struct {
  1064  				from, middle, to []byte
  1065  				opt              rangeOptions
  1066  				val              cacheValue
  1067  			}
  1068  			actions := make([]action, slots)
  1069  			for i := range actions {
  1070  				var a action
  1071  				a.from, a.middle, a.to = randRange(rng, slots)
  1072  				a.opt = randRangeOpt(rng)
  1073  
  1074  				ts := hlc.Timestamp{WallTime: int64(j)}
  1075  				if useClock {
  1076  					ts = clock.Now()
  1077  				}
  1078  				a.val = cacheValue{ts: ts, txnID: txnIDs[i]}
  1079  
  1080  				// This is a lot of log output so only un-comment to debug.
  1081  				// t.Logf("action (%s,%s)[%d] = %s", string(a.from), string(a.to), a.opt, a.val)
  1082  				actions[i] = a
  1083  			}
  1084  
  1085  			// Perform each action, first in order on the "sequential"
  1086  			// intervalSkl, then in parallel on the "concurrent" intervalSkl.
  1087  			// t.Log("sequential actions")
  1088  			for _, a := range actions {
  1089  				sequentialS.AddRange(a.from, a.to, a.opt, a.val)
  1090  			}
  1091  
  1092  			// t.Log("concurrent actions")
  1093  			var wg sync.WaitGroup
  1094  			for _, a := range actions {
  1095  				wg.Add(1)
  1096  				go func(a action) {
  1097  					concurrentS.AddRange(a.from, a.to, a.opt, a.val)
  1098  					wg.Done()
  1099  				}(a)
  1100  			}
  1101  			wg.Wait()
  1102  
  1103  			// Ask each intervalSkl the same questions. We should get the same
  1104  			// answers.
  1105  			for _, a := range actions {
  1106  				// Test single-key lookup at from, if possible.
  1107  				if (a.opt & excludeFrom) == 0 {
  1108  					valS := sequentialS.LookupTimestamp(a.from)
  1109  					valC := concurrentS.LookupTimestamp(a.from)
  1110  					require.Equal(t, valS, valC, "key=%s", string(a.from))
  1111  					assertRatchet(t, a.val, valS)
  1112  				}
  1113  
  1114  				// Test single-key lookup between from and to, if possible.
  1115  				if a.middle != nil {
  1116  					valS := sequentialS.LookupTimestamp(a.middle)
  1117  					valC := concurrentS.LookupTimestamp(a.middle)
  1118  					require.Equal(t, valS, valC, "key=%s", string(a.middle))
  1119  					assertRatchet(t, a.val, valS)
  1120  				}
  1121  
  1122  				// Test single-key lookup at to, if possible.
  1123  				if (a.opt & excludeTo) == 0 {
  1124  					valS := sequentialS.LookupTimestamp(a.to)
  1125  					valC := concurrentS.LookupTimestamp(a.to)
  1126  					require.Equal(t, valS, valC, "key=%s", string(a.to))
  1127  					assertRatchet(t, a.val, valS)
  1128  				}
  1129  
  1130  				// Test range lookup between from and to, if possible.
  1131  				if !(bytes.Equal(a.from, a.to) && a.opt == (excludeFrom|excludeTo)) {
  1132  					valS := sequentialS.LookupTimestampRange(a.from, a.to, a.opt)
  1133  					valC := concurrentS.LookupTimestampRange(a.from, a.to, a.opt)
  1134  					require.Equal(t, valS, valC, "range=(%s,%s)[%d]",
  1135  						string(a.from), string(a.to), a.opt)
  1136  					assertRatchet(t, a.val, valS)
  1137  				}
  1138  			}
  1139  		}
  1140  	})
  1141  }
  1142  
  1143  // assertRatchet asserts that it would be possible for the first cacheValue
  1144  // (before) to be ratcheted to the second cacheValue (after).
  1145  func assertRatchet(t *testing.T, before, after cacheValue) {
  1146  	// Value ratcheting is an anti-symmetric relation R, so if R(before, after)
  1147  	// holds with before != after, then R(after, before) must not hold. Another
  1148  	// way to look at this is that ratcheting is a monotonically increasing
  1149  	// function, so if after comes later than before and the two are not equal,
  1150  	// then before could not also come later than after.
  1151  	//
  1152  	// If before == after, ratcheting will be a no-op, so the assertion will
  1153  	// still hold.
  1154  	_, upgrade := ratchetValue(after, before)
  1155  	require.False(t, upgrade, "ratchet inversion from %s to %s", before, after)
  1156  }
  1157  
  1158  // TestIntervalSklMaxEncodedSize ensures that we do not enter an infinite page
  1159  // rotation loop for ranges that are too large to fit in a single page. Instead,
  1160  // we detect this scenario early and panic.
  1161  func TestIntervalSklMaxEncodedSize(t *testing.T) {
  1162  	manual := hlc.NewManualClock(200)
  1163  	clock := hlc.NewClock(manual.UnixNano, time.Nanosecond)
  1164  
  1165  	ts := clock.Now()
  1166  	val := makeVal(ts, "1")
  1167  
  1168  	testutils.RunTrueAndFalse(t, "fit", func(t *testing.T, fit bool) {
  1169  		testutils.RunTrueAndFalse(t, "fixed", func(t *testing.T, fixed bool) {
  1170  			var key []byte
  1171  			var encSize int
  1172  			if fixed {
  1173  				// Create an arbitrarily sized key. We'll set the pageSize to
  1174  				// either exactly accommodate this or to be one byte too small.
  1175  				key = make([]byte, 65)
  1176  				encSize = encodedRangeSize(key, nil, 0)
  1177  			} else {
  1178  				// Create either the largest possible key that will fit in the
  1179  				// maximumSklPageSize or a key one byte larger than this. This
  1180  				// test forces the intervalSkl to quickly grow its page size
  1181  				// until it is large enough to accommodate the key.
  1182  				encSize = maximumSklPageSize - initialSklAllocSize
  1183  				encOverhead := encodedRangeSize(nil, nil, 0)
  1184  				keySize := encSize - encOverhead
  1185  				if !fit {
  1186  					keySize++
  1187  				}
  1188  				key = make([]byte, keySize)
  1189  				if fit {
  1190  					require.Equal(t, encSize, encodedRangeSize(key, nil, 0))
  1191  				} else {
  1192  					require.Equal(t, encSize+1, encodedRangeSize(key, nil, 0))
  1193  				}
  1194  			}
  1195  
  1196  			s := newIntervalSkl(clock, 1, makeSklMetrics())
  1197  			if fixed {
  1198  				fixedSize := uint32(initialSklAllocSize + encSize)
  1199  				if !fit {
  1200  					fixedSize--
  1201  				}
  1202  				s.setFixedPageSize(fixedSize)
  1203  			}
  1204  			initPageSize := s.pageSize
  1205  
  1206  			if fit {
  1207  				require.NotPanics(t, func() { s.Add(key, val) })
  1208  			} else {
  1209  				require.Panics(t, func() { s.Add(key, val) })
  1210  			}
  1211  
  1212  			if fit && !fixed {
  1213  				// Page size should have grown to maximum.
  1214  				require.Equal(t, uint32(maximumSklPageSize), s.pageSize)
  1215  			} else {
  1216  				// Page size should not have grown.
  1217  				require.Equal(t, initPageSize, s.pageSize)
  1218  			}
  1219  		})
  1220  	})
  1221  }
  1222  
  1223  // TestArenaReuse tests that arenas are re-used when possible during page
  1224  // rotations. Skiplist memory arenas are only re-used when they have the same
  1225  // capacity as the new page.
  1226  func TestArenaReuse(t *testing.T) {
  1227  	s := newIntervalSkl(nil /* clock */, 0 /* minRet */, makeSklMetrics())
  1228  
  1229  	// Track the unique arenas that we observe in use.
  1230  	arenas := make(map[*arenaskl.Arena]struct{})
  1231  	const iters = 256
  1232  	for i := 0; i < iters; i++ {
  1233  		for e := s.pages.Front(); e != nil; e = e.Next() {
  1234  			p := e.Value.(*sklPage)
  1235  			arenas[p.list.Arena()] = struct{}{}
  1236  		}
  1237  		s.rotatePages(s.frontPage())
  1238  	}
  1239  
  1240  	// We expect to see a single arena with each of the allocation sizes between
  1241  	// initialSklPageSize and maximumSklPageSize. We then expect to see repeated
  1242  	// pages with the same size once we hit maximumSklPageSize. Only then do we
  1243  	// expect to see arena re-use.
  1244  	//
  1245  	// Example:
  1246  	//  initSize = 4
  1247  	//  maxSize  = 32
  1248  	//  minPages = 2
  1249  	//
  1250  	//  arena sizes:
  1251  	//   4  (A1)
  1252  	//   8  (A2)
  1253  	//   16 (A3)
  1254  	//   32 (A4)
  1255  	//   32 (A5)
  1256  	//   32 (A4)
  1257  	//   32 (A5)
  1258  	//   ...
  1259  	//
  1260  	intermediatePages := int(math.Log2(maximumSklPageSize) - math.Log2(initialSklPageSize))
  1261  	expArenas := defaultMinSklPages + intermediatePages
  1262  	require.Less(t, expArenas, iters)
  1263  	require.Equal(t, expArenas, len(arenas))
  1264  }
  1265  
  1266  func BenchmarkIntervalSklAdd(b *testing.B) {
  1267  	const max = 500000000 // max size of range
  1268  	const txnID = "123"
  1269  
  1270  	clock := hlc.NewClock(hlc.UnixNano, time.Millisecond)
  1271  	s := newIntervalSkl(clock, MinRetentionWindow, makeSklMetrics())
  1272  	rng := rand.New(rand.NewSource(timeutil.Now().UnixNano()))
  1273  
  1274  	size := 1
  1275  	for i := 0; i < 9; i++ {
  1276  		b.Run(fmt.Sprintf("size_%d", size), func(b *testing.B) {
  1277  			for iter := 0; iter < b.N; iter++ {
  1278  				rnd := int64(rng.Int31n(max))
  1279  				from := []byte(fmt.Sprintf("%020d", rnd))
  1280  				to := []byte(fmt.Sprintf("%020d", rnd+int64(size-1)))
  1281  				s.AddRange(from, to, 0, makeVal(clock.Now(), txnID))
  1282  			}
  1283  		})
  1284  
  1285  		size *= 10
  1286  	}
  1287  }
  1288  
  1289  func BenchmarkIntervalSklAddAndLookup(b *testing.B) {
  1290  	const parallel = 1
  1291  	const max = 1000000000 // max size of range
  1292  	const data = 500000    // number of ranges
  1293  	const txnID = "123"
  1294  
  1295  	clock := hlc.NewClock(hlc.UnixNano, time.Millisecond)
  1296  	s := newIntervalSkl(clock, MinRetentionWindow, makeSklMetrics())
  1297  	rng := rand.New(rand.NewSource(timeutil.Now().UnixNano()))
  1298  
  1299  	for i := 0; i < data; i++ {
  1300  		from, to := makeRange(rng.Int31n(max))
  1301  		nowVal := makeVal(clock.Now(), txnID)
  1302  		s.AddRange(from, to, excludeFrom|excludeTo, nowVal)
  1303  	}
  1304  
  1305  	for i := 0; i <= 10; i++ {
  1306  		b.Run(fmt.Sprintf("frac_%d", i), func(b *testing.B) {
  1307  			var wg sync.WaitGroup
  1308  
  1309  			for p := 0; p < parallel; p++ {
  1310  				wg.Add(1)
  1311  
  1312  				go func(i int) {
  1313  					defer wg.Done()
  1314  
  1315  					rng := rand.New(rand.NewSource(timeutil.Now().UnixNano()))
  1316  
  1317  					for n := 0; n < b.N/parallel; n++ {
  1318  						readFrac := rng.Int31n(10)
  1319  						keyNum := rng.Int31n(max)
  1320  
  1321  						if readFrac < int32(i) {
  1322  							key := []byte(fmt.Sprintf("%020d", keyNum))
  1323  							s.LookupTimestamp(key)
  1324  						} else {
  1325  							from, to := makeRange(keyNum)
  1326  							nowVal := makeVal(clock.Now(), txnID)
  1327  							s.AddRange(from, to, excludeFrom|excludeTo, nowVal)
  1328  						}
  1329  					}
  1330  				}(i)
  1331  			}
  1332  
  1333  			wg.Wait()
  1334  		})
  1335  	}
  1336  }
  1337  
  1338  // makeRange creates a key range from the provided input. The range will start
  1339  // at the provided key and will have an end key that is a deterministic function
  1340  // of the provided key. This means that for a given input, the function will
  1341  // always produce the same range.
  1342  func makeRange(start int32) (from, to []byte) {
  1343  	var end int32
  1344  
  1345  	// Most ranges are small. Larger ranges are less and less likely.
  1346  	rem := start % 100
  1347  	if rem < 80 {
  1348  		end = start + 0
  1349  	} else if rem < 90 {
  1350  		end = start + 100
  1351  	} else if rem < 95 {
  1352  		end = start + 10000
  1353  	} else if rem < 99 {
  1354  		end = start + 1000000
  1355  	} else {
  1356  		end = start + 100000000
  1357  	}
  1358  
  1359  	from = []byte(fmt.Sprintf("%020d", start))
  1360  	to = []byte(fmt.Sprintf("%020d", end))
  1361  	return
  1362  }
  1363  
  1364  // randRange creates a random range with keys within the specified number of
  1365  // slots. The function also returns a middle key, if one exists.
  1366  func randRange(rng *rand.Rand, slots int) (from, middle, to []byte) {
  1367  	fromNum := rng.Intn(slots)
  1368  	toNum := rng.Intn(slots)
  1369  	if fromNum > toNum {
  1370  		fromNum, toNum = toNum, fromNum
  1371  	}
  1372  
  1373  	from = []byte(fmt.Sprintf("%05d", fromNum))
  1374  	to = []byte(fmt.Sprintf("%05d", toNum))
  1375  	if middleNum := fromNum + 1; middleNum < toNum {
  1376  		middle = []byte(fmt.Sprintf("%05d", middleNum))
  1377  	}
  1378  	return
  1379  }
  1380  
  1381  func randRangeOpt(rng *rand.Rand) rangeOptions {
  1382  	return rangeOptions(rng.Intn(int(excludeFrom|excludeTo) + 1))
  1383  }