1313//===----------------------------------------------------------------------===//
1414
1515import Foundation
16+ import Logging
1617import NIO
1718import NIOConcurrencyHelpers
1819import NIOHTTP1
@@ -64,21 +65,29 @@ final class ConnectionPool {
6465 /// When the pool is asked for a new connection, it creates a `Key` from the url associated to the `request`. This key
6566 /// is used to determine if there already exists an associated `HTTP1ConnectionProvider` in `providers`.
6667 /// If there is, the connection provider then takes care of leasing a new connection. If a connection provider doesn't exist, it is created.
67- func getConnection( for request: HTTPClient . Request , preference: HTTPClient . EventLoopPreference , on eventLoop: EventLoop , deadline: NIODeadline ? , setupComplete: EventLoopFuture < Void > ) -> EventLoopFuture < Connection > {
68+ func getConnection( _ request: HTTPClient . Request ,
69+ preference: HTTPClient . EventLoopPreference ,
70+ taskEventLoop: EventLoop ,
71+ deadline: NIODeadline ? ,
72+ setupComplete: EventLoopFuture < Void > ,
73+ logger: Logger ) -> EventLoopFuture < Connection > {
6874 let key = Key ( request)
6975
7076 let provider : HTTP1ConnectionProvider = self . lock. withLock {
7177 if let existing = self . providers [ key] , existing. enqueue ( ) {
7278 return existing
7379 } else {
7480 // Connection provider will be created with `pending = 1`
75- let provider = HTTP1ConnectionProvider ( key: key, eventLoop: eventLoop, configuration: self . configuration, pool: self )
81+ let provider = HTTP1ConnectionProvider ( key: key,
82+ eventLoop: taskEventLoop,
83+ configuration: self . configuration,
84+ pool: self )
7685 self . providers [ key] = provider
7786 return provider
7887 }
7988 }
8089
81- return provider. getConnection ( preference: preference, setupComplete: setupComplete)
90+ return provider. getConnection ( preference: preference, setupComplete: setupComplete, logger : logger )
8291 }
8392
8493 func delete( _ provider: HTTP1ConnectionProvider ) {
@@ -167,21 +176,21 @@ class Connection {
167176 /// Release this `Connection` to its associated `HTTP1ConnectionProvider`.
168177 ///
169178 /// - Warning: This only releases the connection and doesn't take care of cleaning handlers in the `Channel` pipeline.
170- func release( closing: Bool ) {
179+ func release( closing: Bool , logger : Logger ) {
171180 assert ( self . channel. eventLoop. inEventLoop)
172- self . provider. release ( connection: self , closing: closing)
181+ self . provider. release ( connection: self , closing: closing, logger : logger )
173182 }
174183
175184 /// Called when channel exceeds idle time in pool.
176- func timeout( ) {
185+ func timeout( logger : Logger ) {
177186 assert ( self . channel. eventLoop. inEventLoop)
178- self . provider. timeout ( connection: self )
187+ self . provider. timeout ( connection: self , logger : logger )
179188 }
180189
181190 /// Called when channel goes inactive while in the pool.
182- func remoteClosed( ) {
191+ func remoteClosed( logger : Logger ) {
183192 assert ( self . channel. eventLoop. inEventLoop)
184- self . provider. remoteClosed ( connection: self )
193+ self . provider. remoteClosed ( connection: self , logger : logger )
185194 }
186195
187196 func cancel( ) -> EventLoopFuture < Void > {
@@ -194,9 +203,10 @@ class Connection {
194203 }
195204
196205 /// Sets idle timeout handler and channel inactivity listener.
197- func setIdleTimeout( timeout: TimeAmount ? ) {
206+ func setIdleTimeout( timeout: TimeAmount ? , logger : Logger ) {
198207 _ = self . channel. pipeline. addHandler ( IdleStateHandler ( writeTimeout: timeout) , position: . first) . flatMap { _ in
199- self . channel. pipeline. addHandler ( IdlePoolConnectionHandler ( connection: self ) )
208+ self . channel. pipeline. addHandler ( IdlePoolConnectionHandler ( connection: self ,
209+ logger: logger) )
200210 }
201211 }
202212
@@ -280,50 +290,76 @@ class HTTP1ConnectionProvider {
280290 self . state. assertInvariants ( )
281291 }
282292
283- private func execute( _ action: Action ) {
293+ private func execute( _ action: Action , logger : Logger ) {
284294 switch action {
285295 case . lease( let connection, let waiter) :
286296 // if connection is became inactive, we create a new one.
287297 connection. cancelIdleTimeout ( ) . whenComplete { _ in
288298 if connection. isActiveEstimation {
299+ logger. trace ( " leasing existing connection " ,
300+ metadata: [ " ahc-connection " : connection] )
289301 waiter. promise. succeed ( connection)
290302 } else {
303+ logger. trace ( " opening fresh connection (found matching but inactive connection) " ,
304+ metadata: [ " ahc-dead-connection " : " \( connection) " ] )
291305 self . makeChannel ( preference: waiter. preference) . whenComplete { result in
292- self . connect ( result, waiter: waiter, replacing: connection)
306+ self . connect ( result, waiter: waiter, replacing: connection, logger : logger )
293307 }
294308 }
295309 }
296310 case . create( let waiter) :
311+ logger. trace ( " opening fresh connection (no connections to reuse available) " )
297312 self . makeChannel ( preference: waiter. preference) . whenComplete { result in
298- self . connect ( result, waiter: waiter)
313+ self . connect ( result, waiter: waiter, logger : logger )
299314 }
300315 case . replace( let connection, let waiter) :
301316 connection. cancelIdleTimeout ( ) . flatMap {
302317 connection. close ( )
303318 } . whenComplete { _ in
319+ logger. trace ( " opening fresh connection (replacing exising connection) " ,
320+ metadata: [ " ahc-old-connection " : " \( connection) " ,
321+ " ahc-waiter " : " \( waiter) " ] )
304322 self . makeChannel ( preference: waiter. preference) . whenComplete { result in
305- self . connect ( result, waiter: waiter, replacing: connection)
323+ self . connect ( result, waiter: waiter, replacing: connection, logger : logger )
306324 }
307325 }
308326 case . park( let connection) :
309- connection. setIdleTimeout ( timeout: self . configuration. maximumAllowedIdleTimeInConnectionPool)
327+ logger. trace ( " parking connection " ,
328+ metadata: [ " ahc-connection " : " \( connection) " ] )
329+ connection. setIdleTimeout ( timeout: self . configuration. maximumAllowedIdleTimeInConnectionPool,
330+ logger: logger. detachingRequestInformation ( ) )
310331 case . closeProvider:
332+ logger. debug ( " closing provider " ,
333+ metadata: [ " ahc-provider " : " \( self ) " ] )
311334 self . closeAndDelete ( )
312335 case . none:
313336 break
314337 case . parkAnd( let connection, let action) :
315- connection. setIdleTimeout ( timeout: self . configuration. maximumAllowedIdleTimeInConnectionPool)
316- self . execute ( action)
338+ logger. trace ( " parking connection & doing further action " ,
339+ metadata: [ " ahc-connection " : " \( connection) " ,
340+ " ahc-action " : " \( action) " ] )
341+ connection. setIdleTimeout ( timeout: self . configuration. maximumAllowedIdleTimeInConnectionPool,
342+ logger: logger. detachingRequestInformation ( ) )
343+ self . execute ( action, logger: logger)
317344 case . closeAnd( let connection, let action) :
345+ logger. trace ( " closing connection & doing further action " ,
346+ metadata: [ " ahc-connection " : " \( connection) " ,
347+ " ahc-action " : " \( action) " ] )
318348 connection. channel. close ( promise: nil )
319- self . execute ( action)
349+ self . execute ( action, logger : logger )
320350 case . cancel( let connection, let close) :
351+ logger. trace ( " cancelling connection " ,
352+ metadata: [ " ahc-connection " : " \( connection) " ,
353+ " ahc-close " : " \( close) " ] )
321354 connection. cancel ( ) . whenComplete { _ in
322355 if close {
323356 self . closeAndDelete ( )
324357 }
325358 }
326359 case . fail( let waiter, let error) :
360+ logger. debug ( " failing connection for waiter " ,
361+ metadata: [ " ahc-waiter " : " \( waiter) " ,
362+ " ahc-error " : " \( error) " ] )
327363 waiter. promise. fail ( error)
328364 }
329365 }
@@ -335,19 +371,24 @@ class HTTP1ConnectionProvider {
335371 }
336372 }
337373
338- func getConnection( preference: HTTPClient . EventLoopPreference , setupComplete: EventLoopFuture < Void > ) -> EventLoopFuture < Connection > {
374+ func getConnection( preference: HTTPClient . EventLoopPreference ,
375+ setupComplete: EventLoopFuture < Void > ,
376+ logger: Logger ) -> EventLoopFuture < Connection > {
339377 let waiter = Waiter ( promise: self . eventLoop. makePromise ( ) , setupComplete: setupComplete, preference: preference)
340378
341379 let action : Action = self . lock. withLock {
342380 self . state. acquire ( waiter: waiter)
343381 }
344382
345- self . execute ( action)
383+ self . execute ( action, logger : logger )
346384
347385 return waiter. promise. futureResult
348386 }
349387
350- func connect( _ result: Result < Channel , Error > , waiter: Waiter , replacing closedConnection: Connection ? = nil ) {
388+ func connect( _ result: Result < Channel , Error > ,
389+ waiter: Waiter ,
390+ replacing closedConnection: Connection ? = nil ,
391+ logger: Logger ) {
351392 let action : Action
352393 switch result {
353394 case . success( let channel) :
@@ -366,11 +407,13 @@ class HTTP1ConnectionProvider {
366407 waiter. promise. fail ( error)
367408 }
368409 waiter. setupComplete. whenComplete { _ in
369- self . execute ( action)
410+ self . execute ( action, logger : logger )
370411 }
371412 }
372413
373- func release( connection: Connection , closing: Bool ) {
414+ func release( connection: Connection , closing: Bool , logger: Logger ) {
415+ logger. debug ( " releasing connection, request complete " ,
416+ metadata: [ " ahc-closing " : " \( closing) " ] )
374417 let action : Action = self . lock. withLock {
375418 self . state. release ( connection: connection, closing: closing)
376419 }
@@ -381,31 +424,31 @@ class HTTP1ConnectionProvider {
381424 case . park, . closeProvider:
382425 // Since both `.park` and `.deleteProvider` are terminal in terms of execution,
383426 // we can execute them immediately
384- self . execute ( action)
427+ self . execute ( action, logger : logger )
385428 case . cancel, . closeAnd, . create, . fail, . lease, . parkAnd, . replace:
386429 // This is needed to start a new stack, otherwise, since this is called on a previous
387430 // future completion handler chain, it will be growing indefinitely until the connection is closed.
388431 // We might revisit this when https://github.com/apple/swift-nio/issues/970 is resolved.
389432 connection. channel. eventLoop. execute {
390- self . execute ( action)
433+ self . execute ( action, logger : logger )
391434 }
392435 }
393436 }
394437
395- func remoteClosed( connection: Connection ) {
438+ func remoteClosed( connection: Connection , logger : Logger ) {
396439 let action : Action = self . lock. withLock {
397440 self . state. remoteClosed ( connection: connection)
398441 }
399442
400- self . execute ( action)
443+ self . execute ( action, logger : logger )
401444 }
402445
403- func timeout( connection: Connection ) {
446+ func timeout( connection: Connection , logger : Logger ) {
404447 let action : Action = self . lock. withLock {
405448 self . state. timeout ( connection: connection)
406449 }
407450
408- self . execute ( action)
451+ self . execute ( action, logger : logger )
409452 }
410453
411454 private func closeAndDelete( ) {
@@ -510,25 +553,27 @@ class IdlePoolConnectionHandler: ChannelInboundHandler, RemovableChannelHandler
510553
511554 let connection : Connection
512555 var eventSent : Bool
556+ let logger : Logger
513557
514- init ( connection: Connection ) {
558+ init ( connection: Connection , logger : Logger ) {
515559 self . connection = connection
516560 self . eventSent = false
561+ self . logger = logger
517562 }
518563
519564 // this is needed to detect when remote end closes connection while connection is in the pool idling
520565 func channelInactive( context: ChannelHandlerContext ) {
521566 if !self . eventSent {
522567 self . eventSent = true
523- self . connection. remoteClosed ( )
568+ self . connection. remoteClosed ( logger : self . logger )
524569 }
525570 }
526571
527572 func userInboundEventTriggered( context: ChannelHandlerContext , event: Any ) {
528573 if let idleEvent = event as? IdleStateHandler . IdleStateEvent , idleEvent == . write {
529574 if !self . eventSent {
530575 self . eventSent = true
531- self . connection. timeout ( )
576+ self . connection. timeout ( logger : self . logger )
532577 }
533578 } else {
534579 context. fireUserInboundEventTriggered ( event)
0 commit comments