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  }