metrics/
lock.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5use crate::{register_meter_with_group, Meter};
6use parking_lot::{
7    Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
8};
9use std::{
10    ops::{Deref, DerefMut},
11    sync::Arc,
12    time::Instant,
13};
14
15/// Metric type for locks, e.g. `Mutex` and `RwLock`.
16pub struct Lock {
17    acquire_tps: Arc<dyn Meter>, // lock acquires per second
18    wait_time: Arc<dyn Meter>,   // lock wait time per second
19    hold_time: Arc<dyn Meter>,   // lock hold time per second
20}
21
22impl Lock {
23    pub fn register(name: &str) -> Self {
24        Lock {
25            acquire_tps: register_meter_with_group(name, "acquires"),
26            wait_time: register_meter_with_group(name, "wait_t"),
27            hold_time: register_meter_with_group(name, "hold_t"),
28        }
29    }
30}
31
32pub trait MutexExtensions<T> {
33    fn lock_with_metric(&self, metric: &Lock) -> MutexGuardWithMetrics<'_, T>;
34}
35
36impl<T> MutexExtensions<T> for Mutex<T> {
37    fn lock_with_metric(&self, metric: &Lock) -> MutexGuardWithMetrics<'_, T> {
38        metric.acquire_tps.mark(1);
39        let start = Instant::now();
40        let guard = self.lock();
41        metric.wait_time.mark(start.elapsed().as_nanos() as usize);
42        MutexGuardWithMetrics::new(guard, metric.hold_time.clone())
43    }
44}
45
46pub trait RwLockExtensions<T> {
47    fn read_with_metric(
48        &self, metric: &Lock,
49    ) -> RwLockReadGuardWithMetrics<'_, T>;
50    fn write_with_metric(
51        &self, metric: &Lock,
52    ) -> RwLockWriteGuardWithMetrics<'_, T>;
53}
54
55impl<T> RwLockExtensions<T> for RwLock<T> {
56    fn read_with_metric(
57        &self, metric: &Lock,
58    ) -> RwLockReadGuardWithMetrics<'_, T> {
59        metric.acquire_tps.mark(1);
60        let start = Instant::now();
61        let guard = self.read();
62        metric.wait_time.mark(start.elapsed().as_nanos() as usize);
63        RwLockReadGuardWithMetrics::new(guard, metric.hold_time.clone())
64    }
65
66    fn write_with_metric(
67        &self, metric: &Lock,
68    ) -> RwLockWriteGuardWithMetrics<'_, T> {
69        metric.acquire_tps.mark(1);
70        let start = Instant::now();
71        let guard = self.write();
72        metric.wait_time.mark(start.elapsed().as_nanos() as usize);
73        RwLockWriteGuardWithMetrics::new(guard, metric.hold_time.clone())
74    }
75}
76
77pub type MutexGuardWithMetrics<'a, T> = LockGuard<MutexGuard<'a, T>>;
78pub type RwLockReadGuardWithMetrics<'a, T> = LockGuard<RwLockReadGuard<'a, T>>;
79pub type RwLockWriteGuardWithMetrics<'a, T> =
80    LockGuard<RwLockWriteGuard<'a, T>>;
81
82pub struct LockGuard<GUARD> {
83    raw: GUARD,
84    start: Instant,
85    lock_hold_time: Arc<dyn Meter>,
86}
87
88impl<GUARD> LockGuard<GUARD> {
89    fn new(raw: GUARD, lock_hold_time: Arc<dyn Meter>) -> Self {
90        LockGuard {
91            raw,
92            start: Instant::now(),
93            lock_hold_time,
94        }
95    }
96}
97
98impl<GUARD> Drop for LockGuard<GUARD> {
99    fn drop(&mut self) {
100        let elapsed_nano = self.start.elapsed().as_nanos() as usize;
101        self.lock_hold_time.mark(elapsed_nano);
102    }
103}
104
105impl<T, GUARD: Deref<Target = T>> Deref for LockGuard<GUARD> {
106    type Target = T;
107
108    fn deref(&self) -> &T { &self.raw }
109}
110
111impl<T, GUARD: DerefMut<Target = T>> DerefMut for LockGuard<GUARD> {
112    fn deref_mut(&mut self) -> &mut T { &mut self.raw }
113}