github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvclient/kvcoord/batch_test.go (about)

     1  // Copyright 2015 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package kvcoord
    12  
    13  import (
    14  	"bytes"
    15  	"testing"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/keys"
    18  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    19  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    20  )
    21  
    22  // TestBatchPrevNext tests prev() and next()
    23  func TestBatchPrevNext(t *testing.T) {
    24  	defer leaktest.AfterTest(t)()
    25  	loc := func(s string) string {
    26  		return string(keys.RangeDescriptorKey(roachpb.RKey(s)))
    27  	}
    28  	span := func(strs ...string) []roachpb.Span {
    29  		var r []roachpb.Span
    30  		for i, str := range strs {
    31  			if i%2 == 0 {
    32  				r = append(r, roachpb.Span{Key: roachpb.Key(str)})
    33  			} else {
    34  				r[len(r)-1].EndKey = roachpb.Key(str)
    35  			}
    36  		}
    37  		return r
    38  	}
    39  	max, min := string(roachpb.RKeyMax), string(roachpb.RKeyMin)
    40  	abc := span("a", "", "b", "", "c", "")
    41  	testCases := []struct {
    42  		spans             []roachpb.Span
    43  		key, expFW, expBW string
    44  	}{
    45  		{spans: span(), key: "whatevs",
    46  			// Sanity check for empty batch.
    47  			expFW: max,
    48  			expBW: min,
    49  		},
    50  		{spans: span("a", "b", "c", "d"), key: "c",
    51  			// Done with `key < c`, so `c <= key` next.
    52  			expFW: "c",
    53  			// This is the interesting case in this test. See
    54  			// https://github.com/cockroachdb/cockroach/issues/18174
    55  			//
    56  			// Done with `key >= c`, and nothing's in `[b, c)`, so all that's
    57  			// left is `key < b`. Before fixing #18174 we would end up at `c`
    58  			// which could create empty batches.
    59  			expBW: "b",
    60  		},
    61  		{spans: span("a", "c", "b", ""), key: "b",
    62  			// Done with `key < b`, so `b <= key` is next.
    63  			expFW: "b",
    64  			// Done with `key >= b`, but we have work to do for `b > key`.
    65  			expBW: "b",
    66  		},
    67  		{spans: span("a", "c", "b", ""), key: "a",
    68  			// Same as last one.
    69  			expFW: "a",
    70  			// Same as the first test case, except we drop all the way to `min`.
    71  			expBW: min,
    72  		},
    73  		{spans: span("a", "c", "d", ""), key: "c",
    74  			// Having dealt with `key < c` there's a gap which leaves us at `d <= key`.
    75  			expFW: "d",
    76  			// Nothing exciting: [a, c) is outstanding.
    77  			expBW: "c",
    78  		},
    79  		{spans: span("a", "c\x00", "d", ""), key: "c",
    80  			// First request overlaps `c` in both directions,
    81  			// so that's where we stay.
    82  			expFW: "c",
    83  			expBW: "c",
    84  		},
    85  		{spans: abc, key: "b",
    86  			// We've seen `key < b` so we still need to hit `b`.
    87  			expFW: "b",
    88  			// We've seen `key >= b`, so hop over the gap to `a`. Similar to the
    89  			// first test case.
    90  			expBW: "a",
    91  		},
    92  		{spans: abc, key: "b\x00",
    93  			// No surprises.
    94  			expFW: "c",
    95  			expBW: "b",
    96  		},
    97  		{spans: abc, key: "bb",
    98  			// Ditto.
    99  			expFW: "c",
   100  			expBW: "b",
   101  		},
   102  
   103  		// Multiple candidates. No surprises, just a sanity check.
   104  		{spans: span("a", "b", "c", "d"), key: "e",
   105  			expFW: max,
   106  			expBW: "d",
   107  		},
   108  		{spans: span("a", "b", "c", "d"), key: "0",
   109  			expFW: "a",
   110  			expBW: min,
   111  		},
   112  
   113  		// Local keys are tricky. See keys.AddrUpperBound for a comment. The basic
   114  		// intuition should be that /Local/a/b lives between a and a\x00 (for any b)
   115  		// and so the smallest address-resolved range that covers /Local/a/b is [a, a\x00].
   116  		{spans: span(loc("a"), loc("c")), key: "c",
   117  			// We're done with any key that addresses to `< c`, and `loc(c)` isn't covered
   118  			// by that. `loc(c)` lives between `c` and `c\x00` and so `c` is where we have
   119  			// to start in forward mode.
   120  			expFW: "c",
   121  			// We're done with any key that addresses to `>=c`, `loc(c)` is the exclusive
   122  			// end key here, so we next handle `key < c`.
   123  			expBW: "c",
   124  		},
   125  		{spans: span(loc("a"), loc("c")), key: "c\x00",
   126  			// We've dealt with everything addressing to `< c\x00`, and in particular
   127  			// `addr(loc(c)) < c\x00`, so that span is handled and we see `max`.
   128  			expFW: max,
   129  			// Having dealt with `>= c\x00` we have to restart at `c\x00` itself (and not `c`!)
   130  			// because otherwise we'd not see the local keys `/Local/c/x` which are not in `key < c`
   131  			// but are in `key < c\x00`.
   132  			expBW: "c\x00",
   133  		},
   134  		// Explanations below are an exercise for the reader, but it's very similar to above.
   135  		{spans: span(loc("b"), ""), key: "a",
   136  			expFW: "b",
   137  			expBW: min,
   138  		},
   139  		{spans: span(loc("b"), ""), key: "b",
   140  			expFW: "b",
   141  			expBW: min,
   142  		},
   143  		{spans: span(loc("b"), ""), key: "b\x00",
   144  			expFW: max,
   145  			// Handled `key >= b\x00`, so next we'll have to chip away at `[KeyMin, b\x00)`. Note
   146  			// how this doesn't return `b` which would be incorrect as `[KeyMin, b)` does not
   147  			// contain `loc(b)`.
   148  			expBW: "b\x00",
   149  		},
   150  
   151  		// Multiple candidates. No surprises, just a sanity check.
   152  		{spans: span(loc("a"), loc("b"), loc("c"), loc("d")), key: "e",
   153  			expFW: max,
   154  			expBW: "d\x00",
   155  		},
   156  		{spans: span(loc("a"), loc("b"), loc("c"), loc("d")), key: "0",
   157  			expFW: "a",
   158  			expBW: min,
   159  		},
   160  	}
   161  
   162  	for _, test := range testCases {
   163  		t.Run("", func(t *testing.T) {
   164  			var ba roachpb.BatchRequest
   165  			for _, span := range test.spans {
   166  				args := &roachpb.ScanRequest{}
   167  				args.Key, args.EndKey = span.Key, span.EndKey
   168  				ba.Add(args)
   169  			}
   170  			if next, err := next(ba, roachpb.RKey(test.key)); err != nil {
   171  				t.Error(err)
   172  			} else if !bytes.Equal(next, roachpb.Key(test.expFW)) {
   173  				t.Errorf("next: expected %q, got %q", test.expFW, next)
   174  			}
   175  			if prev, err := prev(ba, roachpb.RKey(test.key)); err != nil {
   176  				t.Error(err)
   177  			} else if !bytes.Equal(prev, roachpb.Key(test.expBW)) {
   178  				t.Errorf("prev: expected %q, got %q", test.expBW, prev)
   179  			}
   180  		})
   181  	}
   182  }