Skip to main content

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_filtered::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
33/// Difference vs `GaugeGuard`: stores the gauge by value to avoid borrowing
34/// issues. Increments the gauge when acquired, decrements when the guard drops.
35pub struct InflightGuard(IntGauge);
36
37impl InflightGuard {
38    /// Acquires an `IntGauge` by incrementing its value and taking ownership of
39    /// the gauge so it can be decremented on drop.
40    pub fn acquire(g: IntGauge) -> Self {
41        g.inc();
42        Self(g)
43    }
44}
45
46impl Drop for InflightGuard {
47    /// Decrements the value of the `IntGauge` when the guard is dropped.
48    fn drop(&mut self) {
49        self.0.dec();
50    }
51}
52
53pub trait InflightGuardFutureExt: Future + Sized {
54    /// Count number of in flight futures running
55    fn count_in_flight(self, g: IntGauge) -> InflightGuardFuture<Self>;
56}
57
58impl<F: Future> InflightGuardFutureExt for F {
59    /// Count number of in flight futures running.
60    fn count_in_flight(self, g: IntGauge) -> InflightGuardFuture<Self> {
61        InflightGuardFuture {
62            f: Box::pin(self),
63            _guard: InflightGuard::acquire(g),
64        }
65    }
66}
67
68/// A struct that wraps a future (`f`) with an `InflightGuard`. The
69/// `InflightGuardFuture` is used to manage the lifecycle of a future while
70/// ensuring the associated `InflightGuard` properly tracks the resource usage
71/// during the future's execution. The guard increments the gauge
72/// when the future starts and decrements it when the `InflightGuardFuture` is
73/// dropped.
74pub struct InflightGuardFuture<F: Sized> {
75    f: Pin<Box<F>>,
76    _guard: InflightGuard,
77}
78
79impl<F: Future> Future for InflightGuardFuture<F> {
80    type Output = F::Output;
81
82    /// Polls the wrapped future (`f`) to determine its readiness. This function
83    /// forwards the poll operation to the inner future, allowing the
84    /// `InflightGuardFuture` to manage the polling lifecycle.
85    /// Returns `Poll::Pending` if the future is not ready or `Poll::Ready` with
86    /// the future's result if complete.
87    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
88        self.f.as_mut().poll(cx)
89    }
90}