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 }