From 1e8d6439cf4f9c7224fe80f0aeee32e2af1adbb0 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 20 Oct 2018 10:54:45 -0700 Subject: [PATCH] feat(dns): tokio_threadpool::blocking resolver Unlike the default resolver, this avoids spawning extra dedicated threads but only works on the multi-threaded Tokio runtime. Closes #1676 --- Cargo.toml | 2 ++ src/client/connect/dns.rs | 47 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 3 files changed, 50 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 48535f56d0..429b0a5a9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ tokio-io = "0.1" tokio-reactor = { version = "0.1", optional = true } tokio-tcp = { version = "0.1", optional = true } tokio-timer = { version = "0.2", optional = true } +tokio-threadpool = { version = "0.1", optional = true } want = "0.0.6" [dev-dependencies] @@ -62,6 +63,7 @@ runtime = [ "tokio-reactor", "tokio-tcp", "tokio-timer", + "tokio-threadpool", ] nightly = [] __internal_flaky_tests = [] diff --git a/src/client/connect/dns.rs b/src/client/connect/dns.rs index 6628e63eff..6ca2a5c1d1 100644 --- a/src/client/connect/dns.rs +++ b/src/client/connect/dns.rs @@ -13,6 +13,9 @@ use futures_cpupool::{Builder as CpuPoolBuilder}; use self::sealed::GaiTask; +#[cfg(feature = "runtime")] +pub use self::blocking::{TokioThreadpoolGaiFuture, TokioThreadpoolGaiResolver}; + /// Resolve a hostname to a set of IP addresses. pub trait Resolve { /// The set of IP addresses to try to connect to. @@ -239,6 +242,50 @@ pub(super) mod sealed { } } +#[cfg(feature = "runtime")] +mod blocking { + use futures::{Async, Future, Poll}; + use std::io; + use std::net::ToSocketAddrs; + use tokio_threadpool; + + use super::{Name, IpAddrs, GaiAddrs, Resolve}; + + /// A resolver using `getaddrinfo` calls via the `tokio_threadpool::blocking` API. + /// + /// Unlike the `GaiResolver` this will not spawn dedicated threads, but only works when running on the + /// multi-threaded Tokio runtime. + #[derive(Clone)] + pub struct TokioThreadpoolGaiResolver(()); + + pub struct TokioThreadpoolGaiFuture { + name: Name, + } + + impl Resolve for TokioThreadpoolGaiResolver { + type Addrs = GaiAddrs; + type Future = TokioThreadpoolGaiFuture; + + fn resolve(&self, name: Name) -> TokioThreadpoolGaiFuture { + TokioThreadpoolGaiFuture { name } + } + } + + impl Future for TokioThreadpoolGaiFuture { + type Item = GaiAddrs; + type Error = io::Error; + + fn poll(&mut self) -> Poll { + match tokio_threadpool::blocking(|| (self.name.as_str(), 0).to_socket_addrs()) { + Ok(Async::Ready(Ok(iter))) => Ok(Async::Ready(GaiAddrs { inner: IpAddrs { iter } })), + Ok(Async::Ready(Err(e))) => Err(e), + Ok(Async::NotReady) => Ok(Async::NotReady), + Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)), + } + } + } +} + #[cfg(test)] mod tests { use std::net::{Ipv4Addr, Ipv6Addr}; diff --git a/src/lib.rs b/src/lib.rs index a7be454b8b..ad1f58f6a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,7 @@ extern crate time; #[cfg(feature = "runtime")] extern crate tokio_reactor; #[cfg(feature = "runtime")] extern crate tokio_tcp; #[cfg(feature = "runtime")] extern crate tokio_timer; +#[cfg(feature = "runtime")] extern crate tokio_threadpool; extern crate want; #[cfg(all(test, feature = "nightly"))]