aboutsummaryrefslogtreecommitdiffstats
path: root/metrics/src/vespa/metrics/metricvalueset.hpp
blob: ada833b20e2d958bbbbc0c4a73a740f92e1adf98 (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
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once

#include "metricvalueset.h"
#include <sstream>

namespace metrics {

template<typename ValueClass>
MetricValueSet<ValueClass>::MetricValueSet() noexcept
    : _values(),
      _activeValueIndex(0),
      _flags(0)
{ }

template<typename ValueClass>
MetricValueSet<ValueClass>::MetricValueSet(const MetricValueSet& rhs) noexcept
    : _values(rhs._values),
      _activeValueIndex(rhs._activeValueIndex.load(std::memory_order_relaxed)),
      _flags(rhs._flags.load(std::memory_order_relaxed))
{ }

template<typename ValueClass>
MetricValueSet<ValueClass> & MetricValueSet<ValueClass>::operator=(const MetricValueSet& other) noexcept
{
    setValues(other.getValues());
    return *this;
}

template<typename ValueClass>
ValueClass
MetricValueSet<ValueClass>::getValues() const {
    ValueClass v{};
    if (!isReset()) {
        // Must load with acquire to match release store in setValues.
        // Note that despite being atomic on _individual fields_, this
        // does not guarantee reading a consistent snapshot _across_
        // fields for any given metric.
        const size_t readIndex(_activeValueIndex.load(std::memory_order_acquire));
        v.relaxedLoadFrom(_values[readIndex]);
    }
    return v;
}

template<typename ValueClass>
bool
MetricValueSet<ValueClass>::setValues(const ValueClass& values) {
    // Only setter-thread can write _activeValueIndex, so relaxed
    // load suffices.
    uint32_t nextIndex = (_activeValueIndex.load(std::memory_order_relaxed) + 1) % _values.size();
    // Reset flag is loaded/stored with relaxed semantics since it does not
    // carry data dependencies. _activeValueIndex has a dependency on
    // _values, however, so we must ensure that stores are published
    // and loads acquired.
    if (isReset()) {
        removeFlag(RESET);
        ValueClass resetValues{};
        resetValues.relaxedStoreInto(_values[nextIndex]);
        _activeValueIndex.store(nextIndex, std::memory_order_release);
        return false;
    } else {
        values.relaxedStoreInto(_values[nextIndex]);
        _activeValueIndex.store(nextIndex, std::memory_order_release);
        return true;
    }
}

template<typename ValueClass>
std::string
MetricValueSet<ValueClass>::toString() {
    std::ostringstream ost;
    ost << "MetricValueSet(reset=" << (isReset() ? "true" : "false")
        << ", active " << _activeValueIndex;
#if 0
    ost << "\n  empty: " << ValueClass().toString("unknown");
    for (uint32_t i=0; i<_values.size(); ++i) {
        ost << "\n  " << _values[i].toString("unknown");
    }
#endif
    ost << "\n)";
    return ost.str();
}

} // metrics