Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -496,10 +496,16 @@ extension HTTPConnectionPool {
/// - Parameter connectionID: The released connection's id.
/// - Returns: An index and an IdleConnectionContext to determine the next action for the now idle connection.
/// Call ``leaseConnection(at:)`` or ``closeConnection(at:)`` with the supplied index after
/// this. If you want to park the connection no further call is required.
mutating func releaseConnection(_ connectionID: Connection.ID) -> (Int, IdleConnectionContext) {
/// this. If you want to park the connection no further call is required. `nil` if the
/// connection is no longer known to the state machine.
mutating func releaseConnection(_ connectionID: Connection.ID) -> (Int, IdleConnectionContext)? {
guard let index = self.connections.firstIndex(where: { $0.connectionID == connectionID }) else {
preconditionFailure("A connection that we don't know was released? Something is very wrong...")
// The connection's close/failure may have already been processed by the state
// machine (e.g. the peer closed the connection right as the response finished,
// racing with this release notification) — that path already removed the
// connection and found new work for any queued requests, so there's nothing left
// to do for this now-stale release.
return nil
}

self.connections[index].release()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,12 @@ extension HTTPConnectionPool {
}

mutating func http1ConnectionReleased(_ connectionID: Connection.ID) -> Action {
let (index, context) = self.connections.releaseConnection(connectionID)
guard let (index, context) = self.connections.releaseConnection(connectionID) else {
// The connection was already closed/failed by the time this release was
// processed; that path already handled cleanup. See `http1ConnectionClosed`
// above for the same pattern.
return .none
}
return .init(self.nextActionForIdleConnection(at: index, context: context))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -563,9 +563,14 @@ extension HTTPConnectionPool {
}

mutating func http1ConnectionReleased(_ connectionID: Connection.ID) -> Action {
// It is save to bang the http1Connections here. If we get this callback but we don't have
// It is safe to bang the http1Connections here. If we get this callback but we don't have
// http1 connections something has gone terribly wrong.
let (index, _) = self.http1Connections!.releaseConnection(connectionID)
guard let (index, _) = self.http1Connections!.releaseConnection(connectionID) else {
// The connection was already closed/failed by the time this release was
// processed; that path already handled cleanup. See `http1ConnectionClosed`
// above for the same pattern.
return .none
}
// Any http1 connection that becomes idle should be closed right away after the transition
// to http2.
let connection = self.http1Connections!.closeConnection(at: index)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,9 @@ class HTTPConnectionPool_HTTP1ConnectionsTests: XCTestCase {
XCTAssertEqual(connections.stats.connecting, 1)
XCTAssertFalse(connections.isEmpty)

let (releaseIndex, _) = connections.releaseConnection(lease.id)
guard let (releaseIndex, _) = connections.releaseConnection(lease.id) else {
return XCTFail("Expected that the connection is remembered")
}
XCTAssertEqual(connections.closeConnection(at: releaseIndex), lease)
XCTAssertFalse(connections.isEmpty)

Expand Down
Loading