@@ -671,6 +671,65 @@ func TestTxnWriteBufferServesPointReadsLocally(t *testing.T) {
671671 require .IsType (t , & kvpb.EndTxnResponse {}, br .Responses [0 ].GetInner ())
672672}
673673
674+ // TestTxnWriteBufferServesPointReadsAfterScan is a regression test
675+ // for a bug in which reused iterator state resulted in the end key of
676+ // a scan affecting subsequent GetRequests.
677+ func TestTxnWriteBufferServesPointReadsAfterScan (t * testing.T ) {
678+ defer leaktest .AfterTest (t )()
679+ defer log .Scope (t ).Close (t )
680+ ctx := context .Background ()
681+ twb , mockSender := makeMockTxnWriteBuffer ()
682+
683+ txn := makeTxnProto ()
684+ txn .Sequence = 10
685+ keyA , keyB , keyC := roachpb .Key ("a" ), roachpb .Key ("b" ), roachpb .Key ("c" )
686+
687+ ba := & kvpb.BatchRequest {}
688+ ba .Header = kvpb.Header {Txn : & txn }
689+ ba .Add (putArgs (keyA , "valA" , txn .Sequence ))
690+ ba .Add (putArgs (keyB , "valB" , txn .Sequence ))
691+ ba .Add (putArgs (keyC , "valC" , txn .Sequence ))
692+ numCalled := mockSender .NumCalled ()
693+ br , pErr := twb .SendLocked (ctx , ba )
694+ require .Nil (t , pErr )
695+ require .NotNil (t , br )
696+ // All writes should be buffered.
697+ require .Equal (t , numCalled , mockSender .NumCalled ())
698+
699+ // First, read [a, c) via ScanRequest.
700+ txn .Sequence = 10
701+ ba = & kvpb.BatchRequest {}
702+ ba .Header = kvpb.Header {Txn : & txn }
703+ ba .Add (& kvpb.ScanRequest {
704+ RequestHeader : kvpb.RequestHeader {Key : keyA , EndKey : keyC , Sequence : txn .Sequence },
705+ })
706+ mockSender .MockSend (func (ba * kvpb.BatchRequest ) (* kvpb.BatchResponse , * kvpb.Error ) {
707+ require .Len (t , ba .Requests , 1 )
708+ require .IsType (t , & kvpb.ScanRequest {}, ba .Requests [0 ].GetInner ())
709+ br = ba .CreateReply ()
710+ br .Txn = ba .Txn
711+ return br , nil
712+ })
713+ br , pErr = twb .SendLocked (ctx , ba )
714+ require .Nil (t , pErr )
715+ require .NotNil (t , br )
716+ require .Len (t , br .Responses , 1 )
717+ require .Equal (t , int64 (2 ), br .Responses [0 ].GetScan ().NumKeys )
718+
719+ // Perform a read on keyC.
720+ ba = & kvpb.BatchRequest {}
721+ getC := & kvpb.GetRequest {RequestHeader : kvpb.RequestHeader {Key : keyC , Sequence : txn .Sequence }}
722+ ba .Add (getC )
723+
724+ numCalled = mockSender .NumCalled ()
725+ br , pErr = twb .SendLocked (ctx , ba )
726+ require .Nil (t , pErr )
727+ require .NotNil (t , br )
728+ require .Len (t , br .Responses , 1 )
729+ require .True (t , br .Responses [0 ].GetGet ().Value .IsPresent ())
730+ require .Equal (t , mockSender .NumCalled (), numCalled )
731+ }
732+
674733// TestTxnWriteBufferServesOverlappingReadsCorrectly ensures that Scan and
675734// ReverseScan requests that overlap with buffered writes are correctly served
676735// from the buffer.
0 commit comments