@@ -16,12 +16,12 @@ use std::net::{
16
16
use std:: str:: FromStr ;
17
17
use std:: sync:: Arc ;
18
18
19
+ use futures_util:: { FutureExt , StreamExt } ;
19
20
use tokio_executor:: TypedExecutor ;
20
- use tokio_sync:: oneshot;
21
+ use tokio_sync:: { mpsc , oneshot} ;
21
22
use tokio_threadpool;
22
23
23
- use crate :: common:: { Future , Pin , Poll , Unpin , task} ;
24
- use self :: sealed:: GaiTask ;
24
+ use crate :: common:: { Future , Never , Pin , Poll , Unpin , task} ;
25
25
26
26
/// Resolve a hostname to a set of IP addresses.
27
27
pub trait Resolve : Unpin {
@@ -42,18 +42,24 @@ pub struct Name {
42
42
/// A resolver using blocking `getaddrinfo` calls in a threadpool.
43
43
#[ derive( Clone ) ]
44
44
pub struct GaiResolver {
45
- executor : GaiExecutor ,
45
+ tx : tokio_threadpool:: Sender ,
46
+ /// A handle to keep the threadpool alive until all `GaiResolver` clones
47
+ /// have been dropped.
48
+ _threadpool_keep_alive : ThreadPoolKeepAlive ,
46
49
}
47
50
51
+ #[ derive( Clone ) ]
52
+ struct ThreadPoolKeepAlive ( mpsc:: Sender < Never > ) ;
53
+
48
54
/// An iterator of IP addresses returned from `getaddrinfo`.
49
55
pub struct GaiAddrs {
50
56
inner : IpAddrs ,
51
57
}
52
58
53
59
/// A future to resole a name returned by `GaiResolver`.
54
60
pub struct GaiFuture {
55
- // rx: oneshot::SpawnHandle< IpAddrs, io::Error>,
56
- blocking : GaiBlocking ,
61
+ rx : oneshot:: Receiver < Result < IpAddrs , io:: Error > > ,
62
+ _threadpool_keep_alive : ThreadPoolKeepAlive ,
57
63
}
58
64
59
65
impl Name {
@@ -96,64 +102,66 @@ pub struct InvalidNameError(());
96
102
97
103
impl fmt:: Display for InvalidNameError {
98
104
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
99
- self . description ( ) . fmt ( f )
105
+ f . write_str ( "Not a valid domain name" )
100
106
}
101
107
}
102
108
103
- impl Error for InvalidNameError {
104
- fn description ( & self ) -> & str {
105
- "Not a valid domain name"
106
- }
107
- }
109
+ impl Error for InvalidNameError { }
108
110
109
111
110
112
impl GaiResolver {
111
113
/// Construct a new `GaiResolver`.
112
114
///
113
115
/// Takes number of DNS worker threads.
114
116
pub fn new ( threads : usize ) -> Self {
115
- GaiResolver {
116
- executor : GaiExecutor ,
117
- }
118
- /*
119
- use tokio_threadpool::Builder;
120
-
121
- let pool = Builder::new()
117
+ let pool = tokio_threadpool:: Builder :: new ( )
122
118
. name_prefix ( "hyper-dns-gai-resolver" )
123
119
// not for CPU tasks, so only spawn workers
124
120
// in blocking mode
125
121
. pool_size ( 1 )
126
122
. max_blocking ( threads)
127
123
. build ( ) ;
128
- GaiResolver::new_with_executor(pool)
129
- */
130
- }
131
124
132
- /*
133
- /// Construct a new `GaiResolver` with a shared thread pool executor.
134
- ///
135
- /// Takes an executor to run blocking `getaddrinfo` tasks on.
136
- /*pub */fn new_with_executor<E: 'static>(executor: E) -> Self
137
- where
138
- E: TypedExecutor<GaiTask> + Send + Sync,
139
- {
125
+ let tx = pool. sender ( ) . clone ( ) ;
126
+
127
+ // The pool will start to shutdown once `pool` is dropped,
128
+ // so to keep it alive, we spawn a future onto the pool itself
129
+ // that will only resolve once all `GaiResolver` requests
130
+ // are finished.
131
+ let ( shutdown_tx, shutdown_rx) = mpsc:: channel ( 1 ) ;
132
+
133
+ let on_shutdown = shutdown_rx
134
+ . into_future ( )
135
+ . map ( move |( next, _rx) | {
136
+ match next {
137
+ Some ( never) => match never { } ,
138
+ None => ( ) ,
139
+ }
140
+
141
+ drop ( pool)
142
+ } ) ;
143
+ tx. spawn ( on_shutdown) ;
144
+
140
145
GaiResolver {
141
- executor: GaiExecutor(Arc::new(executor)),
146
+ tx,
147
+ _threadpool_keep_alive : ThreadPoolKeepAlive ( shutdown_tx) ,
142
148
}
143
149
}
144
- */
145
150
}
146
151
147
152
impl Resolve for GaiResolver {
148
153
type Addrs = GaiAddrs ;
149
154
type Future = GaiFuture ;
150
155
151
156
fn resolve ( & self , name : Name ) -> Self :: Future {
152
- let blocking = GaiBlocking :: new ( name. host ) ;
153
- //let rx = oneshot::spawn(blocking, &self.executor);
157
+ let ( tx, rx) = oneshot:: channel ( ) ;
158
+ self . tx . spawn ( GaiBlocking {
159
+ host : name. host ,
160
+ tx : Some ( tx) ,
161
+ } ) ;
154
162
GaiFuture {
155
- // rx,
156
- blocking ,
163
+ rx,
164
+ _threadpool_keep_alive : self . _threadpool_keep_alive . clone ( ) ,
157
165
}
158
166
}
159
167
}
@@ -168,13 +176,11 @@ impl Future for GaiFuture {
168
176
type Output = Result < GaiAddrs , io:: Error > ;
169
177
170
178
fn poll ( mut self : Pin < & mut Self > , cx : & mut task:: Context < ' _ > ) -> Poll < Self :: Output > {
171
- /*
172
- let addrs = try_ready!(self.rx.poll());
173
- Ok(Async::Ready(GaiAddrs {
174
- inner: addrs,
175
- }))
176
- */
177
- Poll :: Ready ( self . blocking . block ( ) . map ( |addrs| GaiAddrs { inner : addrs } ) )
179
+ Pin :: new ( & mut self . rx ) . poll ( cx) . map ( |res| match res {
180
+ Ok ( Ok ( addrs) ) => Ok ( GaiAddrs { inner : addrs } ) ,
181
+ Ok ( Err ( err) ) => Err ( err) ,
182
+ Err ( _canceled) => unreachable ! ( "GaiResolver threadpool shutdown" ) ,
183
+ } )
178
184
}
179
185
}
180
186
@@ -198,27 +204,13 @@ impl fmt::Debug for GaiAddrs {
198
204
}
199
205
}
200
206
201
- #[ derive( Clone ) ]
202
- struct GaiExecutor /*(Arc<dyn Executor<GaiTask> + Send + Sync>)*/ ;
203
-
204
- /*
205
- impl Executor<oneshot::Execute<GaiBlocking>> for GaiExecutor {
206
- fn execute(&self, future: oneshot::Execute<GaiBlocking>) -> Result<(), ExecuteError<oneshot::Execute<GaiBlocking>>> {
207
- self.0.execute(GaiTask { work: future })
208
- .map_err(|err| ExecuteError::new(err.kind(), err.into_future().work))
209
- }
210
- }
211
- */
212
207
213
208
pub ( super ) struct GaiBlocking {
214
209
host : String ,
210
+ tx : Option < oneshot:: Sender < io:: Result < IpAddrs > > > ,
215
211
}
216
212
217
213
impl GaiBlocking {
218
- pub ( super ) fn new ( host : String ) -> GaiBlocking {
219
- GaiBlocking { host }
220
- }
221
-
222
214
fn block ( & self ) -> io:: Result < IpAddrs > {
223
215
debug ! ( "resolving host={:?}" , self . host) ;
224
216
( & * self . host , 0 ) . to_socket_addrs ( )
@@ -227,18 +219,25 @@ impl GaiBlocking {
227
219
}
228
220
}
229
221
230
- /*
231
222
impl Future for GaiBlocking {
232
- type Item = IpAddrs;
233
- type Error = io::Error;
223
+ type Output = ( ) ;
224
+
225
+ fn poll ( mut self : Pin < & mut Self > , cx : & mut task:: Context < ' _ > ) -> Poll < Self :: Output > {
226
+ if self . tx . as_mut ( ) . expect ( "polled after complete" ) . poll_closed ( cx) . is_ready ( ) {
227
+ trace ! ( "resolve future canceled for {:?}" , self . host) ;
228
+ return Poll :: Ready ( ( ) ) ;
229
+ }
234
230
235
- fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
236
231
debug ! ( "resolving host={:?}" , self . host) ;
237
- (&*self.host, 0).to_socket_addrs()
238
- .map(|i| Async::Ready(IpAddrs { iter: i }))
232
+ let res = ( & * self . host , 0 ) . to_socket_addrs ( )
233
+ . map ( |i| IpAddrs { iter : i } ) ;
234
+
235
+ let tx = self . tx . take ( ) . expect ( "polled after complete" ) ;
236
+ let _ = tx. send ( res) ;
237
+
238
+ Poll :: Ready ( ( ) )
239
239
}
240
240
}
241
- */
242
241
243
242
pub ( super ) struct IpAddrs {
244
243
iter : vec:: IntoIter < SocketAddr > ,
@@ -297,33 +296,6 @@ impl Iterator for IpAddrs {
297
296
}
298
297
}
299
298
300
- // Make this Future unnameable outside of this crate.
301
- pub ( super ) mod sealed {
302
- use super :: * ;
303
- // Blocking task to be executed on a thread pool.
304
- pub struct GaiTask {
305
- //pub(super) work: oneshot::Execute<GaiBlocking>
306
- }
307
-
308
- impl fmt:: Debug for GaiTask {
309
- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
310
- f. pad ( "GaiTask" )
311
- }
312
- }
313
-
314
- /*
315
- impl Future for GaiTask {
316
- type Item = ();
317
- type Error = ();
318
-
319
- fn poll(&mut self) -> Poll<(), ()> {
320
- self.work.poll()
321
- }
322
- }
323
- */
324
- }
325
-
326
-
327
299
/// A resolver using `getaddrinfo` calls via the `tokio_threadpool::blocking` API.
328
300
///
329
301
/// Unlike the `GaiResolver` this will not spawn dedicated threads, but only works when running on the
0 commit comments