From 1bfb3ed062e99bd3c74e05d9ff9a7fa4e30bbe21 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 14 Nov 2023 11:36:35 +0000 Subject: [PATCH] Labels: reduce allocations when creating from TSDB WAL (#13044) * Labels: reduce allocations when creating from TSDB When reading the WAL, by passing references into the buffer we can avoid copying strings under `-tags stringlabels`. Signed-off-by: Bryan Boreham --- model/labels/labels.go | 7 +++++++ model/labels/labels_stringlabels.go | 6 ++++++ tsdb/record/record.go | 7 +++---- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/model/labels/labels.go b/model/labels/labels.go index 3dc3049b1c..231460ea33 100644 --- a/model/labels/labels.go +++ b/model/labels/labels.go @@ -617,6 +617,13 @@ func (b *ScratchBuilder) Add(name, value string) { b.add = append(b.add, Label{Name: name, Value: value}) } +// Add a name/value pair, using []byte instead of string. +// The '-tags stringlabels' version of this function is unsafe, hence the name. +// This version is safe - it copies the strings immediately - but we keep the same name so everything compiles. +func (b *ScratchBuilder) UnsafeAddBytes(name, value []byte) { + b.add = append(b.add, Label{Name: string(name), Value: string(value)}) +} + // Sort the labels added so far by name. func (b *ScratchBuilder) Sort() { slices.SortFunc(b.add, func(a, b Label) int { return strings.Compare(a.Name, b.Name) }) diff --git a/model/labels/labels_stringlabels.go b/model/labels/labels_stringlabels.go index cc6bfcc700..bbb4452d45 100644 --- a/model/labels/labels_stringlabels.go +++ b/model/labels/labels_stringlabels.go @@ -829,6 +829,12 @@ func (b *ScratchBuilder) Add(name, value string) { b.add = append(b.add, Label{Name: name, Value: value}) } +// Add a name/value pair, using []byte instead of string to reduce memory allocations. +// The values must remain live until Labels() is called. +func (b *ScratchBuilder) UnsafeAddBytes(name, value []byte) { + b.add = append(b.add, Label{Name: yoloString(name), Value: yoloString(value)}) +} + // Sort the labels added so far by name. func (b *ScratchBuilder) Sort() { slices.SortFunc(b.add, func(a, b Label) int { return strings.Compare(a.Name, b.Name) }) diff --git a/tsdb/record/record.go b/tsdb/record/record.go index 75c15c4900..42a656dfe8 100644 --- a/tsdb/record/record.go +++ b/tsdb/record/record.go @@ -279,13 +279,12 @@ func (d *Decoder) Metadata(rec []byte, metadata []RefMetadata) ([]RefMetadata, e // DecodeLabels decodes one set of labels from buf. func (d *Decoder) DecodeLabels(dec *encoding.Decbuf) labels.Labels { - // TODO: reconsider if this function could be pushed down into labels.Labels to be more efficient. d.builder.Reset() nLabels := dec.Uvarint() for i := 0; i < nLabels; i++ { - lName := dec.UvarintStr() - lValue := dec.UvarintStr() - d.builder.Add(lName, lValue) + lName := dec.UvarintBytes() + lValue := dec.UvarintBytes() + d.builder.UnsafeAddBytes(lName, lValue) } return d.builder.Labels() }