iota_metrics/
guards.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{
6    future::Future,
7    pin::Pin,
8    task::{Context, Poll},
9};
10
11use prometheus::IntGauge;
12
13/// Increments gauge when acquired, decrements when guard drops
14pub struct GaugeGuard<'a>(&'a IntGauge);
15
16impl<'a> GaugeGuard<'a> {
17    /// Acquires an `IntGauge` by incrementing its value and creating a new
18    /// `IntGaugeGuard` instance that holds a reference to the gauge.
19    pub fn acquire(g: &'a IntGauge) -> Self {
20        g.inc();
21        Self(g)
22    }
23}
24
25impl Drop for GaugeGuard<'_> {
26    /// Decrements the value of the `IntGauge` when the `IntGaugeGuard` is
27    /// dropped.
28    fn drop(&mut self) {
29        self.0.dec();
30    }
31}
32
33pub trait GaugeGuardFutureExt: Future + Sized {
34    /// Count number of in flight futures running
35    fn count_in_flight(self, g: &IntGauge) -> GaugeGuardFuture<Self>;
36}
37
38impl<F: Future> GaugeGuardFutureExt for F {
39    /// Count number of in flight futures running.
40    fn count_in_flight(self, g: &IntGauge) -> GaugeGuardFuture<Self> {
41        GaugeGuardFuture {
42            f: Box::pin(self),
43            _guard: GaugeGuard::acquire(g),
44        }
45    }
46}
47
48/// A struct that wraps a future (`f`) with a `GaugeGuard`. The
49/// `GaugeGuardFuture` is used to manage the lifecycle of a future while
50/// ensuring the associated `GaugeGuard` properly tracks the resource usage
51/// during the future's execution. The guard increments the gauge
52/// when the future starts and decrements it when the `GaugeGuardFuture` is
53/// dropped.
54pub struct GaugeGuardFuture<'a, F: Sized> {
55    f: Pin<Box<F>>,
56    _guard: GaugeGuard<'a>,
57}
58
59impl<F: Future> Future for GaugeGuardFuture<'_, F> {
60    type Output = F::Output;
61
62    /// Polls the wrapped future (`f`) to determine its readiness. This function
63    /// forwards the poll operation to the inner future, allowing the
64    /// `GaugeGuardFuture` to manage the polling lifecycle.
65    /// Returns `Poll::Pending` if the future is not ready or `Poll::Ready` with
66    /// the future's result if complete.
67    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
68        self.f.as_mut().poll(cx)
69    }
70}