mirror of
https://github.com/prometheus/prometheus.git
synced 2025-02-02 08:31:11 -08:00
storage/remote: speed up StoreSeries by re-using labels.Builder
Relabeling can take a pre-populated `Builder` instead of making a new one every time. This is much more efficient. Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
This commit is contained in:
parent
d9483bb77c
commit
dcd024a095
|
@ -413,9 +413,10 @@ type QueueManager struct {
|
||||||
clientMtx sync.RWMutex
|
clientMtx sync.RWMutex
|
||||||
storeClient WriteClient
|
storeClient WriteClient
|
||||||
|
|
||||||
seriesMtx sync.Mutex // Covers seriesLabels and droppedSeries.
|
seriesMtx sync.Mutex // Covers seriesLabels, droppedSeries and builder.
|
||||||
seriesLabels map[chunks.HeadSeriesRef]labels.Labels
|
seriesLabels map[chunks.HeadSeriesRef]labels.Labels
|
||||||
droppedSeries map[chunks.HeadSeriesRef]struct{}
|
droppedSeries map[chunks.HeadSeriesRef]struct{}
|
||||||
|
builder *labels.Builder
|
||||||
|
|
||||||
seriesSegmentMtx sync.Mutex // Covers seriesSegmentIndexes - if you also lock seriesMtx, take seriesMtx first.
|
seriesSegmentMtx sync.Mutex // Covers seriesSegmentIndexes - if you also lock seriesMtx, take seriesMtx first.
|
||||||
seriesSegmentIndexes map[chunks.HeadSeriesRef]int
|
seriesSegmentIndexes map[chunks.HeadSeriesRef]int
|
||||||
|
@ -482,6 +483,7 @@ func NewQueueManager(
|
||||||
seriesLabels: make(map[chunks.HeadSeriesRef]labels.Labels),
|
seriesLabels: make(map[chunks.HeadSeriesRef]labels.Labels),
|
||||||
seriesSegmentIndexes: make(map[chunks.HeadSeriesRef]int),
|
seriesSegmentIndexes: make(map[chunks.HeadSeriesRef]int),
|
||||||
droppedSeries: make(map[chunks.HeadSeriesRef]struct{}),
|
droppedSeries: make(map[chunks.HeadSeriesRef]struct{}),
|
||||||
|
builder: labels.NewBuilder(labels.EmptyLabels()),
|
||||||
|
|
||||||
numShards: cfg.MinShards,
|
numShards: cfg.MinShards,
|
||||||
reshardChan: make(chan int),
|
reshardChan: make(chan int),
|
||||||
|
@ -897,12 +899,14 @@ func (t *QueueManager) StoreSeries(series []record.RefSeries, index int) {
|
||||||
// Just make sure all the Refs of Series will insert into seriesSegmentIndexes map for tracking.
|
// Just make sure all the Refs of Series will insert into seriesSegmentIndexes map for tracking.
|
||||||
t.seriesSegmentIndexes[s.Ref] = index
|
t.seriesSegmentIndexes[s.Ref] = index
|
||||||
|
|
||||||
ls := processExternalLabels(s.Labels, t.externalLabels)
|
t.builder.Reset(s.Labels)
|
||||||
lbls, keep := relabel.Process(ls, t.relabelConfigs...)
|
processExternalLabels(t.builder, t.externalLabels)
|
||||||
if !keep || lbls.IsEmpty() {
|
keep := relabel.ProcessBuilder(t.builder, t.relabelConfigs...)
|
||||||
|
if !keep {
|
||||||
t.droppedSeries[s.Ref] = struct{}{}
|
t.droppedSeries[s.Ref] = struct{}{}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
lbls := t.builder.Labels()
|
||||||
t.internLabels(lbls)
|
t.internLabels(lbls)
|
||||||
|
|
||||||
// We should not ever be replacing a series labels in the map, but just
|
// We should not ever be replacing a series labels in the map, but just
|
||||||
|
@ -967,30 +971,14 @@ func (t *QueueManager) releaseLabels(ls labels.Labels) {
|
||||||
ls.ReleaseStrings(t.interner.release)
|
ls.ReleaseStrings(t.interner.release)
|
||||||
}
|
}
|
||||||
|
|
||||||
// processExternalLabels merges externalLabels into ls. If ls contains
|
// processExternalLabels merges externalLabels into b. If b contains
|
||||||
// a label in externalLabels, the value in ls wins.
|
// a label in externalLabels, the value in b wins.
|
||||||
func processExternalLabels(ls labels.Labels, externalLabels []labels.Label) labels.Labels {
|
func processExternalLabels(b *labels.Builder, externalLabels []labels.Label) {
|
||||||
if len(externalLabels) == 0 {
|
for _, el := range externalLabels {
|
||||||
return ls
|
if b.Get(el.Name) == "" {
|
||||||
}
|
b.Set(el.Name, el.Value)
|
||||||
|
|
||||||
b := labels.NewScratchBuilder(ls.Len() + len(externalLabels))
|
|
||||||
j := 0
|
|
||||||
ls.Range(func(l labels.Label) {
|
|
||||||
for j < len(externalLabels) && l.Name > externalLabels[j].Name {
|
|
||||||
b.Add(externalLabels[j].Name, externalLabels[j].Value)
|
|
||||||
j++
|
|
||||||
}
|
}
|
||||||
if j < len(externalLabels) && l.Name == externalLabels[j].Name {
|
|
||||||
j++
|
|
||||||
}
|
|
||||||
b.Add(l.Name, l.Value)
|
|
||||||
})
|
|
||||||
for ; j < len(externalLabels); j++ {
|
|
||||||
b.Add(externalLabels[j].Name, externalLabels[j].Value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.Labels()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *QueueManager) updateShardsLoop() {
|
func (t *QueueManager) updateShardsLoop() {
|
||||||
|
|
|
@ -1013,7 +1013,8 @@ func BenchmarkStartup(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessExternalLabels(t *testing.T) {
|
func TestProcessExternalLabels(t *testing.T) {
|
||||||
for _, tc := range []struct {
|
b := labels.NewBuilder(labels.EmptyLabels())
|
||||||
|
for i, tc := range []struct {
|
||||||
labels labels.Labels
|
labels labels.Labels
|
||||||
externalLabels []labels.Label
|
externalLabels []labels.Label
|
||||||
expected labels.Labels
|
expected labels.Labels
|
||||||
|
@ -1074,7 +1075,9 @@ func TestProcessExternalLabels(t *testing.T) {
|
||||||
expected: labels.FromStrings("a", "b", "c", "d", "e", "f"),
|
expected: labels.FromStrings("a", "b", "c", "d", "e", "f"),
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
require.Equal(t, tc.expected, processExternalLabels(tc.labels, tc.externalLabels))
|
b.Reset(tc.labels)
|
||||||
|
processExternalLabels(b, tc.externalLabels)
|
||||||
|
require.Equal(t, tc.expected, b.Labels(), "test %d", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue