@@ -208,6 +208,17 @@ impl<K: Key, T: Poolable + Send + 'static> Pool<K, T> {
208
208
} )
209
209
}
210
210
211
+ /// Returns a `Checkout` which is a future that resolves if an idle
212
+ /// connection becomes available.
213
+ pub fn checkout ( & self , key : K , waiter : ( oneshot:: Receiver < T > , usize ) ) -> Checkout < K , T > {
214
+ Checkout {
215
+ key,
216
+ pool : self . clone ( ) ,
217
+ waiter,
218
+ clean : true ,
219
+ }
220
+ }
221
+
211
222
pub async fn get < MT > (
212
223
& self ,
213
224
key : K ,
@@ -219,7 +230,7 @@ impl<K: Key, T: Poolable + Send + 'static> Pool<K, T> {
219
230
MT : UnaryService < K , Response = T > + Send + ' static + Sync ,
220
231
MT :: Error : Into < crate :: ClientError > + Send ,
221
232
{
222
- let ( rx, _waiter_token ) = {
233
+ let ( rx, waiter_token ) = {
223
234
let entry = ' outer: loop {
224
235
let entry = ' inner: {
225
236
let mut inner = self . inner . lock ( ) . volo_unwrap ( ) ;
@@ -286,6 +297,7 @@ impl<K: Key, T: Poolable + Send + 'static> Pool<K, T> {
286
297
} ;
287
298
288
299
// 3. select waiter and mc return future
300
+ let checkout = self . checkout ( key. clone ( ) , ( rx, waiter_token) ) ;
289
301
let connector = {
290
302
let key = key. clone ( ) ;
291
303
let this = self . clone ( ) ;
@@ -309,7 +321,7 @@ impl<K: Key, T: Poolable + Send + 'static> Pool<K, T> {
309
321
} ;
310
322
311
323
// waiter or make transport finished
312
- match future:: select ( rx , started:: lazy ( connector) ) . await {
324
+ match future:: select ( checkout , started:: lazy ( connector) ) . await {
313
325
Either :: Left ( ( Ok ( v) , fut) ) => {
314
326
// check the make transport future has started
315
327
if fut. started ( ) {
@@ -407,6 +419,43 @@ impl<K: Key, T: Poolable> Drop for Connecting<K, T> {
407
419
}
408
420
}
409
421
422
+ pub struct Checkout < K : Key , T : Poolable > {
423
+ key : K ,
424
+ pool : Pool < K , T > ,
425
+ waiter : ( oneshot:: Receiver < T > , usize ) ,
426
+ clean : bool ,
427
+ }
428
+
429
+ impl < K : Key , T : Poolable > Future for Checkout < K , T > {
430
+ type Output = Result < T , oneshot:: error:: RecvError > ;
431
+
432
+ fn poll ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
433
+ match Pin :: new ( & mut self . waiter . 0 ) . poll ( cx) {
434
+ Poll :: Ready ( v) => {
435
+ // Successfully received an idle connection, it means that the corresponding tx is
436
+ // already popped from waiters, so no need to remove it again.
437
+ self . clean = false ;
438
+ Poll :: Ready ( v)
439
+ }
440
+ Poll :: Pending => Poll :: Pending ,
441
+ }
442
+ }
443
+ }
444
+
445
+ impl < K : Key , T : Poolable > Drop for Checkout < K , T > {
446
+ fn drop ( & mut self ) {
447
+ // if clean needed, remove the corresponding tx from waiters
448
+ if self . clean {
449
+ tracing:: trace!( "checkout dropped for {:?}" , self . key) ;
450
+ if let Ok ( mut pool) = self . pool . inner . lock ( ) {
451
+ if let Some ( waiters) = pool. waiters . get_mut ( & self . key ) {
452
+ waiters. remove ( self . waiter . 1 ) ;
453
+ }
454
+ }
455
+ }
456
+ }
457
+ }
458
+
410
459
struct Idle < T > {
411
460
inner : T ,
412
461
idle_at : Instant ,
0 commit comments