Skip to content

Commit 17e2c52

Browse files
craig[bot]yuzefovich
andcommitted
Merge #148708
148708: kvcoord: fix memory leak on rollbacks in txnWriteBuffer in some cases r=yuzefovich a=yuzefovich Whenever we perform a rollback of the txnWriteBuffer, we need to remove buffered values that are at or above the given sequence number. If the whole buffered write is being rolled back, we delete it proper, but if only some buffered values are rolled back, then we only remove them but keep the `bufferedWrite`. Previously, we would decrement the buffer size accordingly but forgot to also unset the `bufferedValue`s that could be of non-trivial size. This is now fixed. Epic: None Release note: None Co-authored-by: Yahor Yuzefovich <[email protected]>
2 parents 3ae3365 + 9917f3c commit 17e2c52

File tree

2 files changed

+14
-1
lines changed

2 files changed

+14
-1
lines changed

pkg/kv/kvclient/kvcoord/txn_interceptor_write_buffer.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,12 @@ func (twb *txnWriteBuffer) rollbackToSavepointLocked(ctx context.Context, s save
673673
// Update size bookkeeping for the values we're rolling back.
674674
for i := idx; i < len(bufferedVals); i++ {
675675
twb.bufferSize -= bufferedVals[i].size()
676+
// Lose reference to the value since we're no longer tracking its
677+
// memory footprint.
678+
// TODO(yuzefovich): we also decremented the buffer size by the
679+
// struct overhead, yet we keep reusing the same slice, so we have
680+
// some slop in accounting.
681+
bufferedVals[i] = bufferedValue{}
676682
}
677683
// Rollback writes by truncating the buffered values.
678684
it.Cur().vals = bufferedVals[:idx]

pkg/kv/kvclient/kvcoord/txn_interceptor_write_buffer_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1751,7 +1751,7 @@ func TestTxnWriteBufferRollbackToSavepoint(t *testing.T) {
17511751
require.Len(t, br.Responses, 2)
17521752
require.IsType(t, &kvpb.PutResponse{}, br.Responses[0].GetInner())
17531753
require.IsType(t, &kvpb.DeleteResponse{}, br.Responses[1].GetInner())
1754-
// Verify the
1754+
// Verify the state of the write buffer.
17551755
expBufferedWrites := []bufferedWrite{
17561756
makeBufferedWrite(keyA, makeBufferedValue("valA", 10)),
17571757
makeBufferedWrite(keyC, makeBufferedValue("", 11)),
@@ -1797,6 +1797,13 @@ func TestTxnWriteBufferRollbackToSavepoint(t *testing.T) {
17971797
makeBufferedWrite(keyA, makeBufferedValue("valA", 10)),
17981798
}
17991799
require.Equal(t, expBufferedWrites, twb.testingBufferedWritesAsSlice())
1800+
// Additionally ensure that we don't have a leak of rolled back writes.
1801+
{
1802+
bw := twb.testingBufferedWritesAsSlice()[0]
1803+
require.Greaterf(t, cap(bw.vals), 1, "should have kept the capacity of the slice")
1804+
vals := bw.vals[:cap(bw.vals)]
1805+
require.Equalf(t, bufferedValue{}, vals[1], "should have lost reference to the rolled back value")
1806+
}
18001807

18011808
// Commit the transaction.
18021809
ba = &kvpb.BatchRequest{}

0 commit comments

Comments
 (0)