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 }