Skip to content

Commit 3c1fbfb

Browse files
authored
Merge pull request #513 from prometheus/beorn7/registry
Fix the race in the registry
2 parents 2df5ba3 + 619eb59 commit 3c1fbfb

File tree

2 files changed

+22
-10
lines changed

2 files changed

+22
-10
lines changed

prometheus/registry.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,13 @@ func checkMetricConsistency(
872872
h = hashAddByte(h, separatorByte)
873873
// Make sure label pairs are sorted. We depend on it for the consistency
874874
// check.
875-
sort.Sort(labelPairSorter(dtoMetric.Label))
875+
if !sort.IsSorted(labelPairSorter(dtoMetric.Label)) {
876+
// We cannot sort dtoMetric.Label in place as it is immutable by contract.
877+
copiedLabels := make([]*dto.LabelPair, len(dtoMetric.Label))
878+
copy(copiedLabels, dtoMetric.Label)
879+
sort.Sort(labelPairSorter(copiedLabels))
880+
dtoMetric.Label = copiedLabels
881+
}
876882
for _, lp := range dtoMetric.Label {
877883
h = hashAdd(h, lp.GetName())
878884
h = hashAddByte(h, separatorByte)
@@ -903,8 +909,8 @@ func checkDescConsistency(
903909
}
904910

905911
// Is the desc consistent with the content of the metric?
906-
lpsFromDesc := make([]*dto.LabelPair, 0, len(dtoMetric.Label))
907-
lpsFromDesc = append(lpsFromDesc, desc.constLabelPairs...)
912+
lpsFromDesc := make([]*dto.LabelPair, len(desc.constLabelPairs), len(dtoMetric.Label))
913+
copy(lpsFromDesc, desc.constLabelPairs)
908914
for _, l := range desc.variableLabels {
909915
lpsFromDesc = append(lpsFromDesc, &dto.LabelPair{
910916
Name: proto.String(l),

prometheus/registry_test.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ package prometheus_test
2121

2222
import (
2323
"bytes"
24+
"fmt"
2425
"io/ioutil"
2526
"math/rand"
2627
"net/http"
@@ -783,6 +784,11 @@ func TestAlreadyRegistered(t *testing.T) {
783784
// same HistogramVec is registered concurrently and the Gather method of the
784785
// registry is called concurrently.
785786
func TestHistogramVecRegisterGatherConcurrency(t *testing.T) {
787+
labelNames := make([]string, 16) // Need at least 13 to expose #512.
788+
for i := range labelNames {
789+
labelNames[i] = fmt.Sprint("label_", i)
790+
}
791+
786792
var (
787793
reg = prometheus.NewPedanticRegistry()
788794
hv = prometheus.NewHistogramVec(
@@ -791,7 +797,7 @@ func TestHistogramVecRegisterGatherConcurrency(t *testing.T) {
791797
Help: "This helps testing.",
792798
ConstLabels: prometheus.Labels{"foo": "bar"},
793799
},
794-
[]string{"one", "two", "three"},
800+
labelNames,
795801
)
796802
labelValues = []string{"a", "b", "c", "alpha", "beta", "gamma", "aleph", "beth", "gimel"}
797803
quit = make(chan struct{})
@@ -806,11 +812,11 @@ func TestHistogramVecRegisterGatherConcurrency(t *testing.T) {
806812
return
807813
default:
808814
obs := rand.NormFloat64()*.1 + .2
809-
hv.WithLabelValues(
810-
labelValues[rand.Intn(len(labelValues))],
811-
labelValues[rand.Intn(len(labelValues))],
812-
labelValues[rand.Intn(len(labelValues))],
813-
).Observe(obs)
815+
values := make([]string, 0, len(labelNames))
816+
for range labelNames {
817+
values = append(values, labelValues[rand.Intn(len(labelValues))])
818+
}
819+
hv.WithLabelValues(values...).Observe(obs)
814820
}
815821
}
816822
}
@@ -848,7 +854,7 @@ func TestHistogramVecRegisterGatherConcurrency(t *testing.T) {
848854
if len(g) != 1 {
849855
t.Error("Gathered unexpected number of metric families:", len(g))
850856
}
851-
if len(g[0].Metric[0].Label) != 4 {
857+
if len(g[0].Metric[0].Label) != len(labelNames)+1 {
852858
t.Error("Gathered unexpected number of label pairs:", len(g[0].Metric[0].Label))
853859
}
854860
}

0 commit comments

Comments
 (0)