forked from quic-go/quic-go
improve garbage collection of stream
This removes the Iterate method of the streamsMap, and moves the garbage collection of closed streams from the session to the streamsMap.
This commit is contained in:
@@ -29,26 +29,27 @@ type streamsMap struct {
|
||||
closeErr error
|
||||
nextStreamToAccept protocol.StreamID
|
||||
|
||||
newStream newStreamLambda
|
||||
newStream newStreamLambda
|
||||
removeStreamCallback removeStreamCallback
|
||||
|
||||
numOutgoingStreams uint32
|
||||
numIncomingStreams uint32
|
||||
}
|
||||
|
||||
type streamLambda func(*stream) (bool, error)
|
||||
type removeStreamCallback func(protocol.StreamID)
|
||||
type newStreamLambda func(protocol.StreamID) *stream
|
||||
|
||||
var (
|
||||
errMapAccess = errors.New("streamsMap: Error accessing the streams map")
|
||||
)
|
||||
var errMapAccess = errors.New("streamsMap: Error accessing the streams map")
|
||||
|
||||
func newStreamsMap(newStream newStreamLambda, pers protocol.Perspective, connParams handshake.ParamsNegotiator) *streamsMap {
|
||||
func newStreamsMap(newStream newStreamLambda, removeStreamCallback removeStreamCallback, pers protocol.Perspective, connParams handshake.ParamsNegotiator) *streamsMap {
|
||||
sm := streamsMap{
|
||||
perspective: pers,
|
||||
streams: map[protocol.StreamID]*stream{},
|
||||
openStreams: make([]protocol.StreamID, 0),
|
||||
newStream: newStream,
|
||||
connParams: connParams,
|
||||
perspective: pers,
|
||||
streams: make(map[protocol.StreamID]*stream),
|
||||
openStreams: make([]protocol.StreamID, 0),
|
||||
newStream: newStream,
|
||||
removeStreamCallback: removeStreamCallback,
|
||||
connParams: connParams,
|
||||
}
|
||||
sm.nextStreamOrErrCond.L = &sm.mutex
|
||||
sm.openStreamOrErrCond.L = &sm.mutex
|
||||
@@ -216,21 +217,50 @@ func (m *streamsMap) AcceptStream() (*stream, error) {
|
||||
return str, nil
|
||||
}
|
||||
|
||||
func (m *streamsMap) Iterate(fn streamLambda) error {
|
||||
func (m *streamsMap) DeleteClosedStreams() error {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
openStreams := append([]protocol.StreamID{}, m.openStreams...)
|
||||
|
||||
for _, streamID := range openStreams {
|
||||
cont, err := m.iterateFunc(streamID, fn)
|
||||
if err != nil {
|
||||
return err
|
||||
var numDeletedStreams int
|
||||
// for every closed stream, the streamID is replaced by 0 in the openStreams slice
|
||||
for i, streamID := range m.openStreams {
|
||||
str, ok := m.streams[streamID]
|
||||
if !ok {
|
||||
return errMapAccess
|
||||
}
|
||||
if !cont {
|
||||
break
|
||||
if !str.finished() {
|
||||
continue
|
||||
}
|
||||
m.removeStreamCallback(streamID)
|
||||
numDeletedStreams++
|
||||
m.openStreams[i] = 0
|
||||
if streamID%2 == 0 {
|
||||
m.numOutgoingStreams--
|
||||
} else {
|
||||
m.numIncomingStreams--
|
||||
}
|
||||
delete(m.streams, streamID)
|
||||
}
|
||||
|
||||
if numDeletedStreams == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// remove all 0s (representing closed streams) from the openStreams slice
|
||||
// and adjust the roundRobinIndex
|
||||
var j int
|
||||
for i, id := range m.openStreams {
|
||||
if i != j {
|
||||
m.openStreams[j] = m.openStreams[i]
|
||||
}
|
||||
if id != 0 {
|
||||
j++
|
||||
} else if uint32(j) < m.roundRobinIndex {
|
||||
m.roundRobinIndex--
|
||||
}
|
||||
}
|
||||
m.openStreams = m.openStreams[:len(m.openStreams)-numDeletedStreams]
|
||||
m.openStreamOrErrCond.Signal()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -291,36 +321,6 @@ func (m *streamsMap) putStream(s *stream) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Attention: this function must only be called if a mutex has been acquired previously
|
||||
func (m *streamsMap) RemoveStream(id protocol.StreamID) error {
|
||||
s, ok := m.streams[id]
|
||||
if !ok || s == nil {
|
||||
return fmt.Errorf("attempted to remove non-existing stream: %d", id)
|
||||
}
|
||||
|
||||
if id%2 == 0 {
|
||||
m.numOutgoingStreams--
|
||||
} else {
|
||||
m.numIncomingStreams--
|
||||
}
|
||||
|
||||
for i, s := range m.openStreams {
|
||||
if s == id {
|
||||
// delete the streamID from the openStreams slice
|
||||
m.openStreams = m.openStreams[:i+copy(m.openStreams[i:], m.openStreams[i+1:])]
|
||||
// adjust round-robin index, if necessary
|
||||
if uint32(i) < m.roundRobinIndex {
|
||||
m.roundRobinIndex--
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
delete(m.streams, id)
|
||||
m.openStreamOrErrCond.Signal()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *streamsMap) CloseWithError(err error) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
Reference in New Issue
Block a user