pub struct WorkerClientPool { /* private fields */ }Expand description
Connection pool for WorkerClient instances.
Caches authenticated gRPC channels by worker address, avoiding the overhead
of re-establishing connections and re-authenticating for every block I/O.
Matches Java’s FileSystemContext.acquireBlockWorkerClient() pattern.
The pool is thread-safe and can be shared across concurrent workers.
§Single-Flight Reconnect
When a SASL stream silently expires server-side, many concurrent RPCs on
the same cached channel will fail simultaneously with UNAUTHENTICATED.
Without coordination each observer would independently invoke reconnect,
producing a “thundering herd” that serialises through the pool’s write
lock and wastes CPU/RTT on duplicate TCP+SASL handshakes.
To collapse this herd, each WorkerClient carries a monotonic
generation tag. Callers pass the observed generation back into
reconnect_if_stale after an auth failure;
only the first observer of a given generation actually performs the
reconnect, all other concurrent observers receive the already-replaced
client. This reduces N concurrent reconnects to exactly 1.
Implementations§
Source§impl WorkerClientPool
impl WorkerClientPool
Sourcepub fn new(config: GoosefsConfig) -> Self
pub fn new(config: GoosefsConfig) -> Self
Create a new empty connection pool.
Sourcepub async fn acquire(&self, addr: &str) -> Result<WorkerClient>
pub async fn acquire(&self, addr: &str) -> Result<WorkerClient>
Acquire a WorkerClient for the given address.
Returns a cached client if one exists, otherwise creates a new connection.
The tonic Channel supports multiplexing, so a single cached client can
handle multiple concurrent RPCs.
Sourcepub async fn invalidate(&self, addr: &str)
pub async fn invalidate(&self, addr: &str)
Remove a worker from the pool (e.g., after a connection failure).
The next acquire() call for this address will create a fresh connection.
Sourcepub async fn reconnect_if_stale(
&self,
addr: &str,
stale_generation: u64,
) -> Result<WorkerClient>
pub async fn reconnect_if_stale( &self, addr: &str, stale_generation: u64, ) -> Result<WorkerClient>
Single-flight reconnect: invalidate + reconnect only if the
currently cached client’s generation still matches stale_generation.
This is the preferred recovery path on authentication failure. The
caller passes the generation() of the client that just failed;
because every WorkerClient carries a unique monotonic generation
allocated by this pool:
- If another concurrent task has already reconnected in response
to the same underlying SASL expiry, the cached generation will have
advanced past
stale_generationand this call returns the already-replaced client without performing another TCP+SASL handshake. - Otherwise, this call performs exactly one reconnect under the per-address mutex.
Net effect: N concurrent AuthenticationFailed observers on the
same channel trigger exactly one reconnect instead of N.
Sourcepub async fn reconnect(&self, addr: &str) -> Result<WorkerClient>
pub async fn reconnect(&self, addr: &str) -> Result<WorkerClient>
Invalidate a cached worker connection and immediately reconnect.
Prefer reconnect_if_stale whenever the
caller holds a reference to the failing WorkerClient — it
deduplicates concurrent reconnects triggered by the same underlying
SASL expiry.
This unconditional variant is kept for paths where the caller does
not know the generation of the failing client (e.g. a stand-alone
connect() failure that never produced a WorkerClient). It
acquires the same per-address reconnect mutex so it still coalesces
against any in-flight reconnect_if_stale.
Create a new pool wrapped in Arc for shared ownership.
Auto Trait Implementations§
impl !Freeze for WorkerClientPool
impl !RefUnwindSafe for WorkerClientPool
impl Send for WorkerClientPool
impl Sync for WorkerClientPool
impl Unpin for WorkerClientPool
impl UnsafeUnpin for WorkerClientPool
impl !UnwindSafe for WorkerClientPool
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request