Skip to content

Commit c6e88b5

Browse files
authored
Merge pull request #22140 from k8s-infra-cherrypick-robot/cherry-pick-22134-to-release-3.6
[release-3.6] Fix the `costTxnReq` ignores nested `RequestTxn` issue
2 parents 656d86b + cca254a commit c6e88b5

2 files changed

Lines changed: 86 additions & 4 deletions

File tree

server/storage/quota.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,13 @@ func (b *BackendQuota) Cost(v any) int {
149149
func costPut(r *pb.PutRequest) int { return kvOverhead + len(r.Key) + len(r.Value) }
150150

151151
func costTxnReq(u *pb.RequestOp) int {
152-
r := u.GetRequestPut()
153-
if r == nil {
154-
return 0
152+
if r := u.GetRequestPut(); r != nil {
153+
return costPut(r)
154+
}
155+
if t := u.GetRequestTxn(); t != nil {
156+
return costTxn(t)
155157
}
156-
return costPut(r)
158+
return 0
157159
}
158160

159161
func costTxn(r *pb.TxnRequest) int {

server/storage/quota_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright 2026 The etcd Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package storage
16+
17+
import (
18+
"testing"
19+
20+
"github.com/stretchr/testify/require"
21+
22+
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
23+
)
24+
25+
func TestCostTxn(t *testing.T) {
26+
putOp := func(key, value string) *pb.RequestOp {
27+
return &pb.RequestOp{
28+
Request: &pb.RequestOp_RequestPut{
29+
RequestPut: &pb.PutRequest{Key: []byte(key), Value: []byte(value)},
30+
},
31+
}
32+
}
33+
txnOp := func(txn *pb.TxnRequest) *pb.RequestOp {
34+
return &pb.RequestOp{
35+
Request: &pb.RequestOp_RequestTxn{RequestTxn: txn},
36+
}
37+
}
38+
39+
tests := []struct {
40+
name string
41+
req *pb.TxnRequest
42+
want int
43+
}{
44+
{
45+
name: "flat put",
46+
req: &pb.TxnRequest{
47+
Success: []*pb.RequestOp{putOp("foo", "bar")},
48+
},
49+
want: costPut(&pb.PutRequest{Key: []byte("foo"), Value: []byte("bar")}),
50+
},
51+
{
52+
name: "nested txn put in success branch must be counted",
53+
req: &pb.TxnRequest{
54+
Success: []*pb.RequestOp{
55+
txnOp(&pb.TxnRequest{
56+
Success: []*pb.RequestOp{putOp("nested-key", "nested-value")},
57+
}),
58+
},
59+
},
60+
want: costPut(&pb.PutRequest{Key: []byte("nested-key"), Value: []byte("nested-value")}),
61+
},
62+
{
63+
name: "nested txn put in failure branch must be counted",
64+
req: &pb.TxnRequest{
65+
Failure: []*pb.RequestOp{
66+
txnOp(&pb.TxnRequest{
67+
Failure: []*pb.RequestOp{putOp("nested-key", "nested-value")},
68+
}),
69+
},
70+
},
71+
want: costPut(&pb.PutRequest{Key: []byte("nested-key"), Value: []byte("nested-value")}),
72+
},
73+
}
74+
75+
for _, tt := range tests {
76+
t.Run(tt.name, func(t *testing.T) {
77+
require.Equal(t, tt.want, costTxn(tt.req))
78+
})
79+
}
80+
}

0 commit comments

Comments
 (0)