Skip to content

Commit 796bf33

Browse files
committed
Introduce generic type ConnectionType into ConnectionsState
Motivation: To rework tests of ConnectionsState we want to have a "simpler" version of Connection to be used, therefore here we convert ConnectionsState to support generic type ConnectionType. We will substitute current Connection with a test version in follow up commit. Modifications: ConnectionsState is altered to work on generic type ConnectionType instead of solid type Connection. Users of ConnectionsState are modified to provide type Connection into ConnectionType in this commit. Result: Test are passing, no observable behaviour change.
1 parent cee0296 commit 796bf33

File tree

5 files changed

+57
-57
lines changed

5 files changed

+57
-57
lines changed

Sources/AsyncHTTPClient/Connection.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -153,14 +153,14 @@ extension Connection: CustomStringConvertible {
153153
}
154154
}
155155

156-
struct ConnectionKey: Hashable {
157-
let connection: Connection
156+
struct ConnectionKey<ConnectionType>: Hashable where ConnectionType: PoolManageableConnection {
157+
let connection: ConnectionType
158158

159-
init(_ connection: Connection) {
159+
init(_ connection: ConnectionType) {
160160
self.connection = connection
161161
}
162162

163-
static func == (lhs: ConnectionKey, rhs: ConnectionKey) -> Bool {
163+
static func == (lhs: ConnectionKey<ConnectionType>, rhs: ConnectionKey<ConnectionType>) -> Bool {
164164
return ObjectIdentifier(lhs.connection) == ObjectIdentifier(rhs.connection)
165165
}
166166

Sources/AsyncHTTPClient/ConnectionPool.swift

+7-7
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ class HTTP1ConnectionProvider {
191191

192192
var closePromise: EventLoopPromise<Void>
193193

194-
var state: ConnectionsState
194+
var state: ConnectionsState<Connection>
195195

196196
private let backgroundActivityLogger: Logger
197197

@@ -222,7 +222,7 @@ class HTTP1ConnectionProvider {
222222
self.state.assertInvariants()
223223
}
224224

225-
func execute(_ action: Action, logger: Logger) {
225+
func execute(_ action: Action<Connection>, logger: Logger) {
226226
switch action {
227227
case .lease(let connection, let waiter):
228228
// if connection is became inactive, we create a new one.
@@ -297,7 +297,7 @@ class HTTP1ConnectionProvider {
297297
func getConnection(preference: HTTPClient.EventLoopPreference,
298298
setupComplete: EventLoopFuture<Void>,
299299
logger: Logger) -> EventLoopFuture<Connection> {
300-
let waiter = Waiter(promise: self.eventLoop.makePromise(), setupComplete: setupComplete, preference: preference)
300+
let waiter = Waiter<Connection>(promise: self.eventLoop.makePromise(), setupComplete: setupComplete, preference: preference)
301301

302302
let action: Action = self.lock.withLock {
303303
self.state.acquire(waiter: waiter)
@@ -309,10 +309,10 @@ class HTTP1ConnectionProvider {
309309
}
310310

311311
func connect(_ result: Result<Channel, Error>,
312-
waiter: Waiter,
312+
waiter: Waiter<Connection>,
313313
replacing closedConnection: Connection? = nil,
314314
logger: Logger) {
315-
let action: Action
315+
let action: Action<Connection>
316316
switch result {
317317
case .success(let channel):
318318
logger.trace("successfully created connection",
@@ -478,9 +478,9 @@ class HTTP1ConnectionProvider {
478478
///
479479
/// `Waiter`s are created when `maximumConcurrentConnections` is reached
480480
/// and we cannot create new connections anymore.
481-
struct Waiter {
481+
struct Waiter<ConnectionType: PoolManageableConnection> {
482482
/// The promise to complete once a connection is available
483-
let promise: EventLoopPromise<Connection>
483+
let promise: EventLoopPromise<ConnectionType>
484484

485485
/// Future that will be succeeded when request timeout handler and `TaskHandler` are added to the pipeline.
486486
let setupComplete: EventLoopFuture<Void>

Sources/AsyncHTTPClient/ConnectionsState.swift

+31-31
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,29 @@
1515
import NIO
1616

1717
extension HTTP1ConnectionProvider {
18-
enum Action {
19-
case lease(Connection, Waiter)
20-
case create(Waiter)
21-
case replace(Connection, Waiter)
18+
enum Action<ConnectionType: PoolManageableConnection> {
19+
case lease(ConnectionType, Waiter<ConnectionType>)
20+
case create(Waiter<ConnectionType>)
21+
case replace(ConnectionType, Waiter<ConnectionType>)
2222
case closeProvider
23-
case park(Connection)
23+
case park(ConnectionType)
2424
case none
25-
case fail(Waiter, Error)
26-
indirect case closeAnd(Connection, Action)
27-
indirect case parkAnd(Connection, Action)
25+
case fail(Waiter<ConnectionType>, Error)
26+
indirect case closeAnd(ConnectionType, Action<ConnectionType>)
27+
indirect case parkAnd(ConnectionType, Action<ConnectionType>)
2828
}
2929

30-
struct ConnectionsState {
30+
struct ConnectionsState<ConnectionType: PoolManageableConnection> {
3131
enum State {
3232
case active
3333
case closed
3434
}
3535

36-
struct Snapshot {
36+
struct Snapshot<ConnectionType: PoolManageableConnection> {
3737
var state: State
38-
var availableConnections: CircularBuffer<Connection>
39-
var leasedConnections: Set<ConnectionKey>
40-
var waiters: CircularBuffer<Waiter>
38+
var availableConnections: CircularBuffer<ConnectionType>
39+
var leasedConnections: Set<ConnectionKey<ConnectionType>>
40+
var waiters: CircularBuffer<Waiter<ConnectionType>>
4141
var openedConnectionsCount: Int
4242
var pending: Int
4343
}
@@ -48,16 +48,16 @@ extension HTTP1ConnectionProvider {
4848
private var state: State = .active
4949

5050
/// Opened connections that are available.
51-
private var availableConnections: CircularBuffer<Connection> = .init(initialCapacity: 8)
51+
private var availableConnections: CircularBuffer<ConnectionType> = .init(initialCapacity: 8)
5252

5353
/// Opened connections that are leased to the user.
54-
private var leasedConnections: Set<ConnectionKey> = .init()
54+
private var leasedConnections: Set<ConnectionKey<ConnectionType>> = .init()
5555

5656
/// Consumers that weren't able to get a new connection without exceeding
5757
/// `maximumConcurrentConnections` get a `Future<Connection>`
5858
/// whose associated promise is stored in `Waiter`. The promise is completed
5959
/// as soon as possible by the provider, in FIFO order.
60-
private var waiters: CircularBuffer<Waiter> = .init(initialCapacity: 8)
60+
private var waiters: CircularBuffer<Waiter<ConnectionType>> = .init(initialCapacity: 8)
6161

6262
/// Number of opened or opening connections, used to keep track of all connections and enforcing `maximumConcurrentConnections` limit.
6363
private var openedConnectionsCount: Int = 0
@@ -70,11 +70,11 @@ extension HTTP1ConnectionProvider {
7070
self.eventLoop = eventLoop
7171
}
7272

73-
func testsOnly_getInternalState() -> Snapshot {
73+
func testsOnly_getInternalState() -> Snapshot<ConnectionType> {
7474
return Snapshot(state: self.state, availableConnections: self.availableConnections, leasedConnections: self.leasedConnections, waiters: self.waiters, openedConnectionsCount: self.openedConnectionsCount, pending: self.pending)
7575
}
7676

77-
mutating func testsOnly_setInternalState(_ snapshot: Snapshot) {
77+
mutating func testsOnly_setInternalState(_ snapshot: Snapshot<ConnectionType>) {
7878
self.state = snapshot.state
7979
self.availableConnections = snapshot.availableConnections
8080
self.leasedConnections = snapshot.leasedConnections
@@ -109,15 +109,15 @@ extension HTTP1ConnectionProvider {
109109
return self.openedConnectionsCount == 0 && self.pending == 0
110110
}
111111

112-
mutating func acquire(waiter: Waiter) -> Action {
112+
mutating func acquire(waiter: Waiter<ConnectionType>) -> Action<ConnectionType> {
113113
switch self.state {
114114
case .active:
115115
self.pending -= 1
116116

117117
let (eventLoop, required) = self.resolvePreference(waiter.preference)
118118
if required {
119119
// If there is an opened connection on the same EL - use it
120-
if let found = self.availableConnections.firstIndex(where: { $0.channel.eventLoop === eventLoop }) {
120+
if let found = self.availableConnections.firstIndex(where: { $0.eventLoop === eventLoop }) {
121121
let connection = self.availableConnections.remove(at: found)
122122
self.leasedConnections.insert(ConnectionKey(connection))
123123
return .lease(connection, waiter)
@@ -151,7 +151,7 @@ extension HTTP1ConnectionProvider {
151151
}
152152
}
153153

154-
mutating func release(connection: Connection, closing: Bool) -> Action {
154+
mutating func release(connection: ConnectionType, closing: Bool) -> Action<ConnectionType> {
155155
switch self.state {
156156
case .active:
157157
assert(self.leasedConnections.contains(ConnectionKey(connection)))
@@ -161,12 +161,12 @@ extension HTTP1ConnectionProvider {
161161
let (eventLoop, required) = self.resolvePreference(waiter.preference)
162162

163163
// If returned connection is on same EL or we do not require special EL - lease it
164-
if connection.channel.eventLoop === eventLoop || !required {
164+
if connection.eventLoop === eventLoop || !required {
165165
return .lease(connection, waiter)
166166
}
167167

168168
// If there is an opened connection on the same loop, lease it and park returned
169-
if let found = self.availableConnections.firstIndex(where: { $0.channel.eventLoop === eventLoop }) {
169+
if let found = self.availableConnections.firstIndex(where: { $0.eventLoop === eventLoop }) {
170170
self.leasedConnections.remove(ConnectionKey(connection))
171171
let replacement = self.availableConnections.swap(at: found, with: connection)
172172
self.leasedConnections.insert(ConnectionKey(replacement))
@@ -203,7 +203,7 @@ extension HTTP1ConnectionProvider {
203203
}
204204
}
205205

206-
mutating func offer(connection: Connection) -> Action {
206+
mutating func offer(connection: ConnectionType) -> Action<ConnectionType> {
207207
switch self.state {
208208
case .active:
209209
self.leasedConnections.insert(ConnectionKey(connection))
@@ -214,7 +214,7 @@ extension HTTP1ConnectionProvider {
214214
}
215215
}
216216

217-
mutating func drop(connection: Connection) {
217+
mutating func drop(connection: ConnectionType) {
218218
switch self.state {
219219
case .active:
220220
self.leasedConnections.remove(ConnectionKey(connection))
@@ -223,7 +223,7 @@ extension HTTP1ConnectionProvider {
223223
}
224224
}
225225

226-
mutating func connectFailed() -> Action {
226+
mutating func connectFailed() -> Action<ConnectionType> {
227227
switch self.state {
228228
case .active:
229229
self.openedConnectionsCount -= 1
@@ -239,7 +239,7 @@ extension HTTP1ConnectionProvider {
239239
}
240240
}
241241

242-
mutating func remoteClosed(connection: Connection) -> Action {
242+
mutating func remoteClosed(connection: ConnectionType) -> Action<ConnectionType> {
243243
switch self.state {
244244
case .active:
245245
// Connection can be closed remotely while we wait for `.lease` action to complete.
@@ -260,7 +260,7 @@ extension HTTP1ConnectionProvider {
260260
}
261261
}
262262

263-
mutating func timeout(connection: Connection) -> Action {
263+
mutating func timeout(connection: ConnectionType) -> Action<ConnectionType> {
264264
switch self.state {
265265
case .active:
266266
// We can get timeout and inUse = true when we decided to lease the connection, but this action is not executed yet.
@@ -285,12 +285,12 @@ extension HTTP1ConnectionProvider {
285285
}
286286
}
287287

288-
mutating func processNextWaiter() -> Action {
288+
mutating func processNextWaiter() -> Action<ConnectionType> {
289289
if let waiter = self.waiters.popFirst() {
290290
let (eventLoop, required) = self.resolvePreference(waiter.preference)
291291

292292
// If specific EL is required, we have only two options - find open one or create a new one
293-
if required, let found = self.availableConnections.firstIndex(where: { $0.channel.eventLoop === eventLoop }) {
293+
if required, let found = self.availableConnections.firstIndex(where: { $0.eventLoop === eventLoop }) {
294294
let connection = self.availableConnections.remove(at: found)
295295
self.leasedConnections.insert(ConnectionKey(connection))
296296
return .lease(connection, waiter)
@@ -313,7 +313,7 @@ extension HTTP1ConnectionProvider {
313313
return .none
314314
}
315315

316-
mutating func close() -> (CircularBuffer<Waiter>, CircularBuffer<Connection>, Set<ConnectionKey>, Bool)? {
316+
mutating func close() -> (CircularBuffer<Waiter<ConnectionType>>, CircularBuffer<ConnectionType>, Set<ConnectionKey<ConnectionType>>, Bool)? {
317317
switch self.state {
318318
case .active:
319319
let waiters = self.waiters

Tests/AsyncHTTPClientTests/ConnectionPoolTests.swift

+9-9
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class ConnectionPoolTests: XCTestCase {
2828
var http1ConnectionProvider: HTTP1ConnectionProvider!
2929

3030
func testPending() {
31-
var state = HTTP1ConnectionProvider.ConnectionsState(eventLoop: self.eventLoop)
31+
var state = HTTP1ConnectionProvider.ConnectionsState<Connection>(eventLoop: self.eventLoop)
3232

3333
var snapshot = state.testsOnly_getInternalState()
3434
XCTAssertEqual(0, snapshot.availableConnections.count)
@@ -50,7 +50,7 @@ class ConnectionPoolTests: XCTestCase {
5050
// MARK: - Acquire Tests
5151

5252
func testAcquireWhenEmpty() {
53-
var state = HTTP1ConnectionProvider.ConnectionsState(eventLoop: self.eventLoop)
53+
var state = HTTP1ConnectionProvider.ConnectionsState<Connection>(eventLoop: self.eventLoop)
5454

5555
var snapshot = state.testsOnly_getInternalState()
5656
XCTAssertEqual(0, snapshot.availableConnections.count)
@@ -155,7 +155,7 @@ class ConnectionPoolTests: XCTestCase {
155155
// MARK: - Acquire on Specific EL Tests
156156

157157
func testAcquireWhenEmptySpecificEL() {
158-
var state = HTTP1ConnectionProvider.ConnectionsState(eventLoop: self.eventLoop)
158+
var state = HTTP1ConnectionProvider.ConnectionsState<Connection>(eventLoop: self.eventLoop)
159159
var snapshot = state.testsOnly_getInternalState()
160160

161161
XCTAssertEqual(0, snapshot.availableConnections.count)
@@ -301,7 +301,7 @@ class ConnectionPoolTests: XCTestCase {
301301
// MARK: - Acquire Errors Tests
302302

303303
func testAcquireWhenClosed() {
304-
var state = HTTP1ConnectionProvider.ConnectionsState(eventLoop: self.eventLoop)
304+
var state = HTTP1ConnectionProvider.ConnectionsState<Connection>(eventLoop: self.eventLoop)
305305
_ = state.close()
306306

307307
XCTAssertFalse(state.enqueue())
@@ -317,7 +317,7 @@ class ConnectionPoolTests: XCTestCase {
317317
}
318318

319319
func testConnectFailedWhenClosed() {
320-
var state = HTTP1ConnectionProvider.ConnectionsState(eventLoop: self.eventLoop)
320+
var state = HTTP1ConnectionProvider.ConnectionsState<Connection>(eventLoop: self.eventLoop)
321321
_ = state.close()
322322

323323
let action = state.connectFailed()
@@ -1222,7 +1222,7 @@ class ConnectionPoolTests: XCTestCase {
12221222
// MARK: - Shutdown tests
12231223

12241224
func testShutdownOnPendingAndSuccess() {
1225-
var state = HTTP1ConnectionProvider.ConnectionsState(eventLoop: self.eventLoop)
1225+
var state = HTTP1ConnectionProvider.ConnectionsState<Connection>(eventLoop: self.eventLoop)
12261226

12271227
XCTAssertTrue(state.enqueue())
12281228

@@ -1261,7 +1261,7 @@ class ConnectionPoolTests: XCTestCase {
12611261
}
12621262

12631263
func testShutdownOnPendingAndError() {
1264-
var state = HTTP1ConnectionProvider.ConnectionsState(eventLoop: self.eventLoop)
1264+
var state = HTTP1ConnectionProvider.ConnectionsState<Connection>(eventLoop: self.eventLoop)
12651265

12661266
XCTAssertTrue(state.enqueue())
12671267

@@ -1298,7 +1298,7 @@ class ConnectionPoolTests: XCTestCase {
12981298
}
12991299

13001300
func testShutdownTimeout() {
1301-
var state = HTTP1ConnectionProvider.ConnectionsState(eventLoop: self.eventLoop)
1301+
var state = HTTP1ConnectionProvider.ConnectionsState<Connection>(eventLoop: self.eventLoop)
13021302

13031303
var snapshot = self.http1ConnectionProvider.state.testsOnly_getInternalState()
13041304

@@ -1333,7 +1333,7 @@ class ConnectionPoolTests: XCTestCase {
13331333
}
13341334

13351335
func testShutdownRemoteClosed() {
1336-
var state = HTTP1ConnectionProvider.ConnectionsState(eventLoop: self.eventLoop)
1336+
var state = HTTP1ConnectionProvider.ConnectionsState<Connection>(eventLoop: self.eventLoop)
13371337

13381338
var snapshot = self.http1ConnectionProvider.state.testsOnly_getInternalState()
13391339

Tests/AsyncHTTPClientTests/ConnectionPoolTestsSupport.swift

+6-6
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ import NIO
1717
import XCTest
1818

1919
extension ConnectionPoolTests {
20-
func buildState(count: Int, release: Bool = true, eventLoop: EventLoop? = nil) -> (HTTP1ConnectionProvider.ConnectionsState, [Connection]) {
20+
func buildState(count: Int, release: Bool = true, eventLoop: EventLoop? = nil) -> (HTTP1ConnectionProvider.ConnectionsState<Connection>, [Connection]) {
2121
let eventLoop = eventLoop ?? self.eventLoop!
2222

23-
var state = HTTP1ConnectionProvider.ConnectionsState(eventLoop: eventLoop)
23+
var state = HTTP1ConnectionProvider.ConnectionsState<Connection>(eventLoop: eventLoop)
2424
var items: [Connection] = []
2525

2626
if count == 0 {
@@ -60,7 +60,7 @@ extension ConnectionPoolTests {
6060
}
6161
}
6262

63-
func XCTAssertState(_ state: HTTP1ConnectionProvider.ConnectionsState, available: Int, leased: Int, waiters: Int, pending: Int, opened: Int) {
63+
func XCTAssertState<ConnectionType>(_ state: HTTP1ConnectionProvider.ConnectionsState<ConnectionType>, available: Int, leased: Int, waiters: Int, pending: Int, opened: Int) {
6464
let snapshot = state.testsOnly_getInternalState()
6565
XCTAssertEqual(available, snapshot.availableConnections.count)
6666
XCTAssertEqual(leased, snapshot.leasedConnections.count)
@@ -69,7 +69,7 @@ func XCTAssertState(_ state: HTTP1ConnectionProvider.ConnectionsState, available
6969
XCTAssertEqual(opened, snapshot.openedConnectionsCount)
7070
}
7171

72-
func XCTAssertState(_ state: HTTP1ConnectionProvider.ConnectionsState, available: Int, leased: Int, waiters: Int, pending: Int, opened: Int, isLeased connection: Connection) {
72+
func XCTAssertState<ConnectionType>(_ state: HTTP1ConnectionProvider.ConnectionsState<ConnectionType>, available: Int, leased: Int, waiters: Int, pending: Int, opened: Int, isLeased connection: ConnectionType) {
7373
let snapshot = state.testsOnly_getInternalState()
7474
XCTAssertEqual(available, snapshot.availableConnections.count)
7575
XCTAssertEqual(leased, snapshot.leasedConnections.count)
@@ -79,7 +79,7 @@ func XCTAssertState(_ state: HTTP1ConnectionProvider.ConnectionsState, available
7979
XCTAssertTrue(snapshot.leasedConnections.contains(ConnectionKey(connection)))
8080
}
8181

82-
func XCTAssertState(_ state: HTTP1ConnectionProvider.ConnectionsState, available: Int, leased: Int, waiters: Int, pending: Int, opened: Int, isNotLeased connection: Connection) {
82+
func XCTAssertState<ConnectionType>(_ state: HTTP1ConnectionProvider.ConnectionsState<ConnectionType>, available: Int, leased: Int, waiters: Int, pending: Int, opened: Int, isNotLeased connection: ConnectionType) {
8383
let snapshot = state.testsOnly_getInternalState()
8484
XCTAssertEqual(available, snapshot.availableConnections.count)
8585
XCTAssertEqual(leased, snapshot.leasedConnections.count)
@@ -100,7 +100,7 @@ func XCTUnwrap<T>(_ value: T?) throws -> T {
100100

101101
struct TempError: Error {}
102102

103-
func XCTAssertStateClose(_ state: HTTP1ConnectionProvider.ConnectionsState, available: Int, leased: Int, waiters: Int, clean: Bool) throws {
103+
func XCTAssertStateClose<ConnectionType>(_ state: HTTP1ConnectionProvider.ConnectionsState<ConnectionType>, available: Int, leased: Int, waiters: Int, clean: Bool) throws {
104104
var state = state
105105

106106
let (foundWaiters, foundAvailable, foundLeased, foundClean) = try XCTUnwrap(state.close())

0 commit comments

Comments
 (0)