pub struct ConnectionResolver { /* private fields */ }Expand description
What one connection may ask the resolver to do at once.
Two tiers, because a single shared pool answers only one of the two questions worth asking:
- One reserved slot, held by this connection alone and by nothing else. No number of hostile connections can take it away, so a connection is never starved outright – at worst its lookups run one at a time. This is the guarantee; the shared allowance is only ever an optimisation on top of it.
BURST_LOOKUPSfrom the shared allowance, so ordinary use – a client opening thirty tunnels at once – still resolves them in parallel, while one connection can never hold more than its share of the pool.
The waiting itself is inside the caller’s connect_timeout, so a lookup that
cannot get a slot in time is refused exactly as a resolver that did not
answer in time is, with the same 504 and the same Proxy-Status (D90).
One of these per connection, made by ResolverBudget::per_connection and
held for the connection’s whole life by its crate::tunnel::Context.
Deliberately not Clone: the bound is the connection’s, so a second handle
counting separately would be no bound at all. That is also why the three
semaphores are held inline rather than behind an Arc: with one owner and no
clone, the allocation bought nothing. Each semaphore keeps its own, because
acquire_owned needs an Arc<Semaphore> and one of them is the server-wide
allowance every connection really does share.
Implementations§
Source§impl ConnectionResolver
impl ConnectionResolver
Sourcepub async fn lookup(&self, host: &str, port: u16) -> Result<Vec<SocketAddr>>
pub async fn lookup(&self, host: &str, port: u16) -> Result<Vec<SocketAddr>>
resolve, with a slot in the blocking pool taken for the length of it.
An IP literal never reaches the resolver and so never occupies a thread: it is answered without taking a slot at all, which keeps the budget spent on the only thing that can block.