Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

store: Optimized labels conversion on store.Series; Added unsafe labels conversion. #2230

Merged
merged 1 commit into from
Mar 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ require (
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
golang.org/x/text v0.3.2
golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd // indirect
golang.org/x/tools v0.0.0-20200306191617-51e69f71924f // indirect
google.golang.org/api v0.14.0
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9
google.golang.org/grpc v1.25.1
Expand Down
11 changes: 7 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -771,8 +771,8 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -803,6 +803,8 @@ golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191112182307-2180aed22343 h1:00ohfJ4K98s3m6BGUoBd8nyfp4Yl0GoIKvw5abItTjI=
golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand Down Expand Up @@ -897,8 +899,9 @@ golang.org/x/tools v0.0.0-20191111182352-50fa39b762bc/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2 h1:EtTFh6h4SAKemS+CURDMTDIANuduG5zKEXShyy18bGA=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd h1:hHkvGJK23seRCflePJnVa9IMv8fsuavSCWKd11kDQFs=
golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200306191617-51e69f71924f h1:bFIWQKTZ5vXyr7xMDvzbWUj5Y/WBE4a4sf35MAyZjx0=
golang.org/x/tools v0.0.0-20200306191617-51e69f71924f/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
Expand Down
2 changes: 1 addition & 1 deletion pkg/receive/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ import (
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/route"
"github.com/prometheus/prometheus/prompb"
"github.com/prometheus/prometheus/storage"
terrors "github.com/prometheus/prometheus/tsdb/errors"
"github.com/thanos-io/thanos/pkg/store/storepb/prompb"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand Down
5 changes: 2 additions & 3 deletions pkg/receive/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@ import (
"github.com/golang/snappy"
"github.com/pkg/errors"
"github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/prompb"
"github.com/prometheus/prometheus/storage"
terrors "github.com/prometheus/prometheus/tsdb/errors"
"google.golang.org/grpc"

"github.com/thanos-io/thanos/pkg/store/storepb"
"github.com/thanos-io/thanos/pkg/store/storepb/prompb"
"google.golang.org/grpc"
)

func TestCountCause(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/receive/hashring.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

"github.com/cespare/xxhash"
"github.com/pkg/errors"
"github.com/prometheus/prometheus/prompb"
"github.com/thanos-io/thanos/pkg/store/storepb/prompb"
)

const sep = '\xff'
Expand Down
2 changes: 1 addition & 1 deletion pkg/receive/hashring_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ package receive
import (
"testing"

"github.com/prometheus/prometheus/prompb"
"github.com/thanos-io/thanos/pkg/store/storepb/prompb"
)

func TestHash(t *testing.T) {
Expand Down
3 changes: 1 addition & 2 deletions pkg/receive/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import (
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"github.com/pkg/errors"
"github.com/prometheus/prometheus/prompb"

"github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/storage"
terrors "github.com/prometheus/prometheus/tsdb/errors"
"github.com/thanos-io/thanos/pkg/store/storepb/prompb"
)

// Appendable returns an Appender.
Expand Down
51 changes: 24 additions & 27 deletions pkg/store/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ import (
"github.com/prometheus/common/version"
"github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/pkg/timestamp"
"github.com/prometheus/prometheus/prompb"
"github.com/prometheus/prometheus/storage/remote"
"github.com/prometheus/prometheus/tsdb/chunkenc"
"github.com/thanos-io/thanos/pkg/component"
"github.com/thanos-io/thanos/pkg/exthttp"
"github.com/thanos-io/thanos/pkg/runutil"
"github.com/thanos-io/thanos/pkg/store/storepb"
"github.com/thanos-io/thanos/pkg/store/storepb/prompb"
"github.com/thanos-io/thanos/pkg/tracing"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand Down Expand Up @@ -178,12 +178,7 @@ func (p *PrometheusStore) Series(r *storepb.SeriesRequest, s storepb.Store_Serie
for k, v := range lbm {
lset = append(lset, storepb.Label{Name: k, Value: v})
}
for _, l := range externalLabels {
lset = append(lset, storepb.Label{
Name: l.Name,
Value: l.Value,
})
}
lset = append(lset, storepb.PromLabelsToLabelsUnsafe(externalLabels)...)
sort.Slice(lset, func(i, j int) bool {
return lset[i].Name < lset[j].Name
})
Expand Down Expand Up @@ -518,32 +513,34 @@ func (p *PrometheusStore) encodeChunk(ss []prompb.Sample) (storepb.Chunk_Encodin

// translateAndExtendLabels transforms a metrics into a protobuf label set. It additionally
// attaches the given labels to it, overwriting existing ones on collision.
// Both input labels are expected to be sorted.
//
// NOTE(bwplotka): Don't use modify passed slices as we reuse underlying memory.
func (p *PrometheusStore) translateAndExtendLabels(m []prompb.Label, extend labels.Labels) []storepb.Label {
pbLabels := storepb.PrompbLabelsToLabelsUnsafe(m)
pbExtend := storepb.PromLabelsToLabelsUnsafe(extend)

lset := make([]storepb.Label, 0, len(m)+len(extend))
ei := 0

for _, l := range m {
if extend.Get(l.Name) != "" {
continue
Outer:
for _, l := range pbLabels {
for ei < len(pbExtend) {
if l.Name < pbExtend[ei].Name {
break
}
lset = append(lset, pbExtend[ei])
ei++
if l.Name == pbExtend[ei-1].Name {
continue Outer
}
}
lset = append(lset, storepb.Label{
Name: l.Name,
Value: l.Value,
})
lset = append(lset, l)
}

return extendLset(lset, extend)
}

func extendLset(lset []storepb.Label, extend labels.Labels) []storepb.Label {
for _, l := range extend {
lset = append(lset, storepb.Label{
Name: l.Name,
Value: l.Value,
})
for ei < len(pbExtend) {
lset = append(lset, pbExtend[ei])
ei++
}
sort.Slice(lset, func(i, j int) bool {
return lset[i].Name < lset[j].Name
})
return lset
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/store/prometheus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import (
"github.com/fortytw2/leaktest"
"github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/pkg/timestamp"
"github.com/prometheus/prometheus/prompb"
"github.com/prometheus/prometheus/tsdb"
"github.com/prometheus/prometheus/tsdb/chunkenc"
"github.com/thanos-io/thanos/pkg/testutil/e2eutil"

"github.com/thanos-io/thanos/pkg/component"
"github.com/thanos-io/thanos/pkg/store/storepb"
"github.com/thanos-io/thanos/pkg/store/storepb/prompb"
"github.com/thanos-io/thanos/pkg/testutil"
)

Expand Down
44 changes: 44 additions & 0 deletions pkg/store/storepb/custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ package storepb

import (
"strings"
"unsafe"

"github.com/prometheus/prometheus/pkg/labels"
"github.com/thanos-io/thanos/pkg/store/storepb/prompb"
)

var PartialResponseStrategyValues = func() []string {
Expand Down Expand Up @@ -166,15 +168,57 @@ func (s *mergedSeriesSet) Next() bool {
return true
}

// LabelsToPromLabels converts Thanos proto labels to Prometheus labels in type safe manner.
func LabelsToPromLabels(lset []Label) labels.Labels {
ret := make(labels.Labels, len(lset))
for i, l := range lset {
ret[i] = labels.Label{Name: l.Name, Value: l.Value}
}
return ret
}

// LabelsToPromLabelsUnsafe converts Thanos proto labels to Prometheus labels in type unsafe manner.
// It reuses the same memory. Caller should abort using passed []Labels.
//
// NOTE: This depends on order of struct fields etc, so use with extreme care.
func LabelsToPromLabelsUnsafe(lset []Label) labels.Labels {
return *(*[]labels.Label)(unsafe.Pointer(&lset))
}

// PromLabelsToLabels converts Prometheus labels to Thanos proto labels in type safe manner.
func PromLabelsToLabels(lset labels.Labels) []Label {
ret := make([]Label, len(lset))
for i, l := range lset {
ret[i] = Label{Name: l.Name, Value: l.Value}
}
return ret
}

// PromLabelsToLabelsUnsafe converts Prometheus labels to Thanos proto labels in type unsafe manner.
// It reuses the same memory. Caller should abort using passed labels.Labels.
//
// // NOTE: This depends on order of struct fields etc, so use with extreme care.
func PromLabelsToLabelsUnsafe(lset labels.Labels) []Label {
return *(*[]Label)(unsafe.Pointer(&lset))
}

// PrompbLabelsToLabels converts Prometheus labels to Thanos proto labels in type safe manner.
func PrompbLabelsToLabels(lset []prompb.Label) []Label {
ret := make([]Label, len(lset))
for i, l := range lset {
ret[i] = Label{Name: l.Name, Value: l.Value}
}
return ret
}

// PrompbLabelsToLabelsUnsafe converts Prometheus proto labels to Thanos proto labels in type unsafe manner.
// It reuses the same memory. Caller should abort using passed labels.Labels.
//
// // NOTE: This depends on order of struct fields etc, so use with extreme care.
func PrompbLabelsToLabelsUnsafe(lset []prompb.Label) []Label {
return *(*[]Label)(unsafe.Pointer(&lset))
}

func LabelsToString(lset []Label) string {
var s []string
for _, l := range lset {
Expand Down
56 changes: 56 additions & 0 deletions pkg/store/storepb/custom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/pkg/errors"
"github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/tsdb/chunkenc"
"github.com/thanos-io/thanos/pkg/store/storepb/prompb"
"github.com/thanos-io/thanos/pkg/testutil"
)

Expand Down Expand Up @@ -328,3 +329,58 @@ func BenchmarkMergedSeriesSet(b *testing.B) {
}
}
}

var testLsetMap = map[string]string{
"a": "1",
"c": "2",
"d": "dsfsdfsdfsdf123414234",
"124134235423534534ffdasdfsf": "1",
"": "",
"b": "",
}

func TestPromLabelsToLabelsUnsafe(t *testing.T) {
testutil.Equals(t, PromLabelsToLabels(labels.FromMap(testLsetMap)), PromLabelsToLabelsUnsafe(labels.FromMap(testLsetMap)))
}

func TestLabelsToPromLabelsUnsafe(t *testing.T) {
testutil.Equals(t, labels.FromMap(testLsetMap), LabelsToPromLabels(PromLabelsToLabels(labels.FromMap(testLsetMap))))
testutil.Equals(t, labels.FromMap(testLsetMap), LabelsToPromLabelsUnsafe(PromLabelsToLabels(labels.FromMap(testLsetMap))))
}

func TestPrompbLabelsToLabelsUnsafe(t *testing.T) {
var pb []prompb.Label
for _, l := range labels.FromMap(testLsetMap) {
pb = append(pb, prompb.Label{Name: l.Name, Value: l.Value})
}
testutil.Equals(t, PromLabelsToLabels(labels.FromMap(testLsetMap)), PrompbLabelsToLabels(pb))
testutil.Equals(t, PromLabelsToLabels(labels.FromMap(testLsetMap)), PrompbLabelsToLabelsUnsafe(pb))
}

func BenchmarkUnsafeVSSafeLabelsConversion(b *testing.B) {
const (
fmtLbl = "%07daaaaaaaaaabbbbbbbbbbccccccccccdddddddddd"
num = 10000
)
lbls := make([]labels.Label, 0, num)
for i := 0; i < num; i++ {
lbls = append(lbls, labels.Label{Name: fmt.Sprintf(fmtLbl, i), Value: fmt.Sprintf(fmtLbl, i)})
}

var converted labels.Labels
b.Run("safe", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
converted = LabelsToPromLabels(PromLabelsToLabels(lbls))
}
})
testutil.Equals(b, num, len(converted))
b.Run("unsafe", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
converted = LabelsToPromLabelsUnsafe(PromLabelsToLabelsUnsafe(lbls))
}
})
testutil.Equals(b, num, len(converted))

}
11 changes: 11 additions & 0 deletions pkg/store/storepb/prompb/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
NOTE(bwplotka): This excerpt of "github.com/prometheus/prometheus/prompb" reconstructed to avoid XXX fields for unsafe conversion to safe allocs.

The compiled protobufs are version controlled and you won't normally need to
re-compile them when building Prometheus.

If however you have modified the defs and do need to re-compile, run
`make proto` from the parent dir.

In order for the script to run, you'll need `protoc` (version 3.5.1) in your
PATH.

Loading