aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Common/CurrentMetrics.h
blob: a1ef254485ddf52a19aa57fe215cd4fa02919171 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#pragma once

#include <cstddef>
#include <cstdint>
#include <utility>
#include <atomic>
#include <cassert>
#include <base/types.h>
#include <base/strong_typedef.h>

/** Allows to count number of simultaneously happening processes or current value of some metric.
  *  - for high-level profiling.
  *
  * See also ProfileEvents.h
  * ProfileEvents counts number of happened events - for example, how many times queries was executed.
  * CurrentMetrics counts number of simultaneously happening events - for example, number of currently executing queries, right now,
  *  or just current value of some metric - for example, replica delay in seconds.
  *
  * CurrentMetrics are updated instantly and are correct for any point in time.
  * For periodically (asynchronously) updated metrics, see AsynchronousMetrics.h
  */

namespace CurrentMetrics
{
    /// Metric identifier (index in array).
    using Metric = StrongTypedef<size_t, struct MetricTag>;
    using Value = DB::Int64;

    /// Get name of metric by identifier. Returns statically allocated string.
    const char * getName(Metric event);
    /// Get text description of metric by identifier. Returns statically allocated string.
    const char * getDocumentation(Metric event);

    /// Metric identifier -> current value of metric.
    extern std::atomic<Value> values[];

    /// Get index just after last metric identifier.
    Metric end();

    /// Set value of specified metric.
    inline void set(Metric metric, Value value)
    {
        values[metric].store(value, std::memory_order_relaxed);
    }

    /// Get value of specified metric.
    inline Value get(Metric metric)
    {
        return values[metric].load(std::memory_order_relaxed);
    }

    /// Add value for specified metric. You must subtract value later; or see class Increment below.
    inline void add(Metric metric, Value value = 1)
    {
        values[metric].fetch_add(value, std::memory_order_relaxed);
    }

    inline void sub(Metric metric, Value value = 1)
    {
        add(metric, -value);
    }

    /// For lifetime of object, add amount for specified metric. Then subtract.
    class Increment
    {
    private:
        std::atomic<Value> * what;
        Value amount;

        Increment(std::atomic<Value> * what_, Value amount_)
            : what(what_), amount(amount_)
        {
            *what += amount;
        }

    public:
        explicit Increment(Metric metric, Value amount_ = 1)
            : Increment(&values[metric], amount_)
        {
            assert(metric < CurrentMetrics::end());
        }

        ~Increment()
        {
            if (what)
                what->fetch_sub(amount, std::memory_order_relaxed);
        }

        Increment(Increment && old) noexcept
        {
            *this = std::move(old);
        }

        Increment & operator=(Increment && old) noexcept
        {
            what = old.what;
            amount = old.amount;
            old.what = nullptr;
            return *this;
        }

        void changeTo(Value new_amount)
        {
            what->fetch_add(new_amount - amount, std::memory_order_relaxed);
            amount = new_amount;
        }

        void sub(Value value = 1)
        {
            what->fetch_sub(value, std::memory_order_relaxed);
            amount -= value;
        }

        void add(Value value = 1)
        {
            what->fetch_add(value, std::memory_order_relaxed);
            amount += value;
        }

        /// Subtract value before destructor.
        void destroy()
        {
            what->fetch_sub(amount, std::memory_order_relaxed);
            what = nullptr;
        }
    };
}