github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/client_rangefeed_test.go (about) 1 // Copyright 2020 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 kvserver_test 12 13 import ( 14 "context" 15 "testing" 16 17 "github.com/cockroachdb/cockroach/pkg/base" 18 "github.com/cockroachdb/cockroach/pkg/keys" 19 "github.com/cockroachdb/cockroach/pkg/kv" 20 "github.com/cockroachdb/cockroach/pkg/kv/kvclient/kvcoord" 21 "github.com/cockroachdb/cockroach/pkg/kv/kvserver" 22 "github.com/cockroachdb/cockroach/pkg/roachpb" 23 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 24 "github.com/cockroachdb/cockroach/pkg/testutils/testcluster" 25 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 26 "github.com/stretchr/testify/require" 27 ) 28 29 // TestRangefeedWorksOnSystemRangesUnconditionally ensures that a rangefeed will 30 // not return an error when operating on a system span even if the setting is 31 // disabled. The test also ensures that an error is received if a rangefeed is 32 // run on a user table. 33 func TestRangefeedWorksOnSystemRangesUnconditionally(t *testing.T) { 34 defer leaktest.AfterTest(t)() 35 36 ctx := context.Background() 37 tc := testcluster.StartTestCluster(t, 3, base.TestClusterArgs{}) 38 defer tc.Stopper().Stop(ctx) 39 40 // Make sure the rangefeed setting really is disabled. 41 _, err := tc.ServerConn(0).Exec("SET CLUSTER SETTING kv.rangefeed.enabled = false") 42 require.NoError(t, err) 43 44 db := tc.Server(0).DB() 45 ds := tc.Server(0).DistSenderI().(*kvcoord.DistSender) 46 47 t.Run("works on system ranges", func(t *testing.T) { 48 startTS := db.Clock().Now() 49 descTableKey := keys.SystemSQLCodec.TablePrefix(keys.DescriptorTableID) 50 descTableSpan := roachpb.Span{ 51 Key: descTableKey, 52 EndKey: descTableKey.PrefixEnd(), 53 } 54 55 evChan := make(chan *roachpb.RangeFeedEvent) 56 rangefeedErrChan := make(chan error, 1) 57 ctxToCancel, cancel := context.WithCancel(ctx) 58 go func() { 59 rangefeedErrChan <- ds.RangeFeed(ctxToCancel, descTableSpan, startTS, false /* withDiff */, evChan) 60 }() 61 62 // Note: 42 is a system descriptor. 63 const junkDescriptorID = 42 64 require.GreaterOrEqual(t, keys.MaxReservedDescID, junkDescriptorID) 65 junkDescriptorKey := sqlbase.MakeDescMetadataKey(keys.SystemSQLCodec, junkDescriptorID) 66 junkDescriptor := sqlbase.WrapDescriptor(&sqlbase.DatabaseDescriptor{ 67 Name: "junk", 68 ID: junkDescriptorID, 69 }) 70 require.NoError(t, db.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error { 71 if err := txn.SetSystemConfigTrigger(); err != nil { 72 return err 73 } 74 return txn.Put(ctx, junkDescriptorKey, junkDescriptor) 75 })) 76 after := db.Clock().Now() 77 for { 78 ev := <-evChan 79 if ev.Checkpoint != nil && after.Less(ev.Checkpoint.ResolvedTS) { 80 t.Fatal("expected to see write which occurred before the checkpoint") 81 } 82 83 if ev.Val != nil && ev.Val.Key.Equal(junkDescriptorKey) { 84 var gotProto sqlbase.Descriptor 85 require.NoError(t, ev.Val.Value.GetProto(&gotProto)) 86 require.EqualValues(t, junkDescriptor, &gotProto) 87 break 88 } 89 } 90 cancel() 91 // There are several cases that seems like they can happen due 92 // to closed connections. Instead we just expect an error. 93 // The main point is we get an error in a timely manner. 94 require.Error(t, <-rangefeedErrChan) 95 }) 96 t.Run("does not work on user ranges", func(t *testing.T) { 97 k := tc.ScratchRange(t) 98 require.NoError(t, tc.WaitForSplitAndInitialization(k)) 99 startTS := db.Clock().Now() 100 scratchSpan := roachpb.Span{Key: k, EndKey: k.PrefixEnd()} 101 evChan := make(chan *roachpb.RangeFeedEvent) 102 require.Regexp(t, `rangefeeds require the kv\.rangefeed.enabled setting`, 103 ds.RangeFeed(ctx, scratchSpan, startTS, false /* withDiff */, evChan)) 104 }) 105 } 106 107 // TestMergeOfRangeEventTableWhileRunningRangefeed ensures that it is safe 108 // for a range merge transaction which has laid down intents on the RHS of the 109 // merge commit while a rangefeed is running on the RHS. At the time of writing, 110 // the only such range that this can happen to is the RangeEventTable. 111 func TestMergeOfRangeEventTableWhileRunningRangefeed(t *testing.T) { 112 defer leaktest.AfterTest(t)() 113 114 tc := testcluster.StartTestCluster(t, 1, base.TestClusterArgs{ 115 // Using ReplicationManual will disable the merge queue. 116 ReplicationMode: base.ReplicationManual, 117 }) 118 ctx := context.Background() 119 defer tc.Stopper().Stop(ctx) 120 121 // Set a short closed timestamp interval so that we don't need to wait long 122 // for resolved events off of the rangefeed later. 123 _, err := tc.ServerConn(0).Exec( 124 "SET CLUSTER SETTING kv.closed_timestamp.target_duration = '10ms'") 125 require.NoError(t, err) 126 127 // Find the range containing the range event table and then find the range 128 // to its left. 129 rangeEventTableStart := keys.SystemSQLCodec.TablePrefix(keys.RangeEventTableID) 130 require.NoError(t, tc.WaitForSplitAndInitialization(rangeEventTableStart)) 131 store, _ := getFirstStoreReplica(t, tc.Server(0), rangeEventTableStart) 132 var lhsRepl *kvserver.Replica 133 store.VisitReplicas(func(repl *kvserver.Replica) (wantMore bool) { 134 if repl.Desc().EndKey.AsRawKey().Equal(rangeEventTableStart) { 135 lhsRepl = repl 136 return false 137 } 138 return true 139 }) 140 require.NotNil(t, lhsRepl) 141 142 // Set up a rangefeed for the lhs. 143 db := tc.Server(0).DB() 144 ds := tc.Server(0).DistSenderI().(*kvcoord.DistSender) 145 146 rangefeedCtx, cancel := context.WithCancel(ctx) 147 defer cancel() 148 rangefeedErrChan := make(chan error, 1) 149 // Make the buffer large so we don't risk blocking. 150 eventCh := make(chan *roachpb.RangeFeedEvent, 1000) 151 start := db.Clock().Now() 152 go func() { 153 rangefeedErrChan <- ds.RangeFeed(rangefeedCtx, 154 lhsRepl.Desc().RSpan().AsRawSpanWithNoLocals(), 155 start, 156 false, /* withDiff */ 157 eventCh) 158 }() 159 160 // Wait for an event on the rangefeed to let us know that we're connected. 161 <-eventCh 162 163 // Merge the range event table range with its lhs neighbor. 164 require.NoError(t, db.AdminMerge(ctx, lhsRepl.Desc().StartKey.AsRawKey())) 165 166 // Ensure that we get a checkpoint after the merge. 167 afterMerge := db.Clock().Now() 168 for ev := range eventCh { 169 if ev.Checkpoint == nil { 170 continue 171 } 172 if afterMerge.Less(ev.Checkpoint.ResolvedTS) { 173 break 174 } 175 } 176 177 // Cancel the rangefeed and ensure we get the right error. 178 cancel() 179 require.Regexp(t, context.Canceled.Error(), <-rangefeedErrChan) 180 }