Skip to content

Commit

Permalink
feat(dns): tokio_threadpool::blocking resolver
Browse files Browse the repository at this point in the history
Unlike the default resolver, this avoids spawning extra dedicated
threads but only works on the multi-threaded Tokio runtime.

Closes hyperium#1676
  • Loading branch information
sfackler committed Oct 20, 2018
1 parent 6fe532d commit 106b904
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -62,6 +63,7 @@ runtime = [
"tokio-reactor",
"tokio-tcp",
"tokio-timer",
"tokio-threadpool",
]
nightly = []
__internal_flaky_tests = []
Expand Down
47 changes: 47 additions & 0 deletions src/client/connect/dns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<GaiAddrs, io::Error> {
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};
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand Down

0 comments on commit 106b904

Please sign in to comment.