Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ public static MetricSnapshots mergeDuplicates(MetricSnapshots metricSnapshots) {
return metricSnapshots;
}

// MetricSnapshots is sorted by prometheus name, so any duplicates are adjacent. Detect them in

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overall this change and associated benchmarks look good. I'd like to see a few extra tests added though.

All four of the existing mergeDuplicates tests either exercise the merge path or pass any empty snapshots list. An inverted condition or i=0 start would not be caught by the existing tests. Can we add cases for:

  • unique names → assertThat(TextFormatUtil.mergeDuplicates(s)).isSameAs(s)
  • a mixed case where the duplicate pair is not at index 0/1 (e.g. a, m, z, z) → still merged, which pins the loop range.

Also, the sorted invariant is cross-module and nothing pins the sort key, and the fast path is only correct while MetricSnapshots sorts by getPrometheusName().

MetricSnapshotsTest.testSort asserts order via getMetadata().getName() using names where name, prometheusName and expositionBaseName all coincide so it would keep passing if the sort key moved to name or expositionBaseName. If that happens, mergeDuplicates silently stops merging and the writers emit repeated # HELP/# TYPE blocks for one family.

we could add some tests around this:

  • a test in MetricSnapshotsTest that pins ordering by getPrometheusName() with names where the three differ (e.g. my.metric vs my_metric_b, or a _total-suffixed counter);
  • a comment on the sort in MetricSnapshots naming TextFormatUtil.mergeDuplicates as a
    dependant, so the next person to touch the comparator sees it.

// a single allocation-free pass; when there are none (the common case) return the input as-is
// rather than rebuilding it through a map, a list per group and a new MetricSnapshots.
boolean hasDuplicates = false;
for (int i = 1; i < metricSnapshots.size(); i++) {
if (metricSnapshots
.get(i)
.getMetadata()
.getPrometheusName()
.equals(metricSnapshots.get(i - 1).getMetadata().getPrometheusName())) {
hasDuplicates = true;
break;
}
}
if (!hasDuplicates) {
return metricSnapshots;
}

Map<String, List<MetricSnapshot>> grouped = new LinkedHashMap<>();

for (MetricSnapshot snapshot : metricSnapshots) {
Expand Down
Loading