Skip to content

Commit 3ee07ab

Browse files
authored
perf: smaller future size (#1360)
closes #1359
1 parent f43943b commit 3ee07ab

2 files changed

Lines changed: 21 additions & 5 deletions

File tree

pgdog/src/backend/pool/healthcheck.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,16 @@ impl<'a> Healtcheck<'a> {
5555
return Ok(());
5656
}
5757

58-
match safe_timeout(self.healthcheck_timeout, self.conn.healthcheck(";")).await {
58+
// Boxed to keep the ~1.6 KB query future out of this state machine:
59+
// it is inlined all the way up into `Pool::get`, which is built and
60+
// moved on every checkout, while the query itself runs at most once
61+
// per healthcheck interval.
62+
match safe_timeout(
63+
self.healthcheck_timeout,
64+
Box::pin(self.conn.healthcheck(";")),
65+
)
66+
.await
67+
{
5968
Ok(Ok(())) => Ok(()),
6069
Ok(Err(err)) => {
6170
// Check if this is an administrator command termination

pgdog/src/util.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
pub(crate) mod time;
44

55
use chrono::{DateTime, Local, Utc};
6+
use futures::{FutureExt, future::Either};
67
use once_cell::sync::Lazy;
78
use rand::{Rng, distr::Alphanumeric};
89
use std::ops::ControlFlow;
@@ -315,16 +316,22 @@ fn armable(duration: Option<Duration>) -> Option<Duration> {
315316

316317
/// [`tokio::time::timeout`] that waits forever instead of arming a timer
317318
/// outside [`MAX_TIMER_DURATION`].
318-
pub(crate) async fn safe_timeout<F>(
319+
///
320+
/// Not an `async fn` on purpose: an async wrapper's state machine holds `F`
321+
/// once as its argument and again inside the [`tokio::time::Timeout`] it
322+
/// builds, so every call has to copy the whole future between the two slots.
323+
/// Some of the futures passed here are kilobytes ([`crate::backend::pool::Pool::get`]),
324+
/// and that copy is large enough to show up as `memcpy` in profiles.
325+
pub(crate) fn safe_timeout<F>(
319326
duration: Duration,
320327
future: F,
321-
) -> Result<F::Output, tokio::time::error::Elapsed>
328+
) -> impl Future<Output = Result<F::Output, tokio::time::error::Elapsed>>
322329
where
323330
F: Future,
324331
{
325332
match armable(Some(duration)) {
326-
Some(duration) => tokio::time::timeout(duration, future).await,
327-
None => Ok(future.await),
333+
Some(duration) => Either::Left(tokio::time::timeout(duration, future)),
334+
None => Either::Right(future.map(Ok)),
328335
}
329336
}
330337

0 commit comments

Comments
 (0)