Skip to content

Commit b3a9eca

Browse files
committed
align with java impl & spec
1 parent 5f8895e commit b3a9eca

18 files changed

Lines changed: 987 additions & 441 deletions

src/iceberg/metrics/commit_report.cc

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,48 +24,51 @@
2424

2525
namespace iceberg {
2626

27-
std::unique_ptr<CommitMetrics> CommitMetrics::Of(MetricsContext& context) {
27+
std::unique_ptr<CommitMetrics> CommitMetrics::Make(MetricsContext& context) {
2828
auto m = std::unique_ptr<CommitMetrics>(new CommitMetrics());
29-
m->total_duration = context.GetTimer("total-duration");
29+
m->total_duration = context.GetTimer("total-duration", TimerUnit::kNanoseconds);
3030
m->attempts = context.GetCounter("attempts");
3131
return m;
3232
}
3333

3434
std::unique_ptr<CommitMetrics> CommitMetrics::Noop() {
35-
return CommitMetrics::Of(*MetricsContext::Null());
35+
return CommitMetrics::Make(*MetricsContext::Noop());
3636
}
3737

38-
void CommitMetrics::PopulateResult(CommitMetricsResult& result) const {
39-
result.total_duration =
40-
total_duration ? TimerResult{.unit = std::string(total_duration->Unit()),
41-
.count = total_duration->Count(),
42-
.total_duration = total_duration->TotalDuration()}
43-
: TimerResult{};
44-
result.attempts =
45-
attempts ? CounterResult{.unit = attempts->unit(), .value = attempts->value()}
46-
: CounterResult{};
38+
CommitMetricsResult CommitMetrics::ToResult() const {
39+
CommitMetricsResult result;
40+
if (total_duration && !total_duration->IsNoop()) {
41+
result.total_duration =
42+
TimerResult{.unit = std::string(total_duration->Unit()),
43+
.count = total_duration->Count(),
44+
.total_duration = total_duration->TotalDuration()};
45+
}
46+
if (attempts && !attempts->IsNoop()) {
47+
result.attempts = CounterResult{.unit = attempts->unit(), .value = attempts->value()};
48+
}
49+
return result;
4750
}
4851

4952
CommitMetricsResult CommitMetricsResult::From(
5053
const CommitMetrics& live_metrics,
5154
const std::unordered_map<std::string, std::string>& snapshot_summary) {
52-
CommitMetricsResult result;
53-
live_metrics.PopulateResult(result);
55+
auto result = live_metrics.ToResult();
5456

55-
// Helpers: parse a summary key and wrap as a typed CounterResult.
56-
auto count_field = [&snapshot_summary](const std::string& key) -> CounterResult {
57+
auto count_field =
58+
[&snapshot_summary](const std::string& key) -> std::optional<CounterResult> {
5759
auto it = snapshot_summary.find(key);
58-
if (it == snapshot_summary.end()) return {};
60+
if (it == snapshot_summary.end()) return std::nullopt;
5961
auto parsed = StringUtils::ParseNumber<int64_t>(it->second);
60-
return {.unit = CounterUnit::kCount,
61-
.value = parsed.has_value() ? parsed.value() : 0};
62+
if (!parsed.has_value()) return std::nullopt;
63+
return CounterResult{.unit = CounterUnit::kCount, .value = parsed.value()};
6264
};
63-
auto bytes_field = [&snapshot_summary](const std::string& key) -> CounterResult {
65+
auto bytes_field =
66+
[&snapshot_summary](const std::string& key) -> std::optional<CounterResult> {
6467
auto it = snapshot_summary.find(key);
65-
if (it == snapshot_summary.end()) return {.unit = CounterUnit::kBytes};
68+
if (it == snapshot_summary.end()) return std::nullopt;
6669
auto parsed = StringUtils::ParseNumber<int64_t>(it->second);
67-
return {.unit = CounterUnit::kBytes,
68-
.value = parsed.has_value() ? parsed.value() : 0};
70+
if (!parsed.has_value()) return std::nullopt;
71+
return CounterResult{.unit = CounterUnit::kBytes, .value = parsed.value()};
6972
};
7073

7174
result.added_data_files = count_field(SnapshotSummaryFields::kAddedDataFiles);
@@ -77,12 +80,12 @@ CommitMetricsResult CommitMetricsResult::From(
7780
result.added_positional_delete_files =
7881
count_field(SnapshotSummaryFields::kAddedPosDeleteFiles);
7982
result.added_dvs = count_field(SnapshotSummaryFields::kAddedDVs);
83+
result.removed_delete_files = count_field(SnapshotSummaryFields::kRemovedDeleteFiles);
8084
result.removed_positional_delete_files =
8185
count_field(SnapshotSummaryFields::kRemovedPosDeleteFiles);
8286
result.removed_dvs = count_field(SnapshotSummaryFields::kRemovedDVs);
8387
result.removed_equality_delete_files =
8488
count_field(SnapshotSummaryFields::kRemovedEqDeleteFiles);
85-
result.removed_delete_files = count_field(SnapshotSummaryFields::kRemovedDeleteFiles);
8689
result.total_delete_files = count_field(SnapshotSummaryFields::kTotalDeleteFiles);
8790
result.added_records = count_field(SnapshotSummaryFields::kAddedRecords);
8891
result.removed_records = count_field(SnapshotSummaryFields::kDeletedRecords);

src/iceberg/metrics/commit_report.h

Lines changed: 64 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#pragma once
2121

2222
#include <memory>
23+
#include <optional>
2324
#include <string>
2425
#include <unordered_map>
2526

@@ -31,112 +32,112 @@
3132

3233
namespace iceberg {
3334

34-
// Forward declaration: CommitMetricsResult is defined later in this header.
35-
struct CommitMetricsResult;
36-
37-
/// \brief Live commit metrics collected during a table commit operation.
38-
///
39-
/// Tracks the overall commit duration and retry count. File/record counts come
40-
/// from the snapshot summary after the commit succeeds and are stored separately
41-
/// in CommitMetricsResult.
42-
class ICEBERG_EXPORT CommitMetrics {
43-
public:
44-
/// \brief Create a CommitMetrics instance backed by the given MetricsContext.
45-
static std::unique_ptr<CommitMetrics> Of(MetricsContext& context);
46-
47-
/// \brief Create a CommitMetrics instance with all-noop timer and counter.
48-
static std::unique_ptr<CommitMetrics> Noop();
49-
50-
/// \brief Snapshot timer and counter values into the corresponding fields of result.
51-
///
52-
/// Only total_duration and attempts are written; the caller is responsible for
53-
/// populating the remaining snapshot-summary fields.
54-
void PopulateResult(CommitMetricsResult& result) const;
55-
56-
/// \brief Timer measuring total wall-clock time of the commit call.
57-
std::shared_ptr<Timer> total_duration;
58-
59-
/// \brief Counter for the number of commit attempts (including retries).
60-
std::shared_ptr<Counter> attempts;
61-
62-
private:
63-
CommitMetrics() = default;
64-
};
35+
// Forward declaration: CommitMetrics is defined later in this header.
36+
class CommitMetrics;
6537

6638
/// \brief Immutable snapshot of commit metrics for use in CommitReport.
39+
///
40+
/// Populated by CommitMetrics::ToResult() after a commit completes. File and
41+
/// record counts can also be combined from the snapshot summary with From().
6742
struct ICEBERG_EXPORT CommitMetricsResult {
6843
/// \brief Total wall-clock duration of the commit attempt.
69-
TimerResult total_duration;
44+
std::optional<TimerResult> total_duration;
7045
/// \brief Number of commit attempts (1 on success without retries).
71-
CounterResult attempts;
46+
std::optional<CounterResult> attempts;
7247
/// \brief Number of data files added in this commit.
73-
CounterResult added_data_files;
48+
std::optional<CounterResult> added_data_files;
7449
/// \brief Number of data files removed in this commit.
75-
CounterResult removed_data_files;
50+
std::optional<CounterResult> removed_data_files;
7651
/// \brief Total live data files after this commit.
77-
CounterResult total_data_files;
52+
std::optional<CounterResult> total_data_files;
7853
/// \brief Number of delete files added in this commit.
79-
CounterResult added_delete_files;
54+
std::optional<CounterResult> added_delete_files;
8055
/// \brief Equality delete files added.
81-
CounterResult added_equality_delete_files;
56+
std::optional<CounterResult> added_equality_delete_files;
8257
/// \brief Positional delete files added.
83-
CounterResult added_positional_delete_files;
58+
std::optional<CounterResult> added_positional_delete_files;
8459
/// \brief Deletion vectors added.
85-
CounterResult added_dvs;
60+
std::optional<CounterResult> added_dvs;
61+
/// \brief Number of delete files removed in this commit.
62+
std::optional<CounterResult> removed_delete_files;
8663
/// \brief Positional delete files removed.
87-
CounterResult removed_positional_delete_files;
64+
std::optional<CounterResult> removed_positional_delete_files;
8865
/// \brief Deletion vectors removed.
89-
CounterResult removed_dvs;
66+
std::optional<CounterResult> removed_dvs;
9067
/// \brief Equality delete files removed.
91-
CounterResult removed_equality_delete_files;
92-
/// \brief Number of delete files removed in this commit.
93-
CounterResult removed_delete_files;
68+
std::optional<CounterResult> removed_equality_delete_files;
9469
/// \brief Total live delete files after this commit.
95-
CounterResult total_delete_files;
70+
std::optional<CounterResult> total_delete_files;
9671
/// \brief Number of records added in this commit.
97-
CounterResult added_records;
72+
std::optional<CounterResult> added_records;
9873
/// \brief Number of records removed in this commit.
99-
CounterResult removed_records;
74+
std::optional<CounterResult> removed_records;
10075
/// \brief Total live records after this commit.
101-
CounterResult total_records;
76+
std::optional<CounterResult> total_records;
10277
/// \brief Total byte size of files added.
103-
CounterResult added_files_size_bytes;
78+
std::optional<CounterResult> added_files_size_bytes;
10479
/// \brief Total byte size of files removed.
105-
CounterResult removed_files_size_bytes;
80+
std::optional<CounterResult> removed_files_size_bytes;
10681
/// \brief Total byte size of all live files after this commit.
107-
CounterResult total_files_size_bytes;
82+
std::optional<CounterResult> total_files_size_bytes;
10883
/// \brief Positional delete records added.
109-
CounterResult added_positional_deletes;
84+
std::optional<CounterResult> added_positional_deletes;
11085
/// \brief Positional delete records removed.
111-
CounterResult removed_positional_deletes;
86+
std::optional<CounterResult> removed_positional_deletes;
11287
/// \brief Total positional delete records after this commit.
113-
CounterResult total_positional_deletes;
88+
std::optional<CounterResult> total_positional_deletes;
11489
/// \brief Equality delete records added.
115-
CounterResult added_equality_deletes;
90+
std::optional<CounterResult> added_equality_deletes;
11691
/// \brief Equality delete records removed.
117-
CounterResult removed_equality_deletes;
92+
std::optional<CounterResult> removed_equality_deletes;
11893
/// \brief Total equality delete records after this commit.
119-
CounterResult total_equality_deletes;
94+
std::optional<CounterResult> total_equality_deletes;
12095
/// \brief Manifest files kept unchanged in this commit.
121-
CounterResult kept_manifest_count;
96+
std::optional<CounterResult> kept_manifest_count;
12297
/// \brief Manifest files created in this commit.
123-
CounterResult created_manifest_count;
98+
std::optional<CounterResult> created_manifest_count;
12499
/// \brief Manifest files replaced in this commit.
125-
CounterResult replaced_manifest_count;
100+
std::optional<CounterResult> replaced_manifest_count;
126101
/// \brief Manifest entries processed in this commit.
127-
CounterResult processed_manifest_entries_count;
102+
std::optional<CounterResult> processed_manifest_entries_count;
128103

129104
bool operator==(const CommitMetricsResult&) const = default;
130105

131106
/// \brief Build a CommitMetricsResult from live metrics and a snapshot summary map.
132107
///
133108
/// Combines timer/retry measurements from \p live_metrics with records parsed
134-
/// from \p snapshot_summary. Missing or unparseable summary keys default to 0.
109+
/// from \p snapshot_summary. Missing or unparseable summary keys are omitted.
135110
static CommitMetricsResult From(
136111
const CommitMetrics& live_metrics,
137112
const std::unordered_map<std::string, std::string>& snapshot_summary);
138113
};
139114

115+
/// \brief Live commit metrics collected during a table commit operation.
116+
///
117+
/// Tracks the overall commit duration and retry count. File/record counts come
118+
/// from the snapshot summary after the commit succeeds and are stored separately
119+
/// in CommitMetricsResult.
120+
class ICEBERG_EXPORT CommitMetrics {
121+
public:
122+
/// \brief Create a CommitMetrics instance backed by the given MetricsContext.
123+
static std::unique_ptr<CommitMetrics> Make(MetricsContext& context);
124+
125+
/// \brief Create a CommitMetrics instance with all-noop timer and counter.
126+
static std::unique_ptr<CommitMetrics> Noop();
127+
128+
/// \brief Snapshot current timer and counter values into a CommitMetricsResult.
129+
CommitMetricsResult ToResult() const;
130+
131+
/// \brief Timer measuring total wall-clock time of the commit call.
132+
std::shared_ptr<Timer> total_duration;
133+
134+
/// \brief Counter for the number of commit attempts (including retries).
135+
std::shared_ptr<Counter> attempts;
136+
137+
private:
138+
CommitMetrics() = default;
139+
};
140+
140141
/// \brief Report generated after a commit operation.
141142
///
142143
/// Contains metrics about the changes made in a commit.

src/iceberg/metrics/counter.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ class NoopCounter final : public Counter {
2929
public:
3030
using Counter::Increment;
3131
void Increment(int64_t) override {}
32-
int64_t value() const override { return 0; }
32+
int64_t value() const override { return -1; }
33+
CounterUnit unit() const override { return CounterUnit::kUndefined; }
3334
bool IsNoop() const override { return true; }
3435
};
3536

src/iceberg/metrics/counter.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#include <utility>
2727

2828
#include "iceberg/iceberg_export.h"
29+
#include "iceberg/result.h"
30+
#include "iceberg/util/string_util.h"
2931

3032
namespace iceberg {
3133

@@ -52,11 +54,13 @@ ICEBERG_EXPORT constexpr std::string_view ToString(CounterUnit unit) noexcept {
5254
/// \brief Parse a CounterUnit from a string.
5355
///
5456
/// \param s The string to parse ("count", "bytes", or "undefined").
55-
/// \return The CounterUnit, or CounterUnit::kCount if unrecognized.
56-
ICEBERG_EXPORT constexpr CounterUnit CounterUnitFromString(std::string_view s) noexcept {
57-
if (s == "bytes") return CounterUnit::kBytes;
58-
if (s == "undefined") return CounterUnit::kUndefined;
59-
return CounterUnit::kCount;
57+
/// \return The CounterUnit, or an InvalidArgument error if unrecognized.
58+
ICEBERG_EXPORT inline Result<CounterUnit> CounterUnitFromString(std::string_view s) {
59+
auto unit = StringUtils::ToLower(s);
60+
if (unit == "count") return CounterUnit::kCount;
61+
if (unit == "bytes") return CounterUnit::kBytes;
62+
if (unit == "undefined") return CounterUnit::kUndefined;
63+
return InvalidArgument("Invalid unit: {}", s);
6064
}
6165

6266
/// \brief Abstract counter for tracking event totals.

0 commit comments

Comments
 (0)