github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/batcheval/cmd_clear_range_test.go (about) 1 // Copyright 2017 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 batcheval 12 13 import ( 14 "context" 15 "fmt" 16 "strings" 17 "testing" 18 "time" 19 20 "github.com/cockroachdb/cockroach/pkg/roachpb" 21 "github.com/cockroachdb/cockroach/pkg/storage" 22 "github.com/cockroachdb/cockroach/pkg/storage/enginepb" 23 "github.com/cockroachdb/cockroach/pkg/util/hlc" 24 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 25 "github.com/cockroachdb/errors" 26 ) 27 28 type wrappedBatch struct { 29 storage.Batch 30 clearCount int 31 clearRangeCount int 32 } 33 34 func (wb *wrappedBatch) Clear(key storage.MVCCKey) error { 35 wb.clearCount++ 36 return wb.Batch.Clear(key) 37 } 38 39 func (wb *wrappedBatch) ClearRange(start, end storage.MVCCKey) error { 40 wb.clearRangeCount++ 41 return wb.Batch.ClearRange(start, end) 42 } 43 44 // TestCmdClearRangeBytesThreshold verifies that clear range resorts to 45 // clearing keys individually if under the bytes threshold and issues a 46 // clear range command to the batch otherwise. 47 func TestCmdClearRangeBytesThreshold(t *testing.T) { 48 defer leaktest.AfterTest(t)() 49 50 startKey := roachpb.Key("0000") 51 endKey := roachpb.Key("9999") 52 desc := roachpb.RangeDescriptor{ 53 RangeID: 99, 54 StartKey: roachpb.RKey(startKey), 55 EndKey: roachpb.RKey(endKey), 56 } 57 valueStr := strings.Repeat("0123456789", 1024) 58 var value roachpb.Value 59 value.SetString(valueStr) // 10KiB 60 halfFull := ClearRangeBytesThreshold / (2 * len(valueStr)) 61 overFull := ClearRangeBytesThreshold/len(valueStr) + 1 62 tests := []struct { 63 keyCount int 64 expClearCount int 65 expClearRangeCount int 66 }{ 67 { 68 keyCount: 1, 69 expClearCount: 1, 70 expClearRangeCount: 0, 71 }, 72 // More than a single key, but not enough to use ClearRange. 73 { 74 keyCount: halfFull, 75 expClearCount: halfFull, 76 expClearRangeCount: 0, 77 }, 78 // With key sizes requiring additional space, this will overshoot. 79 { 80 keyCount: overFull, 81 expClearCount: 0, 82 expClearRangeCount: 1, 83 }, 84 } 85 86 for _, test := range tests { 87 t.Run("", func(t *testing.T) { 88 ctx := context.Background() 89 eng := storage.NewDefaultInMem() 90 defer eng.Close() 91 92 var stats enginepb.MVCCStats 93 for i := 0; i < test.keyCount; i++ { 94 key := roachpb.Key(fmt.Sprintf("%04d", i)) 95 if err := storage.MVCCPut(ctx, eng, &stats, key, hlc.Timestamp{WallTime: int64(i % 2)}, value, nil); err != nil { 96 t.Fatal(err) 97 } 98 } 99 100 batch := &wrappedBatch{Batch: eng.NewBatch()} 101 defer batch.Close() 102 103 var h roachpb.Header 104 h.RangeID = desc.RangeID 105 106 cArgs := CommandArgs{Header: h} 107 cArgs.EvalCtx = (&MockEvalCtx{Desc: &desc, Clock: hlc.NewClock(hlc.UnixNano, time.Nanosecond), Stats: stats}).EvalContext() 108 cArgs.Args = &roachpb.ClearRangeRequest{ 109 RequestHeader: roachpb.RequestHeader{ 110 Key: startKey, 111 EndKey: endKey, 112 }, 113 } 114 cArgs.Stats = &enginepb.MVCCStats{} 115 116 if _, err := ClearRange(ctx, batch, cArgs, &roachpb.ClearRangeResponse{}); err != nil { 117 t.Fatal(err) 118 } 119 120 // Verify cArgs.Stats is equal to the stats we wrote. 121 newStats := stats 122 newStats.SysBytes, newStats.SysCount = 0, 0 // ignore these values 123 cArgs.Stats.SysBytes, cArgs.Stats.SysCount = 0, 0 // these too, as GC threshold is updated 124 newStats.Add(*cArgs.Stats) 125 newStats.AgeTo(0) // pin at LastUpdateNanos==0 126 if !newStats.Equal(enginepb.MVCCStats{}) { 127 t.Errorf("expected stats on original writes to be negated on clear range: %+v vs %+v", stats, *cArgs.Stats) 128 } 129 130 // Verify we see the correct counts for Clear and ClearRange. 131 if a, e := batch.clearCount, test.expClearCount; a != e { 132 t.Errorf("expected %d clears; got %d", e, a) 133 } 134 if a, e := batch.clearRangeCount, test.expClearRangeCount; a != e { 135 t.Errorf("expected %d clear ranges; got %d", e, a) 136 } 137 138 // Now ensure that the data is gone, whether it was a ClearRange or individual calls to clear. 139 if err := batch.Commit(true /* commit */); err != nil { 140 t.Fatal(err) 141 } 142 if err := eng.Iterate(startKey, endKey, 143 func(kv storage.MVCCKeyValue) (bool, error) { 144 return true, errors.New("expected no data in underlying engine") 145 }, 146 ); err != nil { 147 t.Fatal(err) 148 } 149 }) 150 } 151 }