Skip to content

Commit fea4b49

Browse files
committed
Code review
1 parent 9d8037d commit fea4b49

File tree

1 file changed

+40
-30
lines changed

1 file changed

+40
-30
lines changed

Diff for: Sources/AsyncHTTPClient/ConnectionPool/State Machine/HTTPConnectionPool+HTTP1Connections.swift

+40-30
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ extension HTTPConnectionPool {
1818
/// Represents the state of a single HTTP/1.1 connection
1919
private struct HTTP1ConnectionState {
2020
enum State {
21-
/// the connection is creating a connection. Valid transitions are to: .idle, .available and .closed
21+
/// the connection is creating a connection. Valid transitions are to: .backingOff, .idle, and .closed
2222
case starting
23-
/// the connection is waiting to retry the establishing a connection. Transition to .closed. From .closed
24-
/// a new connection state must be created for a retry.
23+
/// the connection is waiting to retry the establishing a connection. Valid transitions are to: .closed.
24+
/// This means, the connection can be removed from the connections without cancelling external
25+
/// state. The connection state can then be replaced by a new one.
2526
case backingOff
2627
/// the connection is idle for a new request. Valid transitions to: .leased and .closed
2728
case idle(Connection, since: NIODeadline)
@@ -152,6 +153,11 @@ extension HTTPConnectionPool {
152153
}
153154
}
154155

156+
enum CleanupAction {
157+
case removeConnection
158+
case keepConnection
159+
}
160+
155161
/// Cleanup the current connection for shutdown.
156162
///
157163
/// This method is called, when the connections shall shutdown. Depending on the state
@@ -164,21 +170,21 @@ extension HTTPConnectionPool {
164170
/// or fail until we finalize the shutdown.
165171
///
166172
/// - Parameter context: A cleanup context to add the connection to based on its state.
167-
/// - Returns: A bool weather the connection can be removed from the connections
168-
/// struct immediately.
169-
func cleanup(_ context: inout CleanupContext) -> Bool {
173+
/// - Returns: A cleanup action indicating if the connection can be removed from the
174+
/// connection list.
175+
func cleanup(_ context: inout CleanupContext) -> CleanupAction {
170176
switch self.state {
171177
case .backingOff:
172178
context.connectBackoff.append(self.connectionID)
173-
return true
179+
return .removeConnection
174180
case .starting:
175-
return false
181+
return .keepConnection
176182
case .idle(let connection, since: _):
177183
context.close.append(connection)
178-
return true
184+
return .removeConnection
179185
case .leased(let connection):
180186
context.cancel.append(connection)
181-
return false
187+
return .keepConnection
182188
case .closed:
183189
preconditionFailure("Unexpected state: Did not expect to have connections with this state in the state machine: \(self.state)")
184190
}
@@ -215,15 +221,17 @@ extension HTTPConnectionPool {
215221

216222
var stats: Stats {
217223
var stats = Stats()
224+
// all additions here can be unchecked, since we will have at max self.connections.count
225+
// which itself is an Int. For this reason we will never overflow.
218226
for connectionState in self.connections {
219227
if connectionState.isConnecting {
220-
stats.connecting += 1
228+
stats.connecting &+= 1
221229
} else if connectionState.isBackingOff {
222-
stats.backingOff += 1
230+
stats.backingOff &+= 1
223231
} else if connectionState.isLeased {
224-
stats.leased += 1
232+
stats.leased &+= 1
225233
} else if connectionState.isIdle {
226-
stats.idle += 1
234+
stats.idle &+= 1
227235
}
228236
}
229237
return stats
@@ -234,11 +242,7 @@ extension HTTPConnectionPool {
234242
}
235243

236244
var canGrow: Bool {
237-
if self.overflowIndex < self.connections.endIndex {
238-
return self.overflowIndex < self.maximumConcurrentConnections
239-
} else {
240-
return self.connections.endIndex < self.maximumConcurrentConnections
241-
}
245+
self.overflowIndex < self.maximumConcurrentConnections
242246
}
243247

244248
var startingGeneralPurposeConnections: Int {
@@ -254,7 +258,7 @@ extension HTTPConnectionPool {
254258
}
255259

256260
func startingEventLoopConnections(on eventLoop: EventLoop) -> Int {
257-
self.connections[self.overflowIndex..<self.connections.endIndex].reduce(into: 0) { count, connection in
261+
return self.connections[self.overflowIndex..<self.connections.endIndex].reduce(into: 0) { count, connection in
258262
guard connection.eventLoop === eventLoop else { return }
259263
if connection.isConnecting || connection.isBackingOff {
260264
count += 1
@@ -292,7 +296,7 @@ extension HTTPConnectionPool {
292296
// MARK: Connection creation
293297

294298
mutating func createNewConnection(on eventLoop: EventLoop) -> Connection.ID {
295-
assert(self.canGrow)
299+
precondition(self.canGrow)
296300
let connection = HTTP1ConnectionState(connectionID: self.generator.next(), eventLoop: eventLoop)
297301
self.connections.insert(connection, at: self.overflowIndex)
298302
self.overflowIndex = self.connections.index(after: self.overflowIndex)
@@ -307,7 +311,7 @@ extension HTTPConnectionPool {
307311

308312
/// A new HTTP/1.1 connection was established.
309313
///
310-
/// This will put the position into the idle state.
314+
/// This will put the connection into the idle state.
311315
///
312316
/// - Parameter connection: The new established connection.
313317
/// - Returns: An index and an IdleConnectionContext to determine the next action for the now idle connection.
@@ -317,7 +321,7 @@ extension HTTPConnectionPool {
317321
guard let index = self.connections.firstIndex(where: { $0.connectionID == connection.id }) else {
318322
preconditionFailure("There is a new connection that we didn't request!")
319323
}
320-
assert(connection.eventLoop === self.connections[index].eventLoop, "Expected the new connection to be on EL")
324+
precondition(connection.eventLoop === self.connections[index].eventLoop, "Expected the new connection to be on EL")
321325
self.connections[index].connected(connection)
322326
let context = self.generateIdleConnectionContextForConnection(at: index)
323327
return (index, context)
@@ -391,14 +395,17 @@ extension HTTPConnectionPool {
391395

392396
// MARK: Connection close/removal
393397

398+
/// Closes the connection at the given index. This will also remove the connection right away.
394399
mutating func closeConnection(at index: Int) -> Connection {
400+
if index < self.overflowIndex {
401+
self.overflowIndex = self.connections.index(before: self.overflowIndex)
402+
}
395403
var connectionState = self.connections.remove(at: index)
396-
self.overflowIndex = self.connections.index(before: self.overflowIndex)
397404
return connectionState.close()
398405
}
399406

400407
mutating func removeConnection(at index: Int) {
401-
assert(self.connections[index].isClosed)
408+
precondition(self.connections[index].isClosed)
402409
if index < self.overflowIndex {
403410
self.overflowIndex = self.connections.index(before: self.overflowIndex)
404411
}
@@ -444,7 +451,7 @@ extension HTTPConnectionPool {
444451
/// supplied index after this.
445452
mutating func failConnection(_ connectionID: Connection.ID) -> (Int, FailedConnectionContext) {
446453
guard let index = self.connections.firstIndex(where: { $0.connectionID == connectionID }) else {
447-
preconditionFailure("We tried to create a new connection that we know nothing about?")
454+
preconditionFailure("We tried to fail a new connection that we know nothing about?")
448455
}
449456

450457
let use: ConnectionUse
@@ -474,13 +481,16 @@ extension HTTPConnectionPool {
474481
let initialOverflowIndex = self.overflowIndex
475482

476483
self.connections = self.connections.enumerated().compactMap { index, connectionState in
477-
if connectionState.cleanup(&cleanupContext) {
484+
switch connectionState.cleanup(&cleanupContext) {
485+
case .removeConnection:
478486
if index < initialOverflowIndex {
479-
self.overflowIndex -= 1
487+
self.overflowIndex = self.connections.index(before: self.overflowIndex)
480488
}
481489
return nil
490+
491+
case .keepConnection:
492+
return connectionState
482493
}
483-
return connectionState
484494
}
485495

486496
return cleanupContext
@@ -489,7 +499,7 @@ extension HTTPConnectionPool {
489499
// MARK: - Private functions -
490500

491501
private func generateIdleConnectionContextForConnection(at index: Int) -> IdleConnectionContext {
492-
assert(self.connections[index].isIdle)
502+
precondition(self.connections[index].isIdle)
493503
let eventLoop = self.connections[index].eventLoop
494504
let use: ConnectionUse
495505
if index < self.overflowIndex {

0 commit comments

Comments
 (0)