Skip to content

Commit a5d1090

Browse files
committed
kvcoord: track a write buffer transformation for all requests
Previously, the transaction write buffer kept a transformation for many requests: truly transformed requests (e.g. CPut), and other requests, like Get, which were not actually transformed but needed to be tracked in order to correctly be able to read your own writes. Scan requests, specifically, were not tracked as transformations, but should be, just like Gets (#146103). This commit tracks all requests as transformations regardless of whether they were actually transformed. For most requests, this is needed for correctness; for requests like QueryLocksRequest and LeaseInfoRequest, it is not necessary, but it is harmless and simplifies the code. Fixes: #146103 Release note: None
1 parent 1e26992 commit a5d1090

File tree

3 files changed

+28
-64
lines changed

3 files changed

+28
-64
lines changed

pkg/kv/kvclient/kvcoord/txn_interceptor_write_buffer.go

Lines changed: 22 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -675,13 +675,25 @@ func (twb *txnWriteBuffer) applyTransformations(
675675
var ts transformations
676676
for i, ru := range ba.Requests {
677677
req := ru.GetInner()
678+
// Track a transformation for the request regardless of the type, and
679+
// regardless of whether it was served from the buffer or not. For truly
680+
// transformed requests (e.g. CPut) this is expected. For Gets and Scans, we
681+
// need to track a transformation because we haven't buffered any writes
682+
// from our current batch in the buffer yet, so checking the buffer here, at
683+
// request time, isn't sufficient to determine whether the request needs to
684+
// serve a read from the buffer before returning a response or not.
685+
//
686+
// Only QueryLocksRequest and LeaseInfoRequest don't require a tracking
687+
// transformation, but it's harmless to add one, and it simplifies the code.
688+
//
689+
// The stripped field will be set below for specific stripped requests.
690+
tr := transformation{
691+
stripped: false,
692+
index: i,
693+
origRequest: req,
694+
}
678695
switch t := req.(type) {
679696
case *kvpb.ConditionalPutRequest:
680-
ts = append(ts, transformation{
681-
stripped: false,
682-
index: i,
683-
origRequest: req,
684-
})
685697
// NB: Regardless of whether there is already a buffered write on
686698
// this key or not, we need to send a locking Get to the KV layer to
687699
// acquire a lock. However, if we had knowledge of what locks the
@@ -720,11 +732,7 @@ func (twb *txnWriteBuffer) applyTransformations(
720732
})
721733
baRemote.Requests = append(baRemote.Requests, getReqU)
722734
}
723-
ts = append(ts, transformation{
724-
stripped: !t.MustAcquireExclusiveLock,
725-
index: i,
726-
origRequest: req,
727-
})
735+
tr.stripped = !t.MustAcquireExclusiveLock
728736

729737
case *kvpb.DeleteRequest:
730738
// If MustAcquireExclusiveLock flag is set on the DeleteRequest,
@@ -744,11 +752,7 @@ func (twb *txnWriteBuffer) applyTransformations(
744752
})
745753
baRemote.Requests = append(baRemote.Requests, getReqU)
746754
}
747-
ts = append(ts, transformation{
748-
stripped: !t.MustAcquireExclusiveLock,
749-
index: i,
750-
origRequest: req,
751-
})
755+
tr.stripped = !t.MustAcquireExclusiveLock
752756

753757
case *kvpb.GetRequest:
754758
// If the key is in the buffer, we must serve the read from the buffer.
@@ -779,45 +783,14 @@ func (twb *txnWriteBuffer) applyTransformations(
779783
// Wasn't served locally; send the request to the KV layer.
780784
baRemote.Requests = append(baRemote.Requests, ru)
781785
}
782-
// Even if the request wasn't served from the buffer here, we still track
783-
// a transformation for it. That's because we haven't buffered any writes
784-
// from our current batch in the buffer yet, so checking the buffer above
785-
// isn't sufficient to determine whether the request needs to serve a read
786-
// from the buffer before returning a response or not.
787-
ts = append(ts, transformation{
788-
stripped: stripped,
789-
index: i,
790-
origRequest: req,
791-
})
786+
tr.stripped = stripped
792787

793-
case *kvpb.ScanRequest:
794-
overlaps := twb.scanOverlaps(t.Key, t.EndKey)
795-
if overlaps {
796-
ts = append(ts, transformation{
797-
stripped: false,
798-
index: i,
799-
origRequest: req,
800-
})
801-
}
788+
case *kvpb.ScanRequest, *kvpb.ReverseScanRequest:
802789
// Regardless of whether the scan overlaps with any writes in the buffer
803790
// or not, we must send the request to the KV layer. We can't know for
804791
// sure that there's nothing else to read.
805792
baRemote.Requests = append(baRemote.Requests, ru)
806793

807-
case *kvpb.ReverseScanRequest:
808-
overlaps := twb.scanOverlaps(t.Key, t.EndKey)
809-
if overlaps {
810-
ts = append(ts, transformation{
811-
stripped: false,
812-
index: i,
813-
origRequest: req,
814-
})
815-
}
816-
// Similar to the reasoning above, regardless of whether the reverse
817-
// scan overlaps with any writes in the buffer or not, we must send
818-
// the request to the KV layer.
819-
baRemote.Requests = append(baRemote.Requests, ru)
820-
821794
case *kvpb.QueryLocksRequest, *kvpb.LeaseInfoRequest:
822795
// These requests don't interact with buffered writes, so we simply
823796
// let them through.
@@ -826,6 +799,7 @@ func (twb *txnWriteBuffer) applyTransformations(
826799
default:
827800
return nil, nil, kvpb.NewError(unsupportedMethodError(t.Method()))
828801
}
802+
ts = append(ts, tr)
829803
}
830804
return baRemote, ts, nil
831805
}
@@ -873,14 +847,6 @@ func (twb *txnWriteBuffer) maybeServeRead(
873847
return nil, false
874848
}
875849

876-
// scanOverlaps returns whether the given key range overlaps with any buffered
877-
// write.
878-
func (twb *txnWriteBuffer) scanOverlaps(key roachpb.Key, endKey roachpb.Key) bool {
879-
it := twb.buffer.MakeIter()
880-
it.FirstOverlap(twb.seekItemForSpan(key, endKey))
881-
return it.Valid()
882-
}
883-
884850
// mergeWithScanResp takes a ScanRequest, that was sent to the KV layer, and the
885851
// response returned by the KV layer, and merges it with any writes that were
886852
// buffered by the transaction to correctly uphold read-your-own-write

pkg/kv/kvclient/kvcoord/txn_interceptor_write_buffer_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -292,10 +292,10 @@ func TestTxnWriteBufferBlindWritesIncludingOtherRequests(t *testing.T) {
292292
// Expect 4 responses, even though only 2 KV requests were sent. Moreover,
293293
// ensure that the responses are in the correct order.
294294
require.Len(t, br.Responses, 4)
295-
require.Equal(t, br.Responses[0].GetInner(), &kvpb.PutResponse{})
296-
require.Equal(t, br.Responses[1].GetInner(), &kvpb.GetResponse{})
297-
require.Equal(t, br.Responses[2].GetInner(), &kvpb.DeleteResponse{})
298-
require.Equal(t, br.Responses[3].GetInner(), &kvpb.ScanResponse{})
295+
require.IsType(t, &kvpb.PutResponse{}, br.Responses[0].GetInner())
296+
require.IsType(t, &kvpb.GetResponse{}, br.Responses[1].GetInner())
297+
require.IsType(t, &kvpb.DeleteResponse{}, br.Responses[2].GetInner())
298+
require.IsType(t, &kvpb.ScanResponse{}, br.Responses[3].GetInner())
299299

300300
// Verify the writes were buffered correctly.
301301
expBufferedWrites := []bufferedWrite{

pkg/kv/kvclient/kvcoord/txn_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2308,12 +2308,10 @@ func TestTxnBufferedWriteReadYourOwnWrites(t *testing.T) {
23082308
b.Scan(keyB, keyC)
23092309
return b
23102310
},
2311-
// The Scans should see the values written preceding in the same batch,
2312-
// but currently they don't because of a bug (#146103) that doesn't add
2313-
// always add a transformation for a Scan request.
2311+
// The Scans should see the values written preceding in the same batch.
23142312
expected: map[int32]map[string][]byte{
23152313
0: {"keyB": value22},
2316-
2: {"keyB": value22},
2314+
2: {"keyB": value3},
23172315
},
23182316
},
23192317
// TODO(mira): See if we need more test coverage for other request types

0 commit comments

Comments
 (0)