@@ -18,6 +18,7 @@ pub use self::internal::Cached;
1818// more public, but we can't change type shapes (generics) once things are
1919// public.
2020mod internal {
21+ use std:: collections:: VecDeque ;
2122 use std:: fmt;
2223 use std:: future:: Future ;
2324 use std:: pin:: Pin ;
@@ -108,7 +109,7 @@ mod internal {
108109 #[ derive( Debug ) ]
109110 pub struct Shared < S > {
110111 services : Vec < S > ,
111- waiters : Vec < oneshot:: Sender < S > > ,
112+ waiters : VecDeque < oneshot:: Sender < S > > ,
112113 }
113114
114115 // impl Builder
@@ -149,7 +150,7 @@ mod internal {
149150 events : self . events ,
150151 shared : Arc :: new ( Mutex :: new ( Shared {
151152 services : Vec :: new ( ) ,
152- waiters : Vec :: new ( ) ,
153+ waiters : VecDeque :: new ( ) ,
153154 } ) ) ,
154155 }
155156 }
@@ -205,7 +206,7 @@ mod internal {
205206 }
206207
207208 let ( tx, rx) = oneshot:: channel ( ) ;
208- locked. waiters . push ( tx) ;
209+ locked. waiters . push_back ( tx) ;
209210 rx
210211 } ;
211212
@@ -363,7 +364,7 @@ mod internal {
363364 impl < V > Shared < V > {
364365 fn put ( & mut self , val : V ) {
365366 let mut val = Some ( val) ;
366- while let Some ( tx) = self . waiters . pop ( ) {
367+ while let Some ( tx) = self . waiters . pop_front ( ) {
367368 if !tx. is_closed ( ) {
368369 match tx. send ( val. take ( ) . unwrap ( ) ) {
369370 Ok ( ( ) ) => break ,
@@ -491,4 +492,72 @@ mod tests {
491492 let cached = f. await . expect ( "call" ) ;
492493 drop ( cached) ;
493494 }
495+
496+ // A returned connection is handed to waiters in the order they parked
497+ // (FIFO), so a waiter cannot be starved by later arrivals.
498+ #[ tokio:: test]
499+ async fn test_waiters_woken_in_fifo_order ( ) {
500+ use std:: future:: Future ;
501+ use std:: task:: { Context , Poll , Waker } ;
502+
503+ let ( mock, mut handle) = tower_test:: mock:: pair :: < u32 , & ' static str > ( ) ;
504+ let mut cache = super :: builder ( ) . build ( mock) ;
505+ handle. allow ( 16 ) ;
506+
507+ // Establish one connection and hold it, so the next checkouts find no
508+ // idle service and park.
509+ std:: future:: poll_fn ( |cx| cache. poll_ready ( cx) )
510+ . await
511+ . unwrap ( ) ;
512+ let held = future:: join ( cache. call ( 0 ) , async {
513+ assert_request_eq ! ( handle, 0 ) . send_response ( "conn" ) ;
514+ } )
515+ . await
516+ . 0
517+ . expect ( "call" ) ;
518+
519+ // Park three checkouts in order. Each misses and starts a connect, but
520+ // the connect is never completed, so each parks on its waiter.
521+ let mut cx = Context :: from_waker ( Waker :: noop ( ) ) ;
522+ std:: future:: poll_fn ( |cx| cache. poll_ready ( cx) )
523+ . await
524+ . unwrap ( ) ;
525+ let mut first = Box :: pin ( cache. call ( 1 ) ) ;
526+ assert ! ( first. as_mut( ) . poll( & mut cx) . is_pending( ) ) ;
527+ std:: future:: poll_fn ( |cx| cache. poll_ready ( cx) )
528+ . await
529+ . unwrap ( ) ;
530+ let mut second = Box :: pin ( cache. call ( 2 ) ) ;
531+ assert ! ( second. as_mut( ) . poll( & mut cx) . is_pending( ) ) ;
532+ std:: future:: poll_fn ( |cx| cache. poll_ready ( cx) )
533+ . await
534+ . unwrap ( ) ;
535+ let mut third = Box :: pin ( cache. call ( 3 ) ) ;
536+ assert ! ( third. as_mut( ) . poll( & mut cx) . is_pending( ) ) ;
537+
538+ // Returning the connection wakes the oldest waiter first.
539+ drop ( held) ;
540+ let first = match first. as_mut ( ) . poll ( & mut cx) {
541+ Poll :: Ready ( r) => r. expect ( "first" ) ,
542+ Poll :: Pending => panic ! ( "oldest waiter was not woken first" ) ,
543+ } ;
544+ assert ! ( second. as_mut( ) . poll( & mut cx) . is_pending( ) ) ;
545+ assert ! ( third. as_mut( ) . poll( & mut cx) . is_pending( ) ) ;
546+
547+ // Returning it again wakes the next-oldest, then the last.
548+ drop ( first) ;
549+ let second = match second. as_mut ( ) . poll ( & mut cx) {
550+ Poll :: Ready ( r) => r. expect ( "second" ) ,
551+ Poll :: Pending => panic ! ( "second waiter was not woken next" ) ,
552+ } ;
553+ assert ! ( third. as_mut( ) . poll( & mut cx) . is_pending( ) ) ;
554+
555+ drop ( second) ;
556+ match third. as_mut ( ) . poll ( & mut cx) {
557+ Poll :: Ready ( r) => {
558+ r. expect ( "third" ) ;
559+ }
560+ Poll :: Pending => panic ! ( "last waiter was not woken" ) ,
561+ }
562+ }
494563}
0 commit comments