Skip to content

Commit f7250ea

Browse files
neildgopherbot
authored andcommitted
quic: add a type tracking sent values
Any given datum communicated to the peer follows a state machine: - We do not need to send the this datum. - We need to send it, but have not done so. - We have sent it, but the peer has not acknowledged it. - We have sent it and the peer has acknowledged it. Data transitions between states in a consistent fashion; for example, loss of the most recent packet containing a HANDSHAKE_DONE frame means we should resend the frame in a new packet. Add a sentVal type which tracks this state machine. For golang/go#58547 Change-Id: I9de0ef5e482534b8733ef66363bac8f6c0fd3173 Reviewed-on: https://go-review.googlesource.com/c/net/+/498295 Run-TryBot: Damien Neil <[email protected]> Reviewed-by: Jonathan Amsterdam <[email protected]> Auto-Submit: Damien Neil <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 1b5a2d8 commit f7250ea

File tree

2 files changed

+269
-0
lines changed

2 files changed

+269
-0
lines changed

internal/quic/sent_val.go

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package quic
6+
7+
// A sentVal tracks sending some piece of information to the peer.
8+
// It tracks whether the information has been sent, acked, and
9+
// (when in-flight) the most recent packet to carry it.
10+
//
11+
// For example, a sentVal can track sending of a RESET_STREAM frame.
12+
//
13+
// - unset: stream is active, no need to send RESET_STREAM
14+
// - unsent: we should send a RESET_STREAM, but have not yet
15+
// - sent: we have sent a RESET_STREAM, but have not received an ack
16+
// - received: we have sent a RESET_STREAM, and the peer has acked the packet that contained it
17+
//
18+
// In the "sent" state, a sentVal also tracks the latest packet number to carry
19+
// the information. (QUIC packet numbers are always at most 62 bits in size,
20+
// so the sentVal keeps the number in the low 62 bits and the state in the high 2 bits.)
21+
type sentVal uint64
22+
23+
const (
24+
sentValUnset = 0 // unset
25+
sentValUnsent = 1 << 62 // set, not sent to the peer
26+
sentValSent = 2 << 62 // set, sent to the peer but not yet acked; pnum is set
27+
sentValReceived = 3 << 62 // set, peer acked receipt
28+
29+
sentValStateMask = 3 << 62
30+
)
31+
32+
// isSet reports whether the value is set.
33+
func (s sentVal) isSet() bool { return s != 0 }
34+
35+
// shouldSend reports whether the value is set and has not been sent to the peer.
36+
func (s sentVal) shouldSend() bool { return s.state() == sentValUnsent }
37+
38+
// shouldSend reports whether the the value needs to be sent to the peer.
39+
// The value needs to be sent if it is set and has not been sent.
40+
// If pto is true, indicating that we are sending a PTO probe, the value
41+
// should also be sent if it is set and has not been acknowledged.
42+
func (s sentVal) shouldSendPTO(pto bool) bool {
43+
st := s.state()
44+
return st == sentValUnsent || (pto && st == sentValSent)
45+
}
46+
47+
// isReceived reports whether the value has been received by the peer.
48+
func (s sentVal) isReceived() bool { return s == sentValReceived }
49+
50+
// set sets the value and records that it should be sent to the peer.
51+
// If the value has already been sent, it is not resent.
52+
func (s *sentVal) set() {
53+
if *s == 0 {
54+
*s = sentValUnsent
55+
}
56+
}
57+
58+
// reset sets the value to the unsent state.
59+
func (s *sentVal) setUnsent() { *s = sentValUnsent }
60+
61+
// clear sets the value to the unset state.
62+
func (s *sentVal) clear() { *s = sentValUnset }
63+
64+
// setSent sets the value to the send state and records the number of the most recent
65+
// packet containing the value.
66+
func (s *sentVal) setSent(pnum packetNumber) {
67+
*s = sentValSent | sentVal(pnum)
68+
}
69+
70+
// setReceived sets the value to the received state.
71+
func (s *sentVal) setReceived() { *s = sentValReceived }
72+
73+
// ackOrLoss reports that an acknowledgement has been received for the value,
74+
// or (if acked is false) that the packet carrying the value has been lost.
75+
func (s *sentVal) ackOrLoss(pnum packetNumber, acked bool) {
76+
if acked {
77+
*s = sentValReceived
78+
} else if *s == sentVal(pnum)|sentValSent {
79+
*s = sentValUnsent
80+
}
81+
}
82+
83+
// ackLatestOrLoss reports that an acknowledgement has been received for the value,
84+
// or (if acked is false) that the packet carrying the value has been lost.
85+
// The value is set to the acked state only if pnum is the latest packet containing it.
86+
//
87+
// We use this to handle acks for data that varies every time it is sent.
88+
// For example, if we send a MAX_DATA frame followed by an updated MAX_DATA value in a
89+
// second packet, we consider the data sent only upon receiving an ack for the most
90+
// recent value.
91+
func (s *sentVal) ackLatestOrLoss(pnum packetNumber, acked bool) {
92+
if acked {
93+
if *s == sentVal(pnum)|sentValSent {
94+
*s = sentValReceived
95+
}
96+
} else {
97+
if *s == sentVal(pnum)|sentValSent {
98+
*s = sentValUnsent
99+
}
100+
}
101+
}
102+
103+
func (s sentVal) state() uint64 { return uint64(s) & sentValStateMask }

internal/quic/sent_val_test.go

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package quic
6+
7+
import "testing"
8+
9+
func TestSentVal(t *testing.T) {
10+
for _, test := range []struct {
11+
name string
12+
f func(*sentVal)
13+
wantIsSet bool
14+
wantShouldSend bool
15+
wantIsReceived bool
16+
wantShouldSendPTO bool
17+
}{{
18+
name: "zero value",
19+
f: func(*sentVal) {},
20+
wantIsSet: false,
21+
wantShouldSend: false,
22+
wantShouldSendPTO: false,
23+
wantIsReceived: false,
24+
}, {
25+
name: "v.set()",
26+
f: (*sentVal).set,
27+
wantIsSet: true,
28+
wantShouldSend: true,
29+
wantShouldSendPTO: true,
30+
wantIsReceived: false,
31+
}, {
32+
name: "v.setSent(0)",
33+
f: func(v *sentVal) {
34+
v.setSent(0)
35+
},
36+
wantIsSet: true,
37+
wantShouldSend: false,
38+
wantShouldSendPTO: true,
39+
wantIsReceived: false,
40+
}, {
41+
name: "sent.set()",
42+
f: func(v *sentVal) {
43+
v.setSent(0)
44+
v.set()
45+
},
46+
wantIsSet: true,
47+
wantShouldSend: false,
48+
wantShouldSendPTO: true,
49+
wantIsReceived: false,
50+
}, {
51+
name: "sent.setUnsent()",
52+
f: func(v *sentVal) {
53+
v.setSent(0)
54+
v.setUnsent()
55+
},
56+
wantIsSet: true,
57+
wantShouldSend: true,
58+
wantShouldSendPTO: true,
59+
wantIsReceived: false,
60+
}, {
61+
name: "set.clear()",
62+
f: func(v *sentVal) {
63+
v.set()
64+
v.clear()
65+
},
66+
wantIsSet: false,
67+
wantShouldSend: false,
68+
wantShouldSendPTO: false,
69+
wantIsReceived: false,
70+
}, {
71+
name: "v.setReceived()",
72+
f: (*sentVal).setReceived,
73+
wantIsSet: true,
74+
wantShouldSend: false,
75+
wantShouldSendPTO: false,
76+
wantIsReceived: true,
77+
}, {
78+
name: "v.ackOrLoss(!pnum, true)",
79+
f: func(v *sentVal) {
80+
v.setSent(1)
81+
v.ackOrLoss(0, true) // ack different packet containing the val
82+
},
83+
wantIsSet: true,
84+
wantShouldSend: false,
85+
wantShouldSendPTO: false,
86+
wantIsReceived: true,
87+
}, {
88+
name: "v.ackOrLoss(!pnum, false)",
89+
f: func(v *sentVal) {
90+
v.setSent(1)
91+
v.ackOrLoss(0, false) // lose different packet containing the val
92+
},
93+
wantIsSet: true,
94+
wantShouldSend: false,
95+
wantShouldSendPTO: true,
96+
wantIsReceived: false,
97+
}, {
98+
name: "v.ackOrLoss(pnum, false)",
99+
f: func(v *sentVal) {
100+
v.setSent(1)
101+
v.ackOrLoss(1, false) // lose same packet containing the val
102+
},
103+
wantIsSet: true,
104+
wantShouldSend: true,
105+
wantShouldSendPTO: true,
106+
wantIsReceived: false,
107+
}, {
108+
name: "v.ackLatestOrLoss(!pnum, true)",
109+
f: func(v *sentVal) {
110+
v.setSent(1)
111+
v.ackLatestOrLoss(0, true) // ack different packet containing the val
112+
},
113+
wantIsSet: true,
114+
wantShouldSend: false,
115+
wantShouldSendPTO: true,
116+
wantIsReceived: false,
117+
}, {
118+
name: "v.ackLatestOrLoss(pnum, true)",
119+
f: func(v *sentVal) {
120+
v.setSent(1)
121+
v.ackLatestOrLoss(1, true) // ack same packet containing the val
122+
},
123+
wantIsSet: true,
124+
wantShouldSend: false,
125+
wantShouldSendPTO: false,
126+
wantIsReceived: true,
127+
}, {
128+
name: "v.ackLatestOrLoss(!pnum, false)",
129+
f: func(v *sentVal) {
130+
v.setSent(1)
131+
v.ackLatestOrLoss(0, false) // lose different packet containing the val
132+
},
133+
wantIsSet: true,
134+
wantShouldSend: false,
135+
wantShouldSendPTO: true,
136+
wantIsReceived: false,
137+
}, {
138+
name: "v.ackLatestOrLoss(pnum, false)",
139+
f: func(v *sentVal) {
140+
v.setSent(1)
141+
v.ackLatestOrLoss(1, false) // lose same packet containing the val
142+
},
143+
wantIsSet: true,
144+
wantShouldSend: true,
145+
wantShouldSendPTO: true,
146+
wantIsReceived: false,
147+
}} {
148+
var v sentVal
149+
test.f(&v)
150+
if got, want := v.isSet(), test.wantIsSet; got != want {
151+
t.Errorf("%v: v.isSet() = %v, want %v", test.name, got, want)
152+
}
153+
if got, want := v.shouldSend(), test.wantShouldSend; got != want {
154+
t.Errorf("%v: v.shouldSend() = %v, want %v", test.name, got, want)
155+
}
156+
if got, want := v.shouldSendPTO(false), test.wantShouldSend; got != want {
157+
t.Errorf("%v: v.shouldSendPTO(false) = %v, want %v", test.name, got, want)
158+
}
159+
if got, want := v.shouldSendPTO(true), test.wantShouldSendPTO; got != want {
160+
t.Errorf("%v: v.shouldSendPTO(true) = %v, want %v", test.name, got, want)
161+
}
162+
if got, want := v.isReceived(), test.wantIsReceived; got != want {
163+
t.Errorf("%v: v.isReceived() = %v, want %v", test.name, got, want)
164+
}
165+
}
166+
}

0 commit comments

Comments
 (0)