Skip to content

Commit 33c0b2e

Browse files
craig[bot]stevendanna
andcommitted
Merge #153514
153514: kvcoord: use separate flush for EndTxn with Prepare=true r=yuzefovich a=stevendanna Because of #153513 it is not safe to send a batch with writes and an EndTxn where Prepare=true as it might be immediately committed as a 1PC transaction. I've forgone a release note here because as far as I can tell XA-transactions are not yet a documented feature. Informs #153513 Fixes #144252 Release note: None Co-authored-by: Steven Danna <[email protected]>
2 parents 99b8703 + 1ed2c05 commit 33c0b2e

File tree

5 files changed

+38
-17
lines changed

5 files changed

+38
-17
lines changed

pkg/ccl/multitenantccl/tenantcapabilitiesccl/testdata/can_prepare_txns

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ SELECT * FROM [SHOW TENANT [10] WITH CAPABILITIES] WHERE capability_name = 'can_
33
----
44
10 cluster-10 ready external can_prepare_txns false
55

6-
# TODO(#144252): remove this.
6+
77
exec-sql-tenant
8-
SET kv_transaction_buffered_writes_enabled = false
8+
CREATE TABLE t(a INT PRIMARY KEY)
99
----
1010
ok
1111

12-
exec-sql-tenant
13-
CREATE TABLE t(a INT PRIMARY KEY)
12+
# Disable buffered writes so that the failing batch has the same requests.
13+
exec-privileged-op-tenant
14+
SET kv_transaction_buffered_writes_enabled = false
1415
----
1516
ok
1617

@@ -28,8 +29,12 @@ ok
2829
exec-privileged-op-tenant
2930
PREPARE TRANSACTION 'txn1'
3031
----
31-
pq: ba: QueryIntent [/Tenant/10/Table/104/1/1/0], EndTxn(commit) [/Tenant/10/Table/104/1/1/0], [txn: ‹×›], [can-forward-ts] RPC error: rpc error: code = Unauthenticated desc = client tenant does not have capability "can_prepare_txns" (*kvpb.EndTxnRequest)
32+
pq: ba: QueryIntent [/Tenant/10/Table/104/1/1/0], EndTxn(prepare) [/Tenant/10/Table/104/1/1/0], [txn: ‹×›], [can-forward-ts] RPC error: rpc error: code = Unauthenticated desc = client tenant does not have capability "can_prepare_txns" (*kvpb.EndTxnRequest)
3233

34+
exec-privileged-op-tenant
35+
RESET kv_transaction_buffered_writes_enabled
36+
----
37+
ok
3338

3439
# Grant the capability.
3540
update-capabilities
@@ -57,13 +62,18 @@ ROLLBACK PREPARED 'txn2'
5762
----
5863
ok
5964

60-
6165
# Revoke the capability using REVOKE syntax.
6266
update-capabilities
6367
ALTER TENANT [10] REVOKE CAPABILITY can_prepare_txns
6468
----
6569
ok
6670

71+
# Disable buffered writes so that the failing batch has the same requests.
72+
exec-privileged-op-tenant
73+
SET kv_transaction_buffered_writes_enabled = false
74+
----
75+
ok
76+
6777
# Prepared transactions should no longer work.
6878
exec-privileged-op-tenant
6979
BEGIN
@@ -78,8 +88,12 @@ ok
7888
exec-privileged-op-tenant
7989
PREPARE TRANSACTION 'txn3'
8090
----
81-
pq: ba: QueryIntent [/Tenant/10/Table/104/1/1/0], EndTxn(commit) [/Tenant/10/Table/104/1/1/0], [txn: ‹×›], [can-forward-ts] RPC error: rpc error: code = Unauthenticated desc = client tenant does not have capability "can_prepare_txns" (*kvpb.EndTxnRequest)
91+
pq: ba: QueryIntent [/Tenant/10/Table/104/1/1/0], EndTxn(prepare) [/Tenant/10/Table/104/1/1/0], [txn: ‹×›], [can-forward-ts] RPC error: rpc error: code = Unauthenticated desc = client tenant does not have capability "can_prepare_txns" (*kvpb.EndTxnRequest)
8292

93+
exec-privileged-op-tenant
94+
RESET kv_transaction_buffered_writes_enabled
95+
----
96+
ok
8397

8498
# However, transactions that have not acquired locks are able to be prepared,
8599
# since they don't actually prepare a transaction record in the KV layer. This

pkg/kv/kvclient/kvcoord/txn_interceptor_write_buffer.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,7 +1762,7 @@ func (twb *txnWriteBuffer) flushBufferAndSendBatch(
17621762
return twb.wrapped.SendLocked(ctx, ba) // nothing to flush
17631763
}
17641764

1765-
_, hasEndTxn := ba.GetArg(kvpb.EndTxn)
1765+
endTxnArg, hasEndTxn := ba.GetArg(kvpb.EndTxn)
17661766
if !hasEndTxn {
17671767
// We're flushing the buffer even though the batch doesn't contain an EndTxn
17681768
// request. That means we buffered some writes and decided to disable write
@@ -1771,7 +1771,7 @@ func (twb *txnWriteBuffer) flushBufferAndSendBatch(
17711771
}
17721772

17731773
midTxnFlush := !hasEndTxn
1774-
splitBatchRequired := separateBatchIsNeeded(ba)
1774+
splitBatchRequired := separateBatchIsNeeded(ba, endTxnArg)
17751775

17761776
// Flush all buffered writes by pre-pending them to the requests being sent
17771777
// in the batch.
@@ -1861,7 +1861,16 @@ func requireAllFlushedRequestsProcessed(responses []kvpb.ResponseUnion) error {
18611861
//
18621862
// NB: If you are updating this function, you need to update
18631863
// clearBatchRequestOptions as well.
1864-
func separateBatchIsNeeded(ba *kvpb.BatchRequest) bool {
1864+
func separateBatchIsNeeded(ba *kvpb.BatchRequest, optEndTxn kvpb.Request) bool {
1865+
if optEndTxn != nil {
1866+
// TODO(#153513): This should really be fixed server-side. Currently, if we
1867+
// send an EndTxn with Prepare, it will be erroneously evaluated as a 1PC
1868+
// commit.
1869+
if optEndTxn.(*kvpb.EndTxnRequest).Prepare {
1870+
return true
1871+
}
1872+
}
1873+
18651874
return ba.MightStopEarly() ||
18661875
ba.ReadConsistency != 0 ||
18671876
ba.WaitPolicy != 0 ||

pkg/kv/kvclient/kvcoord/txn_interceptor_write_buffer_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2186,7 +2186,7 @@ func TestTxnWriteBufferSplitsBatchesWhenNecessary(t *testing.T) {
21862186
br.Txn = ba.Txn
21872187
if requestCount == 0 {
21882188
// The buffer flush should not have any problematic settings.
2189-
require.False(t, separateBatchIsNeeded(ba))
2189+
require.False(t, separateBatchIsNeeded(ba, nil))
21902190
}
21912191
requestCount++
21922192
return br, nil
@@ -4090,7 +4090,7 @@ needs to be accounted for in the following functions:
40904090
}
40914091
}
40924092
req := &kvpb.BatchRequest{Header: header}
4093-
require.True(t, separateBatchIsNeeded(req),
4093+
require.True(t, separateBatchIsNeeded(req, nil),
40944094
"non-zero value for %s not handled in separateBatchIsNeeded", fieldName)
40954095

40964096
clearBatchRequestOptions(req)

pkg/kv/kvpb/api.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,9 @@ var _ SafeFormatterRequest = (*EndTxnRequest)(nil)
248248
func (etr *EndTxnRequest) SafeFormat(s redact.SafePrinter, _ rune) {
249249
s.Printf("%s(", etr.Method())
250250
if etr.Commit {
251-
if etr.IsParallelCommit() {
251+
if etr.Prepare {
252+
s.Printf("prepare")
253+
} else if etr.IsParallelCommit() {
252254
s.Printf("parallel commit")
253255
} else {
254256
s.Printf("commit")

pkg/sql/logictest/testdata/logic_test/two_phase_commit

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
# LogicTest: !3node-tenant-default-configs !local-prepared
22

3-
# TODO(#144252): remove this.
4-
statement ok
5-
SET kv_transaction_buffered_writes_enabled = false;
6-
73
query T
84
SHOW max_prepared_transactions
95
----

0 commit comments

Comments
 (0)