mirror of https://github.com/mongodb/mongo
SERVER-114944: Add a templated atomic-based counter class. (#45058)
GitOrigin-RevId: 9b281196fc1e2b75a6884148a04a9d3177a9454d
This commit is contained in:
parent
5ddbc7c494
commit
bdc1063064
|
|
@ -18,6 +18,14 @@ idl_generator(
|
|||
src = "metrics_settings.idl",
|
||||
)
|
||||
|
||||
mongo_cc_unit_test(
|
||||
name = "metrics_counter_test",
|
||||
srcs = [
|
||||
"metrics_counter_test.cpp",
|
||||
],
|
||||
tags = ["mongo_unittest_third_group"],
|
||||
)
|
||||
|
||||
mongo_cc_library(
|
||||
name = "otel_metrics",
|
||||
srcs = [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* Copyright (C) 2025-present MongoDB, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the Server Side Public License, version 1,
|
||||
* as published by MongoDB, Inc.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Server Side Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Server Side Public License
|
||||
* along with this program. If not, see
|
||||
* <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
*
|
||||
* As a special exception, the copyright holders give permission to link the
|
||||
* code of portions of this program with the OpenSSL library under certain
|
||||
* conditions as described in each individual source file and distribute
|
||||
* linked combinations including the program with the OpenSSL library. You
|
||||
* must comply with the Server Side Public License in all respects for
|
||||
* all of the code used other than as permitted herein. If you modify file(s)
|
||||
* with this exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||
* delete this exception statement from your version. If you delete this
|
||||
* exception statement from all source files in the program, then also delete
|
||||
* it in the license file.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "mongo/platform/atomic.h"
|
||||
#include "mongo/util/assert_util.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "src/mongo/util/modules.h"
|
||||
|
||||
namespace mongo::otel::metrics {
|
||||
|
||||
template <typename T>
|
||||
class MONGO_MOD_PUBLIC Counter {
|
||||
public:
|
||||
// T must be nonnegative.
|
||||
virtual void add(T value) = 0;
|
||||
|
||||
virtual T value() const = 0;
|
||||
|
||||
virtual const std::string& name() const = 0;
|
||||
|
||||
virtual const std::string& description() const = 0;
|
||||
|
||||
virtual const std::string& unit() const = 0;
|
||||
};
|
||||
|
||||
// A lock free (non-decreasing) counter and metadata about it.
|
||||
template <typename T>
|
||||
class CounterImpl : public Counter<T> {
|
||||
public:
|
||||
CounterImpl(std::string name, std::string description, std::string unit);
|
||||
|
||||
void add(T value) override;
|
||||
|
||||
T value() const override {
|
||||
return _value.load();
|
||||
}
|
||||
|
||||
const std::string& name() const override {
|
||||
return _name;
|
||||
}
|
||||
|
||||
const std::string& description() const override {
|
||||
return _description;
|
||||
}
|
||||
|
||||
const std::string& unit() const override {
|
||||
return _unit;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string _name;
|
||||
std::string _description;
|
||||
std::string _unit;
|
||||
Atomic<T> _value;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation details
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T>
|
||||
CounterImpl<T>::CounterImpl(std::string name, std::string description, std::string unit)
|
||||
: _name(std::move(name)), _description(std::move(description)), _unit(std::move(unit)) {}
|
||||
|
||||
template <typename T>
|
||||
void CounterImpl<T>::add(T value) {
|
||||
massert(ErrorCodes::BadValue, "Counter increment must be nonnegative", value >= 0);
|
||||
_value.fetchAndAddRelaxed(value);
|
||||
}
|
||||
|
||||
} // namespace mongo::otel::metrics
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* Copyright (C) 2025-present MongoDB, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the Server Side Public License, version 1,
|
||||
* as published by MongoDB, Inc.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Server Side Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Server Side Public License
|
||||
* along with this program. If not, see
|
||||
* <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
*
|
||||
* As a special exception, the copyright holders give permission to link the
|
||||
* code of portions of this program with the OpenSSL library under certain
|
||||
* conditions as described in each individual source file and distribute
|
||||
* linked combinations including the program with the OpenSSL library. You
|
||||
* must comply with the Server Side Public License in all respects for
|
||||
* all of the code used other than as permitted herein. If you modify file(s)
|
||||
* with this exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||
* delete this exception statement from your version. If you delete this
|
||||
* exception statement from all source files in the program, then also delete
|
||||
* it in the license file.
|
||||
*/
|
||||
|
||||
#include "mongo/otel/metrics/metrics_counter.h"
|
||||
|
||||
#include "mongo/stdx/thread.h"
|
||||
#include "mongo/unittest/unittest.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace mongo::otel::metrics {
|
||||
|
||||
TEST(Int64CounterImplTest, Adds) {
|
||||
CounterImpl<int64_t> counter("name", "description", "unit");
|
||||
ASSERT_EQ(counter.value(), 0);
|
||||
counter.add(1);
|
||||
ASSERT_EQ(counter.value(), 1);
|
||||
counter.add(10);
|
||||
ASSERT_EQ(counter.value(), 11);
|
||||
}
|
||||
|
||||
TEST(Int64CounterImplTest, AddsZero) {
|
||||
CounterImpl<int64_t> counter("name", "description", "unit");
|
||||
ASSERT_EQ(counter.value(), 0);
|
||||
counter.add(0);
|
||||
ASSERT_EQ(counter.value(), 0);
|
||||
counter.add(10);
|
||||
counter.add(0);
|
||||
ASSERT_EQ(counter.value(), 10);
|
||||
}
|
||||
|
||||
TEST(Int64CounterImplTest, ExceptionOnNegativeAdd) {
|
||||
CounterImpl<int64_t> counter("name", "description", "unit");
|
||||
counter.add(1);
|
||||
counter.add(3);
|
||||
ASSERT_THROWS_CODE(counter.add(-1), DBException, ErrorCodes::BadValue);
|
||||
}
|
||||
|
||||
// Any issues with thread safety should be caught by tsan on this test.
|
||||
TEST(Int64CounterImplTest, ConcurrentAdds) {
|
||||
CounterImpl<int64_t> counter("name", "description", "unit");
|
||||
constexpr int kNumThreads = 10;
|
||||
constexpr int kIncrementsPerThread = 1000;
|
||||
|
||||
std::vector<stdx::thread> threads;
|
||||
for (int i = 0; i < kNumThreads; ++i) {
|
||||
threads.emplace_back([&counter]() {
|
||||
for (int j = 0; j < kIncrementsPerThread; ++j) {
|
||||
counter.add(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (stdx::thread& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
ASSERT_EQ(counter.value(), kNumThreads * kIncrementsPerThread);
|
||||
}
|
||||
|
||||
} // namespace mongo::otel::metrics
|
||||
Loading…
Reference in New Issue