5#include <gtest/gtest.h>
41 EXPECT_TRUE(buffer.
empty());
42 EXPECT_FALSE(buffer.
full());
43 EXPECT_EQ(buffer.
size(), 0);
46 for (
int i = 0; i < 7; ++i) {
47 auto result = buffer.
write(std::move(i));
48 EXPECT_TRUE(result.is_ok()) <<
"Failed to write " << i;
51 EXPECT_EQ(buffer.
size(), 7);
52 EXPECT_FALSE(buffer.
empty());
53 EXPECT_TRUE(buffer.
full());
56 auto result = buffer.
write(std::move(999));
57 EXPECT_FALSE(result.is_ok());
61 for (
int i = 0; i < 7; ++i) {
62 auto read_result = buffer.
read(value);
63 EXPECT_TRUE(read_result.is_ok());
67 EXPECT_TRUE(buffer.
empty());
79 for (
int i = 0; i < 8; ++i) {
80 auto result = buffer.
write(std::move(i));
81 EXPECT_TRUE(result.is_ok());
85 std::vector<int> read_values;
87 while (buffer.
read(value).is_ok()) {
88 read_values.push_back(value);
91 EXPECT_GE(read_values.size(), 3);
98 std::vector<int> write_data = {1, 2, 3, 4, 5};
99 size_t written = buffer.
write_batch(std::move(write_data));
100 EXPECT_EQ(written, 5);
103 std::vector<int> read_data;
104 size_t read_count = buffer.
read_batch(read_data, 10);
105 EXPECT_EQ(read_count, 5);
106 EXPECT_EQ(read_data.size(), 5);
108 for (
size_t i = 0; i < read_data.size(); ++i) {
109 EXPECT_EQ(read_data[i],
static_cast<int>(i + 1));
116 buffer.
write(std::move(42));
117 buffer.
write(std::move(84));
120 auto result = buffer.
peek(value);
121 EXPECT_TRUE(result.is_ok());
122 EXPECT_EQ(value, 42);
125 EXPECT_EQ(buffer.
size(), 2);
129 EXPECT_EQ(value, 42);
137 EXPECT_EQ(metric_double.
as_double(), 3.14159);
141 EXPECT_EQ(metric_int.
as_int64(), 42);
146 EXPECT_EQ(metric_string.
as_string(),
"test");
155 for (
int i = 0; i < 5; ++i) {
160 EXPECT_EQ(batch.
size(), 5);
161 EXPECT_FALSE(batch.
empty());
165 EXPECT_TRUE(batch.
empty());
173 std::vector<double> samples = {0.001, 0.01, 0.1, 0.5, 1.0, 2.0, 5.0, 10.0};
174 for (
double sample : samples) {
179 EXPECT_GT(hist.
sum, 0);
180 EXPECT_GT(hist.
mean(), 0);
183 for (
const auto& bucket : hist.
buckets) {
184 EXPECT_GE(bucket.count, 0);
195 ASSERT_TRUE(series_result.is_ok());
196 auto& series = series_result.value();
198 EXPECT_TRUE(series->empty());
199 EXPECT_EQ(series->name(),
"test_series");
202 auto now = std::chrono::system_clock::now();
203 for (
int i = 0; i < 10; ++i) {
204 auto timestamp = now + std::chrono::seconds(i);
205 auto result = series->add_point(
static_cast<double>(i), timestamp);
206 EXPECT_TRUE(result.is_ok());
209 EXPECT_EQ(series->size(), 10);
210 EXPECT_FALSE(series->empty());
213 auto latest = series->get_latest_value();
214 EXPECT_TRUE(latest.is_ok());
215 EXPECT_EQ(latest.value(), 9.0);
220 ASSERT_TRUE(series_result.is_ok());
221 auto& series = series_result.value();
223 auto now = std::chrono::system_clock::now();
226 for (
int i = 0; i < 60; ++i) {
227 auto timestamp = now + std::chrono::seconds(i);
228 series->add_point(
static_cast<double>(i), timestamp);
233 query.
start_time = now + std::chrono::seconds(10);
234 query.
end_time = now + std::chrono::seconds(50);
235 query.
step = std::chrono::seconds(10);
237 auto result = series->query(query);
238 EXPECT_TRUE(result.is_ok());
240 const auto& agg_result = result.value();
241 EXPECT_GT(agg_result.points.size(), 0);
242 EXPECT_GT(agg_result.total_samples, 0);
244 auto summary = agg_result.get_summary();
246 EXPECT_GE(
summary.min_value, 10.0);
247 EXPECT_LE(
summary.max_value, 50.0);
260 auto result1 =
storage.store_metric(
"cpu_usage", 65.5, metric_type::gauge);
261 EXPECT_TRUE(result1.is_ok());
263 auto result2 =
storage.store_metric(
"memory_usage", 4096.0, metric_type::gauge);
264 EXPECT_TRUE(result2.is_ok());
266 auto result3 =
storage.store_metric(
"request_count", 100.0, metric_type::counter);
267 EXPECT_TRUE(result3.is_ok());
273 auto cpu =
storage.get_latest_value(
"cpu_usage");
274 EXPECT_TRUE(
cpu.is_ok());
275 EXPECT_EQ(
cpu.value(), 65.5);
278 EXPECT_TRUE(
memory.is_ok());
279 EXPECT_EQ(
memory.value(), 4096.0);
282 auto names =
storage.get_metric_names();
283 EXPECT_GE(names.size(), 3);
286 const auto& stats =
storage.get_stats();
287 EXPECT_GE(stats.total_metrics_stored.load(), 3);
288 EXPECT_EQ(stats.total_metrics_dropped.load(), 0);
297 auto init_result =
storage.store_metric(
"batch_metric", 0.0, metric_type::gauge);
298 EXPECT_TRUE(init_result.is_ok());
304 for (
int i = 0; i < 50; ++i) {
310 size_t stored =
storage.store_metrics_batch(batch);
311 EXPECT_EQ(stored, 50);
317 auto result =
storage.query_metric(
"batch_metric", query);
318 EXPECT_TRUE(result.is_ok());
330 EXPECT_TRUE(
storage.store_metric(
"metric1", 1.0).is_ok());
331 EXPECT_TRUE(
storage.store_metric(
"metric2", 2.0).is_ok());
334 auto result =
storage.store_metric(
"metric3", 3.0);
337 const auto& stats =
storage.get_stats();
338 EXPECT_LE(stats.active_metric_series.load(), 2);
344 const int num_threads = 4;
345 const int metrics_per_thread = 100;
346 std::vector<std::thread> threads;
349 for (
int t = 0; t < num_threads; ++t) {
350 threads.emplace_back([&
storage, t, metrics_per_thread]() {
351 std::random_device rd;
352 std::mt19937 gen(rd());
353 std::uniform_real_distribution<> dis(0.0, 100.0);
355 for (
int i = 0; i < metrics_per_thread; ++i) {
356 std::string metric_name =
"thread_" + std::to_string(t) +
"_metric_" + std::to_string(i);
357 double value = dis(gen);
358 storage.store_metric(metric_name, value);
361 std::this_thread::sleep_for(std::chrono::microseconds(1));
367 for (
auto& thread : threads) {
374 const auto& stats =
storage.get_stats();
375 EXPECT_GT(stats.total_metrics_stored.load(), num_threads * metrics_per_thread * 0.8);
377 auto names =
storage.get_metric_names();
378 EXPECT_GT(names.size(), 0);
385 invalid_ring_config.
capacity = 1000;
387 auto validation = invalid_ring_config.
validate();
388 EXPECT_FALSE(validation.is_ok());
394 validation = valid_ring_config.
validate();
395 EXPECT_TRUE(validation.is_ok());
401 validation = invalid_ts_config.
validate();
402 EXPECT_FALSE(validation.is_ok());
408 validation = invalid_storage_config.
validate();
409 EXPECT_FALSE(validation.is_ok());
Test suite for Phase 3 P1: Memory-efficient metric storage.
Thread-safe metric storage with ring buffer buffering.
void flush()
Flush buffered metrics to time series.
Lock-free ring buffer with atomic operations.
size_t write_batch(std::vector< T > &&items)
Write multiple elements in batch.
size_t size() const noexcept
Get current number of elements in buffer.
common::VoidResult write(T &&item)
Write a single element to the buffer.
size_t capacity() const noexcept
Get buffer capacity.
size_t read_batch(std::vector< T > &items, size_t max_count=SIZE_MAX)
Read multiple elements in batch.
bool full() const noexcept
Check if buffer is full.
common::VoidResult peek(T &item) const
Peek at the next item without removing it.
common::VoidResult read(T &item)
Read a single element from the buffer.
bool empty() const noexcept
Check if buffer is empty.
static common::Result< std::unique_ptr< time_series > > create(const std::string &name, const time_series_config &config={})
Factory method to create time_series with validation.
Memory-efficient metric storage with ring buffer backend.
Common metric type definitions for efficient storage.
@ summary
Pre-calculated quantiles and count/sum.
metric_metadata create_metric_metadata(const std::string &name, metric_type type, size_t tag_count=0)
Create metric metadata from name and type.
@ storage
Storage device sensor.
@ memory
Memory/DRAM power domain (RAPL)
@ cpu
CPU power domain (RAPL)
Lock-free ring buffer for efficient metric storage.
Memory-efficient metric value storage.
double as_double() const
Get value as double.
std::string as_string() const
Get value as string.
bool is_numeric() const noexcept
Check if metric is numeric.
int64_t as_int64() const
Get value as integer.
Histogram data with buckets.
double mean() const noexcept
Get mean value.
void init_standard_buckets()
Initialize standard buckets.
std::vector< histogram_bucket > buckets
void add_sample(double value)
Add value to histogram.
Batch of metrics for efficient processing.
void clear()
Clear all metrics.
size_t size() const noexcept
Get number of metrics in batch.
void add_metric(compact_metric_value &&metric)
Add metric to batch.
size_t memory_footprint() const noexcept
Get batch size in bytes.
bool empty() const noexcept
Check if batch is empty.
Configuration for metric storage.
bool enable_background_processing
size_t ring_buffer_capacity
common::VoidResult validate() const
Validate configuration.
Basic metric structure for interface compatibility.
Configuration for ring buffer behavior.
common::VoidResult validate() const
Validate ring buffer configuration.
Configuration for time series storage.
common::VoidResult validate() const
Validate configuration.
std::chrono::seconds retention_period
Query parameters for time series data.
std::chrono::milliseconds step
std::chrono::system_clock::time_point start_time
std::chrono::system_clock::time_point end_time
TEST_F(MetricStorageTest, RingBufferBasicOperations)
Time-series data storage for efficient metric history.