@@ -6,7 +6,7 @@ use std::time::Duration;
66
77use once_cell:: sync:: { Lazy , OnceCell } ;
88use parking_lot:: { lock_api:: MutexGuard , Mutex , RawMutex } ;
9- use tokio:: time:: Instant ;
9+ use tokio:: time:: { timeout , Instant } ;
1010use tracing:: error;
1111
1212use crate :: backend:: { Server , ServerOptions } ;
@@ -96,60 +96,78 @@ impl Pool {
9696 }
9797
9898 pub async fn get ( & self , request : & Request ) -> Result < Guard , Error > {
99- self . get_internal ( request) . await
99+ match timeout ( self . config ( ) . checkout_timeout , self . get_internal ( request) ) . await {
100+ Ok ( Ok ( conn) ) => Ok ( conn) ,
101+ Err ( _) => {
102+ self . inner . health . toggle ( false ) ;
103+ Err ( Error :: CheckoutTimeout )
104+ }
105+ Ok ( Err ( err) ) => {
106+ self . inner . health . toggle ( false ) ;
107+ Err ( err. into ( ) )
108+ }
109+ }
100110 }
101111
102112 /// Get a connection from the pool.
103113 async fn get_internal ( & self , request : & Request ) -> Result < Guard , Error > {
104- let pool = self . clone ( ) ;
105-
106- // Fast path, idle connection probably available.
107- let ( server, granted_at, paused) = {
108- // Ask for time before we acquire the lock
109- // and only if we actually waited for a connection.
110- let granted_at = request. created_at ;
111- let elapsed = granted_at. saturating_duration_since ( request. created_at ) ;
112- let mut guard = self . lock ( ) ;
114+ loop {
115+ let pool = self . clone ( ) ;
113116
114- if !guard. online {
115- return Err ( Error :: Offline ) ;
116- }
117+ // Fast path, idle connection probably available.
118+ let ( server, granted_at, paused) = {
119+ // Ask for time before we acquire the lock
120+ // and only if we actually waited for a connection.
121+ let granted_at = request. created_at ;
122+ let elapsed = granted_at. saturating_duration_since ( request. created_at ) ;
123+ let mut guard = self . lock ( ) ;
117124
118- let conn = guard. take ( request) ;
125+ if !guard. online {
126+ return Err ( Error :: Offline ) ;
127+ }
119128
120- if conn. is_some ( ) {
121- guard. stats . counts . wait_time += elapsed;
122- guard. stats . counts . server_assignment_count += 1 ;
123- }
129+ let conn = guard. take ( request) ;
124130
125- ( conn, granted_at, guard. paused )
126- } ;
131+ if conn. is_some ( ) {
132+ guard. stats . counts . wait_time += elapsed;
133+ guard. stats . counts . server_assignment_count += 1 ;
134+ }
127135
128- if paused {
129- self . comms ( ) . ready . notified ( ) . await ;
130- }
136+ ( conn, granted_at, guard. paused )
137+ } ;
131138
132- let ( server, granted_at) = if let Some ( mut server) = server {
133- server
134- . prepared_statements_mut ( )
135- . set_capacity ( self . inner . config . prepared_statements_limit ) ;
136- server. set_pooler_mode ( self . inner . config . pooler_mode ) ;
137- ( Guard :: new ( pool, server, granted_at) , granted_at)
138- } else {
139- // Slow path, pool is empty, will create new connection
140- // or wait for one to be returned if the pool is maxed out.
141- let mut waiting = Waiting :: new ( pool, request) ?;
142- waiting. wait ( ) . await ?
143- } ;
139+ if paused {
140+ self . comms ( ) . ready . notified ( ) . await ;
141+ }
144142
145- return self
146- . maybe_healthcheck (
147- server,
148- self . inner . config . healthcheck_timeout ,
149- self . inner . config . healthcheck_interval ,
150- granted_at,
151- )
152- . await ;
143+ let ( server, granted_at) = if let Some ( mut server) = server {
144+ server
145+ . prepared_statements_mut ( )
146+ . set_capacity ( self . inner . config . prepared_statements_limit ) ;
147+ server. set_pooler_mode ( self . inner . config . pooler_mode ) ;
148+ ( Guard :: new ( pool, server, granted_at) , granted_at)
149+ } else {
150+ // Slow path, pool is empty, will create new connection
151+ // or wait for one to be returned if the pool is maxed out.
152+ let mut waiting = Waiting :: new ( pool, request) ?;
153+ waiting. wait ( ) . await ?
154+ } ;
155+
156+ match self
157+ . maybe_healthcheck (
158+ server,
159+ self . inner . config . healthcheck_timeout ,
160+ self . inner . config . healthcheck_interval ,
161+ granted_at,
162+ )
163+ . await
164+ {
165+ Ok ( conn) => return Ok ( conn) ,
166+ // Try another connection.
167+ Err ( Error :: HealthcheckError ) => continue ,
168+ Err ( err) => return Err ( err) ,
169+ }
170+ }
153171 }
154172
155173 /// Get server parameters, fetch them if necessary.
0 commit comments