refactor frame packing to logic to not access the streams map (#4596)

* avoid accessing the streams map when packing stream data

* avoid accessing the streams map when packing flow control frames

* remove streamGetter interface
This commit is contained in:
Marten Seemann
2024-07-28 12:32:54 -07:00
committed by GitHub
parent fc79a77ffe
commit 42f04d4e02
20 changed files with 224 additions and 390 deletions

View File

@@ -19,9 +19,7 @@ const (
type framer struct {
mutex sync.Mutex
streamGetter streamGetter
activeStreams map[protocol.StreamID]struct{}
activeStreams map[protocol.StreamID]sendStreamI
streamQueue ringbuffer.RingBuffer[protocol.StreamID]
controlFrameMutex sync.Mutex
@@ -30,11 +28,8 @@ type framer struct {
queuedTooManyControlFrames bool
}
func newFramer(streamGetter streamGetter) *framer {
return &framer{
streamGetter: streamGetter,
activeStreams: make(map[protocol.StreamID]struct{}),
}
func newFramer() *framer {
return &framer{activeStreams: make(map[protocol.StreamID]sendStreamI)}
}
func (f *framer) HasData() bool {
@@ -109,15 +104,25 @@ func (f *framer) QueuedTooManyControlFrames() bool {
return f.queuedTooManyControlFrames
}
func (f *framer) AddActiveStream(id protocol.StreamID) {
func (f *framer) AddActiveStream(id protocol.StreamID, str sendStreamI) {
f.mutex.Lock()
if _, ok := f.activeStreams[id]; !ok {
f.streamQueue.PushBack(id)
f.activeStreams[id] = struct{}{}
f.activeStreams[id] = str
}
f.mutex.Unlock()
}
// RemoveActiveStream is called when a stream completes.
func (f *framer) RemoveActiveStream(id protocol.StreamID) {
f.mutex.Lock()
delete(f.activeStreams, id)
// We don't delete the stream from the streamQueue,
// since we'd have to iterate over the ringbuffer.
// Instead, we check if the stream is still in activeStreams in AppendStreamFrames.
f.mutex.Unlock()
}
func (f *framer) AppendStreamFrames(frames []ackhandler.StreamFrame, maxLen protocol.ByteCount, v protocol.Version) ([]ackhandler.StreamFrame, protocol.ByteCount) {
startLen := len(frames)
var length protocol.ByteCount
@@ -131,10 +136,9 @@ func (f *framer) AppendStreamFrames(frames []ackhandler.StreamFrame, maxLen prot
id := f.streamQueue.PopFront()
// This should never return an error. Better check it anyway.
// The stream will only be in the streamQueue, if it enqueued itself there.
str, err := f.streamGetter.GetOrOpenSendStream(id)
// The stream can be nil if it completed after it said it had data.
if str == nil || err != nil {
delete(f.activeStreams, id)
str, ok := f.activeStreams[id]
// The stream might have been removed after being enqueued.
if !ok {
continue
}
remainingLen := maxLen - length