github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ccl/followerreadsccl/followerreads_test.go (about)

     1  // Copyright 2019 The Cockroach Authors.
     2  //
     3  // Licensed as a CockroachDB Enterprise file under the Cockroach Community
     4  // License (the "License"); you may not use this file except in compliance with
     5  // the License. You may obtain a copy of the License at
     6  //
     7  //     https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt
     8  
     9  package followerreadsccl
    10  
    11  import (
    12  	"context"
    13  	"reflect"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/ccl/utilccl"
    18  	"github.com/cockroachdb/cockroach/pkg/kv"
    19  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver"
    20  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    21  	"github.com/cockroachdb/cockroach/pkg/rpc"
    22  	"github.com/cockroachdb/cockroach/pkg/settings/cluster"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/physicalplan/replicaoracle"
    24  	"github.com/cockroachdb/cockroach/pkg/storage/enginepb"
    25  	"github.com/cockroachdb/cockroach/pkg/testutils"
    26  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    27  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    28  	"github.com/cockroachdb/cockroach/pkg/util/log"
    29  	"github.com/cockroachdb/cockroach/pkg/util/stop"
    30  	"github.com/cockroachdb/cockroach/pkg/util/timeutil"
    31  	"github.com/cockroachdb/cockroach/pkg/util/tracing"
    32  	"github.com/cockroachdb/cockroach/pkg/util/uuid"
    33  )
    34  
    35  const (
    36  	defaultInterval                          = 3
    37  	defaultFraction                          = .2
    38  	defaultMultiple                          = 3
    39  	expectedFollowerReadOffset time.Duration = 1e9 * /* 1 second */
    40  		-defaultInterval * (1 + defaultFraction*defaultMultiple)
    41  )
    42  
    43  func TestEvalFollowerReadOffset(t *testing.T) {
    44  	defer leaktest.AfterTest(t)()
    45  	disableEnterprise := utilccl.TestingEnableEnterprise()
    46  	defer disableEnterprise()
    47  	st := cluster.MakeTestingClusterSettings()
    48  	if offset, err := evalFollowerReadOffset(uuid.MakeV4(), st); err != nil {
    49  		t.Fatal(err)
    50  	} else if offset != expectedFollowerReadOffset {
    51  		t.Fatalf("expected %v, got %v", expectedFollowerReadOffset, offset)
    52  	}
    53  	disableEnterprise()
    54  	_, err := evalFollowerReadOffset(uuid.MakeV4(), st)
    55  	if !testutils.IsError(err, "requires an enterprise license") {
    56  		t.Fatalf("failed to get error when evaluating follower read offset without " +
    57  			"an enterprise license")
    58  	}
    59  }
    60  
    61  func TestCanSendToFollower(t *testing.T) {
    62  	defer leaktest.AfterTest(t)()
    63  	disableEnterprise := utilccl.TestingEnableEnterprise()
    64  	defer disableEnterprise()
    65  	st := cluster.MakeTestingClusterSettings()
    66  	kvserver.FollowerReadsEnabled.Override(&st.SV, true)
    67  
    68  	old := hlc.Timestamp{
    69  		WallTime: timeutil.Now().Add(2 * expectedFollowerReadOffset).UnixNano(),
    70  	}
    71  	oldHeader := roachpb.Header{Txn: &roachpb.Transaction{
    72  		ReadTimestamp: old,
    73  	}}
    74  	rw := roachpb.BatchRequest{Header: oldHeader}
    75  	rw.Add(&roachpb.PutRequest{})
    76  	if canSendToFollower(uuid.MakeV4(), st, rw) {
    77  		t.Fatalf("should not be able to send a rw request to a follower")
    78  	}
    79  	roNonTxn := roachpb.BatchRequest{Header: oldHeader}
    80  	roNonTxn.Add(&roachpb.QueryTxnRequest{})
    81  	if canSendToFollower(uuid.MakeV4(), st, roNonTxn) {
    82  		t.Fatalf("should not be able to send a non-transactional ro request to a follower")
    83  	}
    84  	roNoTxn := roachpb.BatchRequest{}
    85  	roNoTxn.Add(&roachpb.GetRequest{})
    86  	if canSendToFollower(uuid.MakeV4(), st, roNoTxn) {
    87  		t.Fatalf("should not be able to send a batch with no txn to a follower")
    88  	}
    89  	roOld := roachpb.BatchRequest{Header: oldHeader}
    90  	roOld.Add(&roachpb.GetRequest{})
    91  	if !canSendToFollower(uuid.MakeV4(), st, roOld) {
    92  		t.Fatalf("should be able to send an old ro batch to a follower")
    93  	}
    94  	roRWTxnOld := roachpb.BatchRequest{Header: roachpb.Header{
    95  		Txn: &roachpb.Transaction{
    96  			TxnMeta:       enginepb.TxnMeta{Key: []byte("key")},
    97  			ReadTimestamp: old,
    98  		},
    99  	}}
   100  	roRWTxnOld.Add(&roachpb.GetRequest{})
   101  	if canSendToFollower(uuid.MakeV4(), st, roRWTxnOld) {
   102  		t.Fatalf("should not be able to send a ro request from a rw txn to a follower")
   103  	}
   104  	kvserver.FollowerReadsEnabled.Override(&st.SV, false)
   105  	if canSendToFollower(uuid.MakeV4(), st, roOld) {
   106  		t.Fatalf("should not be able to send an old ro batch to a follower when follower reads are disabled")
   107  	}
   108  	kvserver.FollowerReadsEnabled.Override(&st.SV, true)
   109  	roNew := roachpb.BatchRequest{Header: roachpb.Header{
   110  		Txn: &roachpb.Transaction{
   111  			ReadTimestamp: hlc.Timestamp{WallTime: timeutil.Now().UnixNano()},
   112  		},
   113  	}}
   114  	if canSendToFollower(uuid.MakeV4(), st, roNew) {
   115  		t.Fatalf("should not be able to send a new ro batch to a follower")
   116  	}
   117  	roOldWithNewMax := roachpb.BatchRequest{Header: roachpb.Header{
   118  		Txn: &roachpb.Transaction{
   119  			MaxTimestamp: hlc.Timestamp{WallTime: timeutil.Now().UnixNano()},
   120  		},
   121  	}}
   122  	roOldWithNewMax.Add(&roachpb.GetRequest{})
   123  	if canSendToFollower(uuid.MakeV4(), st, roNew) {
   124  		t.Fatalf("should not be able to send a ro batch with new MaxTimestamp to a follower")
   125  	}
   126  	disableEnterprise()
   127  	if canSendToFollower(uuid.MakeV4(), st, roOld) {
   128  		t.Fatalf("should not be able to send an old ro batch to a follower without enterprise enabled")
   129  	}
   130  }
   131  
   132  func TestFollowerReadMultipleValidation(t *testing.T) {
   133  	defer leaktest.AfterTest(t)()
   134  	defer func() {
   135  		if r := recover(); r == nil {
   136  			t.Fatalf("expected panic from setting followerReadMultiple to .1")
   137  		}
   138  	}()
   139  	st := cluster.MakeTestingClusterSettings()
   140  	followerReadMultiple.Override(&st.SV, .1)
   141  }
   142  
   143  // TestOracle tests the OracleFactory exposed by this package.
   144  // This test ends up being rather indirect but works by checking if the type
   145  // of the oracle returned from the factory differs between requests we'd
   146  // expect to support follower reads and that which we'd expect not to.
   147  func TestOracleFactory(t *testing.T) {
   148  	defer leaktest.AfterTest(t)()
   149  	disableEnterprise := utilccl.TestingEnableEnterprise()
   150  	defer disableEnterprise()
   151  	st := cluster.MakeTestingClusterSettings()
   152  	kvserver.FollowerReadsEnabled.Override(&st.SV, true)
   153  	clock := hlc.NewClock(hlc.UnixNano, time.Nanosecond)
   154  	stopper := stop.NewStopper()
   155  	defer stopper.Stop(context.Background())
   156  	rpcContext := rpc.NewInsecureTestingContext(clock, stopper)
   157  	c := kv.NewDB(log.AmbientContext{
   158  		Tracer: tracing.NewTracer(),
   159  	}, kv.MockTxnSenderFactory{},
   160  		hlc.NewClock(hlc.UnixNano, time.Nanosecond))
   161  	txn := kv.NewTxn(context.Background(), c, 0)
   162  	of := replicaoracle.NewOracleFactory(followerReadAwareChoice, replicaoracle.Config{
   163  		Settings:   st,
   164  		RPCContext: rpcContext,
   165  	})
   166  	noFollowerReadOracle := of.Oracle(txn)
   167  	old := hlc.Timestamp{
   168  		WallTime: timeutil.Now().Add(2 * expectedFollowerReadOffset).UnixNano(),
   169  	}
   170  	txn.SetFixedTimestamp(context.Background(), old)
   171  	followerReadOracle := of.Oracle(txn)
   172  	if reflect.TypeOf(followerReadOracle) == reflect.TypeOf(noFollowerReadOracle) {
   173  		t.Fatalf("expected types of %T and %T to differ", followerReadOracle,
   174  			noFollowerReadOracle)
   175  	}
   176  	disableEnterprise()
   177  	disabledFollowerReadOracle := of.Oracle(txn)
   178  	if reflect.TypeOf(disabledFollowerReadOracle) != reflect.TypeOf(noFollowerReadOracle) {
   179  		t.Fatalf("expected types of %T and %T not to differ", disabledFollowerReadOracle,
   180  			noFollowerReadOracle)
   181  	}
   182  }