From 7502d59c4f01f9421689b429b73626b71d8eec06 Mon Sep 17 00:00:00 2001 From: Zach Stone Date: Mon, 28 Mar 2022 16:09:45 +0200 Subject: [PATCH 1/2] Try using curry values --- prometheus/vec.go | 86 +++++++++++------------------------------- prometheus/vec_test.go | 60 ++++++++--------------------- 2 files changed, 39 insertions(+), 107 deletions(-) diff --git a/prometheus/vec.go b/prometheus/vec.go index 3d5f79793..40b9ccdd1 100644 --- a/prometheus/vec.go +++ b/prometheus/vec.go @@ -80,16 +80,6 @@ func (m *MetricVec) DeleteLabelValues(lvs ...string) bool { return m.metricMap.deleteByHashWithLabelValues(h, lvs, m.curry) } -// DeletePartialMatchLabelValues deletes all metrics where the variable labels -// contain all of the values passed. The order of the passed values does not matter. -// It returns the number of metrics deleted. - -// This method deletes a metric if the given value is present for any label. -// To delete a metric based on a partial match for a particular label, use DeletePartialMatch(). -func (m *MetricVec) DeletePartialMatchLabelValues(lvs ...string) int { - return m.metricMap.deleteByLabelValues(lvs) -} - // Delete deletes the metric where the variable labels are the same as those // passed in as labels. It returns true if a metric was deleted. // @@ -116,7 +106,7 @@ func (m *MetricVec) Delete(labels Labels) bool { // This method deletes a metric if the given label: value pair is found in that metric. // To delete a metric if a particular value is found associated with any label, use DeletePartialMatchLabelValues(). func (m *MetricVec) DeletePartialMatch(labels Labels) int { - return m.metricMap.deleteByLabels(labels) + return m.metricMap.deleteByLabels(labels, m.curry) } // Without explicit forwarding of Describe, Collect, Reset, those methods won't @@ -373,51 +363,6 @@ func (m *metricMap) deleteByHashWithLabelValues( return true } -// deleteByLabelValues deletes a metric if the given values (lvs) are present in the metric. -func (m *metricMap) deleteByLabelValues(lvs []string) int { - m.mtx.Lock() - defer m.mtx.Unlock() - - var numDeleted int - - for h, metrics := range m.metrics { - i := findMetricWithPartialLabelValues(metrics, lvs) - if i >= len(metrics) { - // Didn't find matching label values in this metric slice. - continue - } - delete(m.metrics, h) - numDeleted++ - } - - return numDeleted -} - -// findMetricWithPartialLabelValues returns the index of the matching metric or -// len(metrics) if not found. -func findMetricWithPartialLabelValues( - metrics []metricWithLabelValues, lvs []string, -) int { - for i, metric := range metrics { - if matchPartialLabelValues(metric.values, lvs) { - return i - } - } - return len(metrics) -} - -// matchPartialLabelValues searches the current metric values and returns whether all of the target values are present. -func matchPartialLabelValues(values []string, lvs []string) bool { - for _, v := range lvs { - // Check if the target value exists in our metrics and get the index. - if _, validValue := indexOf(v, values); validValue { - continue - } - return false - } - return true -} - // deleteByHashWithLabels removes the metric from the hash bucket h. If there // are multiple matches in the bucket, use lvs to select a metric and remove // only that metric. @@ -447,14 +392,14 @@ func (m *metricMap) deleteByHashWithLabels( } // deleteByLabels deletes a metric if the given labels are present in the metric. -func (m *metricMap) deleteByLabels(labels Labels) int { +func (m *metricMap) deleteByLabels(labels Labels, curry []curriedLabelValue) int { m.mtx.Lock() defer m.mtx.Unlock() var numDeleted int for h, metrics := range m.metrics { - i := findMetricWithPartialLabels(m.desc, metrics, labels) + i := findMetricWithPartialLabels(m.desc, metrics, labels, curry) if i >= len(metrics) { // Didn't find matching labels in this metric slice. continue @@ -469,10 +414,10 @@ func (m *metricMap) deleteByLabels(labels Labels) int { // findMetricWithPartialLabel returns the index of the matching metric or // len(metrics) if not found. func findMetricWithPartialLabels( - desc *Desc, metrics []metricWithLabelValues, labels Labels, + desc *Desc, metrics []metricWithLabelValues, labels Labels, curry []curriedLabelValue, ) int { for i, metric := range metrics { - if matchPartialLabels(desc, metric.values, labels) { + if matchPartialLabels(desc, metric.values, labels, curry) { return i } } @@ -490,17 +435,32 @@ func indexOf(target string, items []string) (int, bool) { return len(items), false } +// valueOrCurriedValue determines if a value was previously curried, +// and returns either the "base" value or the curried value accordingly. +func valueOrCurriedValue(index int, values []string, curry []curriedLabelValue) string { + for _, curriedValue := range curry { + if curriedValue.index == index { + return curriedValue.value + } + } + return values[index] +} + // matchPartialLabels searches the current metric and returns whether all of the target label:value pairs are present. -func matchPartialLabels(desc *Desc, values []string, labels Labels) bool { +func matchPartialLabels(desc *Desc, values []string, labels Labels, curry []curriedLabelValue) bool { for l, v := range labels { // Check if the target label exists in our metrics and get the index. varLabelIndex, validLabel := indexOf(l, desc.variableLabels) if validLabel { // Check the value of that label against the target value. - if values[varLabelIndex] == v { + if valueOrCurriedValue(varLabelIndex, values, curry) == v { continue - } + + // if values[varLabelIndex] == v { + // continue + + // } } return false } diff --git a/prometheus/vec_test.go b/prometheus/vec_test.go index 67c4f60ea..05a11d723 100644 --- a/prometheus/vec_test.go +++ b/prometheus/vec_test.go @@ -164,10 +164,17 @@ func testDeletePartialMatch(t *testing.T, vec *GaugeVec) { // Try to delete with a single valid label which matches multiple metrics. vec.With(Labels{"l1": "v1", "l2": "v2"}).(Gauge).Set(42) vec.With(Labels{"l1": "v1", "l2": "vv22"}).(Gauge).Set(84) + c3 := vec.MustCurryWith(Labels{"l2": "l2C3CurriedValue"}) // Used below + vec.With(Labels{"l1": "v3", "l2": "v3"}).(Gauge).Set(168) if got, want := vec.DeletePartialMatch(Labels{"l1": "v1"}), 2; got != want { t.Errorf("got %v, want %v", got, want) } + // Try to delete a value which shouldn't be in our base vector (only the curried one c3). + if got, want := vec.DeletePartialMatch(Labels{"l2": "l2C3CurriedValue"}), 0; got != want { + t.Errorf("got %v, want %v", got, want) + } + c2 := vec.MustCurryWith(Labels{"l2": "l2CurriedValue"}) c2.With(Labels{"l1": "11"}).Inc() @@ -175,60 +182,25 @@ func testDeletePartialMatch(t *testing.T, vec *GaugeVec) { if got, want := c2.DeletePartialMatch(Labels{"l2": "l2CurriedValue"}), 1; got != want { t.Errorf("got %v, want %v", got, want) } - - // Same labels, value matches. - vec.With(Labels{"l1": "v1", "l2": "v2"}).(Gauge).Set(42) - if got, want := vec.DeletePartialMatch(Labels{"l1": "v1"}), 1; got != want { + // Try to delete with a label value from before currying. + if got, want := c2.DeletePartialMatch(Labels{"l2": "v3"}), 0; got != want { t.Errorf("got %v, want %v", got, want) } -} - -func TestDeletePartialMatchLabelValues(t *testing.T) { - vec := NewGaugeVec( - GaugeOpts{ - Name: "test", - Help: "helpless", - }, - []string{"l1", "l2"}, - ) - testDeletePartialMatchLabelValues(t, vec) -} -func testDeletePartialMatchLabelValues(t *testing.T, vec *GaugeVec) { - // No metric value is set. - if got, want := vec.DeletePartialMatchLabelValues("v1", "v2"), 0; got != want { - t.Errorf("got %v, want %v", got, want) - } + c3.With(Labels{"l1": "11"}).Inc() - // Try to delete with a single valid value. - vec.With(Labels{"l1": "v1", "l2": "v2"}).(Gauge).Set(42) - if got, want := vec.DeletePartialMatchLabelValues("v1"), 1; got != want { + // Try to delete with invalid curried pair l1: v1. + if got, want := c3.DeletePartialMatch(Labels{"l1": "v1"}), 0; got != want { t.Errorf("got %v, want %v", got, want) } - - // Try to delete with partially invalid values. - vec.With(Labels{"l1": "v1", "l2": "v2"}).(Gauge).Set(42) - if got, want := vec.DeletePartialMatchLabelValues("v1", "xv2"), 0; got != want { + // Delete valid curried pair l2: l2C3CurriedValue. + if got, want := c3.DeletePartialMatch(Labels{"l2": "l2C3CurriedValue"}), 1; got != want { t.Errorf("got %v, want %v", got, want) } - // Try to delete with a single valid value which matches multiple metrics. + // Same labels, value matches. vec.With(Labels{"l1": "v1", "l2": "v2"}).(Gauge).Set(42) - vec.With(Labels{"l1": "v1", "l2": "vv22"}).(Gauge).Set(84) - if got, want := vec.DeletePartialMatchLabelValues("v1"), 2; got != want { - t.Errorf("got %v, want %v", got, want) - } - - c1 := vec.MustCurryWith(Labels{"l1": "cv1"}) - c1.WithLabelValues("2").Inc() - - // Try to delete with nonexistent value z1. - if got, want := c1.DeletePartialMatchLabelValues("z1"), 0; got != want { - t.Errorf("got %v, want %v", got, want) - } - - // Delete with valid curried value cv1. - if got, want := c1.DeletePartialMatchLabelValues("cv1"), 1; got != want { + if got, want := vec.DeletePartialMatch(Labels{"l1": "v1"}), 1; got != want { t.Errorf("got %v, want %v", got, want) } } From a3a1a5858322d99af077cdcf572fc9dfc359e19d Mon Sep 17 00:00:00 2001 From: Zach Stone Date: Mon, 28 Mar 2022 16:29:25 +0200 Subject: [PATCH 2/2] Skip curry value to demo Signed-off-by: Zach Stone --- prometheus/vec.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/prometheus/vec.go b/prometheus/vec.go index 40b9ccdd1..6ac722ca9 100644 --- a/prometheus/vec.go +++ b/prometheus/vec.go @@ -453,14 +453,14 @@ func matchPartialLabels(desc *Desc, values []string, labels Labels, curry []curr varLabelIndex, validLabel := indexOf(l, desc.variableLabels) if validLabel { // Check the value of that label against the target value. - if valueOrCurriedValue(varLabelIndex, values, curry) == v { - continue - } - - // if values[varLabelIndex] == v { + // if valueOrCurriedValue(varLabelIndex, values, curry) == v { // continue - // } + + if values[varLabelIndex] == v { + continue + + } } return false }