Skip to content

Commit b13dc04

Browse files
committed
aggmetric: add clear method in ChildStorage
This patch introduces `clear` method in ChildStorage. It will clear all children which are part of parent metric. This method will be used during reinitialisation of aggmetric on cluster setting changes. Epic: CRDB-43153 Part of: CRDB-48253 Release note: None
1 parent a0df03c commit b13dc04

File tree

6 files changed

+118
-36
lines changed

6 files changed

+118
-36
lines changed

pkg/util/metric/aggmetric/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ go_test(
4646
"@com_github_cockroachdb_crlib//testutils/require",
4747
"@com_github_prometheus_client_model//go",
4848
"@com_github_prometheus_common//expfmt",
49+
"@com_github_stretchr_testify//assert",
4950
"@com_github_stretchr_testify//require",
5051
],
5152
)

pkg/util/metric/aggmetric/agg_metric.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,16 @@ func (cs *childSet) get(labelVals ...string) (ChildMetric, bool) {
149149
return cs.mu.children.Get(labelVals...)
150150
}
151151

152+
// clear method removes all children from the childSet. It does not reset parent metric values.
153+
// Method should cautiously be used when childSet is reinitialised/updated. Today, it is
154+
// only used when cluster settings are updated to support app and db label values. For normal
155+
// operations, please use add, remove and get method to update the childSet.
156+
func (cs *childSet) clear() {
157+
cs.mu.Lock()
158+
defer cs.mu.Unlock()
159+
cs.mu.children.Clear()
160+
}
161+
152162
type MetricItem interface {
153163
labelValuer
154164
}
@@ -185,6 +195,7 @@ type ChildrenStorage interface {
185195
Del(key ChildMetric)
186196
Do(f func(e interface{}))
187197
GetChildMetric(e interface{}) ChildMetric
198+
Clear()
188199
}
189200

190201
var _ ChildrenStorage = &UnorderedCacheWrapper{}
@@ -229,6 +240,10 @@ func (ucw *UnorderedCacheWrapper) Do(f func(e interface{})) {
229240
})
230241
}
231242

243+
func (ucw *UnorderedCacheWrapper) Clear() {
244+
ucw.cache.Clear()
245+
}
246+
232247
type BtreeWrapper struct {
233248
tree *btree.BTree
234249
}
@@ -267,6 +282,10 @@ func (b BtreeWrapper) GetChildMetric(e interface{}) ChildMetric {
267282
return e.(ChildMetric)
268283
}
269284

285+
func (b BtreeWrapper) Clear() {
286+
b.tree.Clear(false)
287+
}
288+
270289
func (lv *labelValuesSlice) Less(o btree.Item) bool {
271290
ov := o.(labelValuer).labelValues()
272291
if len(ov) != len(*lv) {

pkg/util/metric/aggmetric/agg_metric_test.go

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -71,22 +71,7 @@ func TestAggMetric(t *testing.T) {
7171
defer leaktest.AfterTest(t)()
7272

7373
r := metric.NewRegistry()
74-
writePrometheusMetrics := func(t *testing.T) string {
75-
var in bytes.Buffer
76-
ex := metric.MakePrometheusExporter()
77-
scrape := func(ex *metric.PrometheusExporter) {
78-
ex.ScrapeRegistry(r, true /* includeChildMetrics */, true)
79-
}
80-
require.NoError(t, ex.ScrapeAndPrintAsText(&in, expfmt.FmtText, scrape))
81-
var lines []string
82-
for sc := bufio.NewScanner(&in); sc.Scan(); {
83-
if !bytes.HasPrefix(sc.Bytes(), []byte{'#'}) {
84-
lines = append(lines, sc.Text())
85-
}
86-
}
87-
sort.Strings(lines)
88-
return strings.Join(lines, "\n")
89-
}
74+
writePrometheusMetrics := WritePrometheusMetricsFunc(r)
9075

9176
c := NewCounter(metric.Metadata{
9277
Name: "foo_counter",
@@ -296,3 +281,59 @@ func TestAggHistogramRotate(t *testing.T) {
296281
// Go to beginning.
297282
}
298283
}
284+
285+
func TestAggMetricClear(t *testing.T) {
286+
defer leaktest.AfterTest(t)()
287+
288+
r := metric.NewRegistry()
289+
writePrometheusMetrics := WritePrometheusMetricsFunc(r)
290+
291+
c := NewCounter(metric.Metadata{
292+
Name: "foo_counter",
293+
}, "tenant_id")
294+
r.AddMetric(c)
295+
296+
d := NewCounter(metric.Metadata{
297+
Name: "bar_counter",
298+
}, "tenant_id")
299+
d.initWithCacheStorageType([]string{"tenant_id"})
300+
r.AddMetric(d)
301+
302+
tenant2 := roachpb.MustMakeTenantID(2)
303+
c1 := c.AddChild(tenant2.String())
304+
305+
t.Run("before clear", func(t *testing.T) {
306+
c1.Inc(2)
307+
d.Inc(2, "3")
308+
testFile := "aggMetric_pre_clear.txt"
309+
echotest.Require(t, writePrometheusMetrics(t), datapathutils.TestDataPath(t, testFile))
310+
})
311+
312+
c.clear()
313+
d.clear()
314+
315+
t.Run("post clear", func(t *testing.T) {
316+
testFile := "aggMetric_post_clear.txt"
317+
echotest.Require(t, writePrometheusMetrics(t), datapathutils.TestDataPath(t, testFile))
318+
})
319+
}
320+
321+
func WritePrometheusMetricsFunc(r *metric.Registry) func(t *testing.T) string {
322+
writePrometheusMetrics := func(t *testing.T) string {
323+
var in bytes.Buffer
324+
ex := metric.MakePrometheusExporter()
325+
scrape := func(ex *metric.PrometheusExporter) {
326+
ex.ScrapeRegistry(r, true /* includeChildMetrics */, true)
327+
}
328+
require.NoError(t, ex.ScrapeAndPrintAsText(&in, expfmt.FmtText, scrape))
329+
var lines []string
330+
for sc := bufio.NewScanner(&in); sc.Scan(); {
331+
if !bytes.HasPrefix(sc.Bytes(), []byte{'#'}) {
332+
lines = append(lines, sc.Text())
333+
}
334+
}
335+
sort.Strings(lines)
336+
return strings.Join(lines, "\n")
337+
}
338+
return writePrometheusMetrics
339+
}

pkg/util/metric/aggmetric/gauge_test.go

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ import (
2020
"github.com/cockroachdb/cockroach/pkg/util/metric"
2121
"github.com/cockroachdb/crlib/testutils/require"
2222
"github.com/prometheus/common/expfmt"
23+
"github.com/stretchr/testify/assert"
2324
)
2425

2526
func TestAggGaugeEviction(t *testing.T) {
2627
defer leaktest.AfterTest(t)()
2728
const cacheSize = 10
2829
r := metric.NewRegistry()
29-
writePrometheusMetrics := writePrometheusMetricsFunc(r)
30+
writePrometheusMetrics := WritePrometheusMetricsFunc(r)
3031

3132
g := NewGauge(metric.Metadata{
3233
Name: "foo_gauge",
@@ -101,11 +102,30 @@ func TestAggGaugeMethods(t *testing.T) {
101102
echotest.Require(t, writePrometheusMetrics(t), datapathutils.TestDataPath(t, testFile))
102103
}
103104

105+
func TestPanicForAggGaugeWithBtreeStorage(t *testing.T) {
106+
defer leaktest.AfterTest(t)()
107+
g := NewGauge(metric.Metadata{
108+
Name: "foo_gauge",
109+
}, "tenant_id")
110+
111+
assert.Panics(t, func() {
112+
g.Inc(1, "1", "1")
113+
}, "expected panic when Inc is invoked on AggGauge with BTreeStorage")
114+
115+
assert.Panics(t, func() {
116+
g.Dec(1, "1", "1")
117+
}, "expected panic when Dec is invoked on AggGauge with BTreeStorage")
118+
119+
assert.Panics(t, func() {
120+
g.Update(1, "1", "1")
121+
}, "expected panic when Update is invoked on AggGauge with BTreeStorage")
122+
}
123+
104124
func TestAggGaugeFloat64Eviction(t *testing.T) {
105125
defer leaktest.AfterTest(t)()
106126
const cacheSize = 10
107127
r := metric.NewRegistry()
108-
writePrometheusMetrics := writePrometheusMetricsFunc(r)
128+
writePrometheusMetrics := WritePrometheusMetricsFunc(r)
109129

110130
g := NewGaugeFloat64(metric.Metadata{
111131
Name: "foo_gauge_float64",
@@ -136,22 +156,13 @@ func TestAggGaugeFloat64Eviction(t *testing.T) {
136156
echotest.Require(t, writePrometheusMetrics(t), datapathutils.TestDataPath(t, testFile))
137157
}
138158

139-
func writePrometheusMetricsFunc(r *metric.Registry) func(t *testing.T) string {
140-
writePrometheusMetrics := func(t *testing.T) string {
141-
var in bytes.Buffer
142-
ex := metric.MakePrometheusExporter()
143-
scrape := func(ex *metric.PrometheusExporter) {
144-
ex.ScrapeRegistry(r, true /* includeChildMetrics */, true)
145-
}
146-
require.NoError(t, ex.ScrapeAndPrintAsText(&in, expfmt.FmtText, scrape))
147-
var lines []string
148-
for sc := bufio.NewScanner(&in); sc.Scan(); {
149-
if !bytes.HasPrefix(sc.Bytes(), []byte{'#'}) {
150-
lines = append(lines, sc.Text())
151-
}
152-
}
153-
sort.Strings(lines)
154-
return strings.Join(lines, "\n")
155-
}
156-
return writePrometheusMetrics
159+
func TestPanicForAggGaugeFloat64WithBtreeStorage(t *testing.T) {
160+
defer leaktest.AfterTest(t)()
161+
g := NewGaugeFloat64(metric.Metadata{
162+
Name: "foo_gauge",
163+
}, "tenant_id")
164+
165+
assert.Panics(t, func() {
166+
g.Update(1, "1", "1")
167+
}, "expected panic when Update is invoked on AggGaugeFloat64 with BTreeStorage")
157168
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
echo
2+
----
3+
bar_counter 2
4+
foo_counter 2
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
echo
2+
----
3+
bar_counter 2
4+
bar_counter{tenant_id="3"} 2
5+
foo_counter 2
6+
foo_counter{tenant_id="2"} 2

0 commit comments

Comments
 (0)