@@ -11,8 +11,10 @@ import (
11
11
"testing"
12
12
13
13
"github.com/cockroachdb/cockroach/pkg/kv/kvpb"
14
+ "github.com/cockroachdb/cockroach/pkg/kv/kvserver/concurrency/lock"
14
15
"github.com/cockroachdb/cockroach/pkg/roachpb"
15
16
"github.com/cockroachdb/cockroach/pkg/storage/enginepb"
17
+ "github.com/cockroachdb/cockroach/pkg/testutils"
16
18
"github.com/cockroachdb/cockroach/pkg/util/leaktest"
17
19
"github.com/cockroachdb/cockroach/pkg/util/log"
18
20
"github.com/cockroachdb/errors"
@@ -825,3 +827,108 @@ func TestTxnWriteBufferServesOverlappingReadsCorrectly(t *testing.T) {
825
827
require .Len (t , br .Responses , 1 )
826
828
require .IsType (t , & kvpb.EndTxnResponse {}, br .Responses [0 ].GetInner ())
827
829
}
830
+
831
+ // TestTxnWriteBufferLockingGetRequests ensures that locking get requests are
832
+ // handled appropriately -- they're sent to KV, to acquire a lock, but the
833
+ // read is served from the buffer (upholding read-your-own-write semantics).
834
+ func TestTxnWriteBufferLockingGetRequests (t * testing.T ) {
835
+ defer leaktest .AfterTest (t )()
836
+ defer log .Scope (t ).Close (t )
837
+ ctx := context .Background ()
838
+ twb , mockSender := makeMockTxnWriteBuffer ()
839
+
840
+ txn := makeTxnProto ()
841
+ txn .Sequence = 10
842
+ keyA := roachpb .Key ("a" )
843
+ valA := "val"
844
+
845
+ // Blindly write to keys A.
846
+ ba := & kvpb.BatchRequest {}
847
+ ba .Header = kvpb.Header {Txn : & txn }
848
+ putA := putArgs (keyA , valA , txn .Sequence )
849
+ ba .Add (putA )
850
+
851
+ numCalled := mockSender .NumCalled ()
852
+ br , pErr := twb .SendLocked (ctx , ba )
853
+ require .Nil (t , pErr )
854
+ require .NotNil (t , br )
855
+ // All the requests should be buffered and not make it past the
856
+ // txnWriteBuffer.
857
+ require .Equal (t , numCalled , mockSender .NumCalled ())
858
+ // Even though the txnWriteBuffer did not send any Put requests to the KV
859
+ // layer above, the responses should still be populated.
860
+ require .Len (t , br .Responses , 1 )
861
+ require .Equal (t , br .Responses [0 ].GetInner (), & kvpb.PutResponse {})
862
+
863
+ // Verify the writes were buffered correctly.
864
+ expBufferedWrites := []bufferedWrite {
865
+ makeBufferedWrite (keyA , makeBufferedValue (valA , 10 )),
866
+ }
867
+ require .Equal (t , expBufferedWrites , twb .testingBufferedWritesAsSlice ())
868
+
869
+ // Perform a locking read on keyA. Ensure a request is sent to the KV layer,
870
+ // but the response is served from the buffer.
871
+ testutils .RunValues (t , "str" , []lock.Strength {lock .None , lock .Shared , lock .Exclusive , lock .Update }, func (t * testing.T , strength lock.Strength ) {
872
+ txn .Sequence = 11
873
+ ba = & kvpb.BatchRequest {}
874
+ ba .Header = kvpb.Header {Txn : & txn }
875
+ getA := & kvpb.GetRequest {
876
+ RequestHeader : kvpb.RequestHeader {Key : keyA , Sequence : txn .Sequence },
877
+ KeyLockingStrength : strength ,
878
+ }
879
+ ba .Add (getA )
880
+ numCalled = mockSender .NumCalled ()
881
+
882
+ mockSender .MockSend (func (ba * kvpb.BatchRequest ) (* kvpb.BatchResponse , * kvpb.Error ) {
883
+ require .Len (t , ba .Requests , 1 )
884
+ require .IsType (t , & kvpb.GetRequest {}, ba .Requests [0 ].GetInner ())
885
+ require .Equal (t , strength , ba .Requests [0 ].GetInner ().(* kvpb.GetRequest ).KeyLockingStrength )
886
+ require .True (t , strength != lock .None ) // non-locking Gets aren't sent to KV
887
+
888
+ br = ba .CreateReply ()
889
+ br .Txn = ba .Txn
890
+ return br , nil
891
+ })
892
+
893
+ br , pErr = twb .SendLocked (ctx , ba )
894
+ require .Nil (t , pErr )
895
+ require .NotNil (t , br )
896
+ require .Len (t , br .Responses , 1 )
897
+ require .Equal (t , roachpb .MakeValueFromString (valA ), * br .Responses [0 ].GetInner ().(* kvpb.GetResponse ).Value )
898
+
899
+ var expNumCalled int
900
+ if strength == lock .None {
901
+ expNumCalled = numCalled // nothing should be sent to KV
902
+ } else {
903
+ expNumCalled = numCalled + 1 // a locking request should still be sent to KV
904
+ }
905
+ require .Equal (t , expNumCalled , mockSender .NumCalled ())
906
+ })
907
+
908
+ // Lastly, for completeness, commit the transaction and ensure that the buffer
909
+ // is correctly flushed.
910
+ ba = & kvpb.BatchRequest {}
911
+ ba .Header = kvpb.Header {Txn : & txn }
912
+ ba .Add (& kvpb.EndTxnRequest {Commit : true })
913
+
914
+ mockSender .MockSend (func (ba * kvpb.BatchRequest ) (* kvpb.BatchResponse , * kvpb.Error ) {
915
+ require .Len (t , ba .Requests , 2 )
916
+
917
+ // We now expect the buffer to be flushed along with the commit.
918
+ require .IsType (t , & kvpb.PutRequest {}, ba .Requests [0 ].GetInner ())
919
+ require .IsType (t , & kvpb.EndTxnRequest {}, ba .Requests [1 ].GetInner ())
920
+
921
+ br = ba .CreateReply ()
922
+ br .Txn = ba .Txn
923
+ return br , nil
924
+ })
925
+
926
+ br , pErr = twb .SendLocked (ctx , ba )
927
+ require .Nil (t , pErr )
928
+ require .NotNil (t , br )
929
+
930
+ // Even though we flushed the buffer, responses from the blind writes should
931
+ // not be returned.
932
+ require .Len (t , br .Responses , 1 )
933
+ require .IsType (t , & kvpb.EndTxnResponse {}, br .Responses [0 ].GetInner ())
934
+ }
0 commit comments