From de0a772b8e7d27dc744810a1a693d97be027049a Mon Sep 17 00:00:00 2001 From: Tom Wilkie Date: Mon, 18 Nov 2019 11:53:33 -0800 Subject: [PATCH] Port tsdb to use pkg/labels. (#6326) * Port tsdb to use pkg/labels. Signed-off-by: Tom Wilkie * Get tests passing. Signed-off-by: Tom Wilkie * Remove useless cast. Signed-off-by: Tom Wilkie * Appease linters. Signed-off-by: Tom Wilkie * Fix review comments Signed-off-by: Ganesh Vernekar --- pkg/labels/labels.go | 18 +++ pkg/labels/matcher.go | 24 +++ pkg/labels/test_utils.go | 87 ++++++++++ storage/remote/queue_manager.go | 3 +- storage/remote/queue_manager_test.go | 19 ++- storage/remote/read_test.go | 72 ++++----- storage/tsdb/tsdb.go | 48 +----- tsdb/block.go | 4 +- tsdb/block_test.go | 7 +- tsdb/cmd/tsdb/main.go | 4 +- tsdb/compact.go | 2 +- tsdb/compact_test.go | 4 +- tsdb/db.go | 4 +- tsdb/db_test.go | 80 ++++----- tsdb/head.go | 10 +- tsdb/head_bench_test.go | 56 +++---- tsdb/head_test.go | 42 ++--- tsdb/index/index.go | 2 +- tsdb/index/index_test.go | 2 +- tsdb/index/postings.go | 2 +- tsdb/index/postings_test.go | 2 +- tsdb/labels/labels.go | 233 --------------------------- tsdb/labels/labels_test.go | 199 ----------------------- tsdb/labels/selector.go | 109 ------------- tsdb/mocks_test.go | 4 +- tsdb/querier.go | 58 ++++--- tsdb/querier_test.go | 122 +++++++------- tsdb/record/record.go | 2 +- tsdb/record/record_test.go | 2 +- tsdb/repair_test.go | 2 +- tsdb/test/labels_test.go | 2 +- tsdb/wal.go | 2 +- tsdb/wal/checkpoint_test.go | 2 +- tsdb/wal/watcher_test.go | 2 +- tsdb/wal_test.go | 2 +- web/api/v1/api.go | 39 +---- web/api/v1/api_test.go | 7 +- web/api/v2/api.go | 28 ++-- 38 files changed, 410 insertions(+), 897 deletions(-) create mode 100644 pkg/labels/test_utils.go delete mode 100644 tsdb/labels/labels.go delete mode 100644 tsdb/labels/labels_test.go delete mode 100644 tsdb/labels/selector.go diff --git a/pkg/labels/labels.go b/pkg/labels/labels.go index b1d434881a..93c0a338b9 100644 --- a/pkg/labels/labels.go +++ b/pkg/labels/labels.go @@ -201,6 +201,24 @@ func (ls Labels) Has(name string) bool { return false } +// WithoutEmpty returns the labelset without empty labels. +// May return the same labelset. +func (ls Labels) WithoutEmpty() Labels { + for _, v := range ls { + if v.Value != "" { + continue + } + els := make(Labels, 0, len(ls)-1) + for _, v := range ls { + if v.Value != "" { + els = append(els, v) + } + } + return els + } + return ls +} + // Equal returns whether the two label sets are equal. func Equal(ls, o Labels) bool { if len(ls) != len(o) { diff --git a/pkg/labels/matcher.go b/pkg/labels/matcher.go index 7fa5d947e7..2702d9ddbe 100644 --- a/pkg/labels/matcher.go +++ b/pkg/labels/matcher.go @@ -68,6 +68,15 @@ func NewMatcher(t MatchType, n, v string) (*Matcher, error) { return m, nil } +// MustNewMatcher panics on error - only for use in tests! +func MustNewMatcher(mt MatchType, name, val string) *Matcher { + m, err := NewMatcher(mt, name, val) + if err != nil { + panic(err) + } + return m +} + func (m *Matcher) String() string { return fmt.Sprintf("%s%s%q", m.Name, m.Type, m.Value) } @@ -86,3 +95,18 @@ func (m *Matcher) Matches(s string) bool { } panic("labels.Matcher.Matches: invalid match type") } + +// Inverse returns a matcher that matches the opposite. +func (m *Matcher) Inverse() (*Matcher, error) { + switch m.Type { + case MatchEqual: + return NewMatcher(MatchNotEqual, m.Name, m.Value) + case MatchNotEqual: + return NewMatcher(MatchEqual, m.Name, m.Value) + case MatchRegexp: + return NewMatcher(MatchNotRegexp, m.Name, m.Value) + case MatchNotRegexp: + return NewMatcher(MatchRegexp, m.Name, m.Value) + } + panic("labels.Matcher.Matches: invalid match type") +} diff --git a/pkg/labels/test_utils.go b/pkg/labels/test_utils.go new file mode 100644 index 0000000000..319ee6184e --- /dev/null +++ b/pkg/labels/test_utils.go @@ -0,0 +1,87 @@ +// Copyright 2017 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package labels + +import ( + "bufio" + "os" + "sort" + "strings" + + "github.com/pkg/errors" +) + +// Slice is a sortable slice of label sets. +type Slice []Labels + +func (s Slice) Len() int { return len(s) } +func (s Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s Slice) Less(i, j int) bool { return Compare(s[i], s[j]) < 0 } + +// Selector holds constraints for matching against a label set. +type Selector []*Matcher + +// Matches returns whether the labels satisfy all matchers. +func (s Selector) Matches(labels Labels) bool { + for _, m := range s { + if v := labels.Get(m.Name); !m.Matches(v) { + return false + } + } + return true +} + +// ReadLabels reads up to n label sets in a JSON formatted file fn. It is mostly useful +// to load testing data. +func ReadLabels(fn string, n int) ([]Labels, error) { + f, err := os.Open(fn) + if err != nil { + return nil, err + } + defer f.Close() + + scanner := bufio.NewScanner(f) + + var mets []Labels + hashes := map[uint64]struct{}{} + i := 0 + + for scanner.Scan() && i < n { + m := make(Labels, 0, 10) + + r := strings.NewReplacer("\"", "", "{", "", "}", "") + s := r.Replace(scanner.Text()) + + labelChunks := strings.Split(s, ",") + for _, labelChunk := range labelChunks { + split := strings.Split(labelChunk, ":") + m = append(m, Label{Name: split[0], Value: split[1]}) + } + // Order of the k/v labels matters, don't assume we'll always receive them already sorted. + sort.Sort(m) + + h := m.Hash() + if _, ok := hashes[h]; ok { + continue + } + mets = append(mets, m) + hashes[h] = struct{}{} + i++ + } + + if i != n { + return mets, errors.Errorf("requested %d metrics but found %d", n, i) + } + return mets, nil +} diff --git a/storage/remote/queue_manager.go b/storage/remote/queue_manager.go index a0e4b5b415..57e4ff3bab 100644 --- a/storage/remote/queue_manager.go +++ b/storage/remote/queue_manager.go @@ -32,7 +32,6 @@ import ( "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/pkg/relabel" "github.com/prometheus/prometheus/prompb" - tsdbLabels "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/record" "github.com/prometheus/prometheus/tsdb/wal" ) @@ -443,7 +442,7 @@ func releaseLabels(ls labels.Labels) { // processExternalLabels merges externalLabels into ls. If ls contains // a label in externalLabels, the value in ls wins. -func processExternalLabels(ls tsdbLabels.Labels, externalLabels labels.Labels) labels.Labels { +func processExternalLabels(ls labels.Labels, externalLabels labels.Labels) labels.Labels { i, j, result := 0, 0, make(labels.Labels, 0, len(ls)+len(externalLabels)) for i < len(ls) && j < len(externalLabels) { if ls[i].Name < externalLabels[j].Name { diff --git a/storage/remote/queue_manager_test.go b/storage/remote/queue_manager_test.go index eef8082e4a..e52780925b 100644 --- a/storage/remote/queue_manager_test.go +++ b/storage/remote/queue_manager_test.go @@ -36,7 +36,6 @@ import ( "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/prompb" - tsdbLabels "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/record" "github.com/prometheus/prometheus/util/testutil" ) @@ -117,7 +116,7 @@ func TestSampleDeliveryOrder(t *testing.T) { }) series = append(series, record.RefSeries{ Ref: uint64(i), - Labels: tsdbLabels.Labels{tsdbLabels.Label{Name: "__name__", Value: name}}, + Labels: labels.Labels{labels.Label{Name: "__name__", Value: name}}, }) } @@ -186,7 +185,7 @@ func TestSeriesReset(t *testing.T) { for i := 0; i < numSegments; i++ { series := []record.RefSeries{} for j := 0; j < numSeries; j++ { - series = append(series, record.RefSeries{Ref: uint64((i * 100) + j), Labels: tsdbLabels.Labels{{Name: "a", Value: "a"}}}) + series = append(series, record.RefSeries{Ref: uint64((i * 100) + j), Labels: labels.Labels{{Name: "a", Value: "a"}}}) } m.StoreSeries(series, i) } @@ -266,8 +265,8 @@ func TestReleaseNoninternedString(t *testing.T) { m.StoreSeries([]record.RefSeries{ { Ref: uint64(i), - Labels: tsdbLabels.Labels{ - tsdbLabels.Label{ + Labels: labels.Labels{ + labels.Label{ Name: "asdf", Value: fmt.Sprintf("%d", i), }, @@ -338,7 +337,7 @@ func createTimeseries(n int) ([]record.RefSample, []record.RefSeries) { }) series = append(series, record.RefSeries{ Ref: uint64(i), - Labels: tsdbLabels.Labels{{Name: "__name__", Value: name}}, + Labels: labels.Labels{{Name: "__name__", Value: name}}, }) } return samples, series @@ -541,27 +540,27 @@ func BenchmarkStartup(b *testing.B) { func TestProcessExternalLabels(t *testing.T) { for _, tc := range []struct { - labels tsdbLabels.Labels + labels labels.Labels externalLabels labels.Labels expected labels.Labels }{ // Test adding labels at the end. { - labels: tsdbLabels.Labels{{Name: "a", Value: "b"}}, + labels: labels.Labels{{Name: "a", Value: "b"}}, externalLabels: labels.Labels{{Name: "c", Value: "d"}}, expected: labels.Labels{{Name: "a", Value: "b"}, {Name: "c", Value: "d"}}, }, // Test adding labels at the beginning. { - labels: tsdbLabels.Labels{{Name: "c", Value: "d"}}, + labels: labels.Labels{{Name: "c", Value: "d"}}, externalLabels: labels.Labels{{Name: "a", Value: "b"}}, expected: labels.Labels{{Name: "a", Value: "b"}, {Name: "c", Value: "d"}}, }, // Test we don't override existing labels. { - labels: tsdbLabels.Labels{{Name: "a", Value: "b"}}, + labels: labels.Labels{{Name: "a", Value: "b"}}, externalLabels: labels.Labels{{Name: "a", Value: "c"}}, expected: labels.Labels{{Name: "a", Value: "b"}}, }, diff --git a/storage/remote/read_test.go b/storage/remote/read_test.go index b9e1b2a3a3..1571a8562a 100644 --- a/storage/remote/read_test.go +++ b/storage/remote/read_test.go @@ -24,17 +24,9 @@ import ( "github.com/prometheus/prometheus/storage" ) -func mustNewLabelMatcher(mt labels.MatchType, name, val string) *labels.Matcher { - m, err := labels.NewMatcher(mt, name, val) - if err != nil { - panic(err) - } - return m -} - func TestExternalLabelsQuerierSelect(t *testing.T) { matchers := []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "job", "api-server"), + labels.MustNewMatcher(labels.MatchEqual, "job", "api-server"), } q := &externalLabelsQuerier{ Querier: mockQuerier{}, @@ -61,10 +53,10 @@ func TestExternalLabelsQuerierAddExternalLabels(t *testing.T) { }{ { inMatchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "job", "api-server"), + labels.MustNewMatcher(labels.MatchEqual, "job", "api-server"), }, outMatchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "job", "api-server"), + labels.MustNewMatcher(labels.MatchEqual, "job", "api-server"), }, added: labels.Labels{}, }, @@ -74,12 +66,12 @@ func TestExternalLabelsQuerierAddExternalLabels(t *testing.T) { {Name: "region", Value: "europe"}, }, inMatchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "job", "api-server"), + labels.MustNewMatcher(labels.MatchEqual, "job", "api-server"), }, outMatchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "job", "api-server"), - mustNewLabelMatcher(labels.MatchEqual, "region", "europe"), - mustNewLabelMatcher(labels.MatchEqual, "dc", "berlin-01"), + labels.MustNewMatcher(labels.MatchEqual, "job", "api-server"), + labels.MustNewMatcher(labels.MatchEqual, "region", "europe"), + labels.MustNewMatcher(labels.MatchEqual, "dc", "berlin-01"), }, added: labels.Labels{ {Name: "dc", Value: "berlin-01"}, @@ -92,13 +84,13 @@ func TestExternalLabelsQuerierAddExternalLabels(t *testing.T) { {Name: "dc", Value: "berlin-01"}, }, inMatchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "job", "api-server"), - mustNewLabelMatcher(labels.MatchEqual, "dc", "munich-02"), + labels.MustNewMatcher(labels.MatchEqual, "job", "api-server"), + labels.MustNewMatcher(labels.MatchEqual, "dc", "munich-02"), }, outMatchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "job", "api-server"), - mustNewLabelMatcher(labels.MatchEqual, "region", "europe"), - mustNewLabelMatcher(labels.MatchEqual, "dc", "munich-02"), + labels.MustNewMatcher(labels.MatchEqual, "job", "api-server"), + labels.MustNewMatcher(labels.MatchEqual, "region", "europe"), + labels.MustNewMatcher(labels.MatchEqual, "dc", "munich-02"), }, added: labels.Labels{ {Name: "region", Value: "europe"}, @@ -227,12 +219,12 @@ func TestRequiredMatchersFilter(t *testing.T) { storage.QueryableFunc(func(ctx context.Context, mint, maxt int64) (storage.Querier, error) { return mockQuerier{ctx: ctx, mint: mint, maxt: maxt}, nil }), - []*labels.Matcher{mustNewLabelMatcher(labels.MatchEqual, "special", "label")}, + []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "special", "label")}, ) want := &requiredMatchersQuerier{ Querier: mockQuerier{ctx: ctx, mint: 0, maxt: 50}, - requiredMatchers: []*labels.Matcher{mustNewLabelMatcher(labels.MatchEqual, "special", "label")}, + requiredMatchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "special", "label")}, } have, err := f.Querier(ctx, 0, 50) if err != nil { @@ -253,66 +245,66 @@ func TestRequiredLabelsQuerierSelect(t *testing.T) { { requiredMatchers: []*labels.Matcher{}, matchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "special", "label"), + labels.MustNewMatcher(labels.MatchEqual, "special", "label"), }, seriesSet: mockSeriesSet{}, }, { requiredMatchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "special", "label"), + labels.MustNewMatcher(labels.MatchEqual, "special", "label"), }, matchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "special", "label"), + labels.MustNewMatcher(labels.MatchEqual, "special", "label"), }, seriesSet: mockSeriesSet{}, }, { requiredMatchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "special", "label"), + labels.MustNewMatcher(labels.MatchEqual, "special", "label"), }, matchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchRegexp, "special", "label"), + labels.MustNewMatcher(labels.MatchRegexp, "special", "label"), }, seriesSet: storage.NoopSeriesSet(), }, { requiredMatchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "special", "label"), + labels.MustNewMatcher(labels.MatchEqual, "special", "label"), }, matchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "special", "different"), + labels.MustNewMatcher(labels.MatchEqual, "special", "different"), }, seriesSet: storage.NoopSeriesSet(), }, { requiredMatchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "special", "label"), + labels.MustNewMatcher(labels.MatchEqual, "special", "label"), }, matchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "special", "label"), - mustNewLabelMatcher(labels.MatchEqual, "foo", "bar"), + labels.MustNewMatcher(labels.MatchEqual, "special", "label"), + labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"), }, seriesSet: mockSeriesSet{}, }, { requiredMatchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "special", "label"), - mustNewLabelMatcher(labels.MatchEqual, "foo", "bar"), + labels.MustNewMatcher(labels.MatchEqual, "special", "label"), + labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"), }, matchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "special", "label"), - mustNewLabelMatcher(labels.MatchEqual, "foo", "baz"), + labels.MustNewMatcher(labels.MatchEqual, "special", "label"), + labels.MustNewMatcher(labels.MatchEqual, "foo", "baz"), }, seriesSet: storage.NoopSeriesSet(), }, { requiredMatchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "special", "label"), - mustNewLabelMatcher(labels.MatchEqual, "foo", "bar"), + labels.MustNewMatcher(labels.MatchEqual, "special", "label"), + labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"), }, matchers: []*labels.Matcher{ - mustNewLabelMatcher(labels.MatchEqual, "special", "label"), - mustNewLabelMatcher(labels.MatchEqual, "foo", "bar"), + labels.MustNewMatcher(labels.MatchEqual, "special", "label"), + labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"), }, seriesSet: mockSeriesSet{}, }, diff --git a/storage/tsdb/tsdb.go b/storage/tsdb/tsdb.go index e72242d126..d982ef5cf2 100644 --- a/storage/tsdb/tsdb.go +++ b/storage/tsdb/tsdb.go @@ -17,7 +17,6 @@ import ( "context" "sync" "time" - "unsafe" "github.com/alecthomas/units" "github.com/go-kit/kit/log" @@ -27,7 +26,6 @@ import ( "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/storage" "github.com/prometheus/prometheus/tsdb" - tsdbLabels "github.com/prometheus/prometheus/tsdb/labels" ) // ErrNotReady is returned if the underlying storage is not ready yet. @@ -244,12 +242,7 @@ type querier struct { q tsdb.Querier } -func (q querier) Select(_ *storage.SelectParams, oms ...*labels.Matcher) (storage.SeriesSet, storage.Warnings, error) { - ms := make([]tsdbLabels.Matcher, 0, len(oms)) - - for _, om := range oms { - ms = append(ms, convertMatcher(om)) - } +func (q querier) Select(_ *storage.SelectParams, ms ...*labels.Matcher) (storage.SeriesSet, storage.Warnings, error) { set, err := q.q.Select(ms...) if err != nil { return nil, nil, err @@ -279,15 +272,15 @@ type series struct { s tsdb.Series } -func (s series) Labels() labels.Labels { return toLabels(s.s.Labels()) } -func (s series) Iterator() storage.SeriesIterator { return storage.SeriesIterator(s.s.Iterator()) } +func (s series) Labels() labels.Labels { return s.s.Labels() } +func (s series) Iterator() storage.SeriesIterator { return s.s.Iterator() } type appender struct { a tsdb.Appender } func (a appender) Add(lset labels.Labels, t int64, v float64) (uint64, error) { - ref, err := a.a.Add(toTSDBLabels(lset), t, v) + ref, err := a.a.Add(lset, t, v) switch errors.Cause(err) { case tsdb.ErrNotFound: @@ -320,36 +313,3 @@ func (a appender) AddFast(_ labels.Labels, ref uint64, t int64, v float64) error func (a appender) Commit() error { return a.a.Commit() } func (a appender) Rollback() error { return a.a.Rollback() } - -func convertMatcher(m *labels.Matcher) tsdbLabels.Matcher { - switch m.Type { - case labels.MatchEqual: - return tsdbLabels.NewEqualMatcher(m.Name, m.Value) - - case labels.MatchNotEqual: - return tsdbLabels.Not(tsdbLabels.NewEqualMatcher(m.Name, m.Value)) - - case labels.MatchRegexp: - res, err := tsdbLabels.NewRegexpMatcher(m.Name, "^(?:"+m.Value+")$") - if err != nil { - panic(err) - } - return res - - case labels.MatchNotRegexp: - res, err := tsdbLabels.NewRegexpMatcher(m.Name, "^(?:"+m.Value+")$") - if err != nil { - panic(err) - } - return tsdbLabels.Not(res) - } - panic("storage.convertMatcher: invalid matcher type") -} - -func toTSDBLabels(l labels.Labels) tsdbLabels.Labels { - return *(*tsdbLabels.Labels)(unsafe.Pointer(&l)) -} - -func toLabels(l tsdbLabels.Labels) labels.Labels { - return *(*labels.Labels)(unsafe.Pointer(&l)) -} diff --git a/tsdb/block.go b/tsdb/block.go index 2235c7e318..e61d43ae4f 100644 --- a/tsdb/block.go +++ b/tsdb/block.go @@ -26,12 +26,12 @@ import ( "github.com/go-kit/kit/log/level" "github.com/oklog/ulid" "github.com/pkg/errors" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/chunkenc" "github.com/prometheus/prometheus/tsdb/chunks" tsdb_errors "github.com/prometheus/prometheus/tsdb/errors" "github.com/prometheus/prometheus/tsdb/fileutil" "github.com/prometheus/prometheus/tsdb/index" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/tombstones" ) @@ -504,7 +504,7 @@ func (r blockChunkReader) Close() error { } // Delete matching series between mint and maxt in the block. -func (pb *Block) Delete(mint, maxt int64, ms ...labels.Matcher) error { +func (pb *Block) Delete(mint, maxt int64, ms ...*labels.Matcher) error { pb.mtx.Lock() defer pb.mtx.Unlock() diff --git a/tsdb/block_test.go b/tsdb/block_test.go index 86f07a1984..d0f0a44413 100644 --- a/tsdb/block_test.go +++ b/tsdb/block_test.go @@ -17,8 +17,6 @@ import ( "context" "encoding/binary" - "github.com/prometheus/prometheus/tsdb/fileutil" - "errors" "io/ioutil" "math/rand" @@ -28,8 +26,9 @@ import ( "testing" "github.com/go-kit/kit/log" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/chunks" - "github.com/prometheus/prometheus/tsdb/labels" + "github.com/prometheus/prometheus/tsdb/fileutil" "github.com/prometheus/prometheus/tsdb/tsdbutil" "github.com/prometheus/prometheus/util/testutil" ) @@ -184,7 +183,7 @@ func TestBlockSize(t *testing.T) { // Delete some series and check the sizes again. { - testutil.Ok(t, blockInit.Delete(1, 10, labels.NewMustRegexpMatcher("", ".*"))) + testutil.Ok(t, blockInit.Delete(1, 10, labels.MustNewMatcher(labels.MatchRegexp, "", ".*"))) expAfterDelete := blockInit.Size() testutil.Assert(t, expAfterDelete > expSizeInit, "after a delete the block size should be bigger as the tombstone file should grow %v > %v", expAfterDelete, expSizeInit) actAfterDelete, err := fileutil.DirSize(blockDirInit) diff --git a/tsdb/cmd/tsdb/main.go b/tsdb/cmd/tsdb/main.go index 9acc80ad7a..0f8d8c00dc 100644 --- a/tsdb/cmd/tsdb/main.go +++ b/tsdb/cmd/tsdb/main.go @@ -32,10 +32,10 @@ import ( "github.com/go-kit/kit/log" "github.com/pkg/errors" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb" "github.com/prometheus/prometheus/tsdb/chunks" tsdb_errors "github.com/prometheus/prometheus/tsdb/errors" - "github.com/prometheus/prometheus/tsdb/labels" kingpin "gopkg.in/alecthomas/kingpin.v2" ) @@ -630,7 +630,7 @@ func dumpSamples(db *tsdb.DBReadOnly, mint, maxt int64) (err error) { err = merr.Err() }() - ss, err := q.Select(labels.NewMustRegexpMatcher("", ".*")) + ss, err := q.Select(labels.MustNewMatcher(labels.MatchRegexp, "", ".*")) if err != nil { return err } diff --git a/tsdb/compact.go b/tsdb/compact.go index 5a39a9650f..e446235fbb 100644 --- a/tsdb/compact.go +++ b/tsdb/compact.go @@ -29,12 +29,12 @@ import ( "github.com/oklog/ulid" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/chunkenc" "github.com/prometheus/prometheus/tsdb/chunks" tsdb_errors "github.com/prometheus/prometheus/tsdb/errors" "github.com/prometheus/prometheus/tsdb/fileutil" "github.com/prometheus/prometheus/tsdb/index" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/tombstones" ) diff --git a/tsdb/compact_test.go b/tsdb/compact_test.go index 617d80cbee..e24b720d2a 100644 --- a/tsdb/compact_test.go +++ b/tsdb/compact_test.go @@ -27,9 +27,9 @@ import ( "github.com/go-kit/kit/log" "github.com/pkg/errors" prom_testutil "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/chunks" "github.com/prometheus/prometheus/tsdb/fileutil" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/tombstones" "github.com/prometheus/prometheus/util/testutil" ) @@ -289,7 +289,7 @@ func TestLeveledCompactor_plan(t *testing.T) { }, `Regression test: we were wrongly assuming that new block is fresh from WAL when its ULID is newest. We need to actually look on max time instead. - + With previous, wrong approach "8" block was ignored, so we were wrongly compacting 5 and 7 and introducing block overlaps`: { metas: []dirMeta{ diff --git a/tsdb/db.go b/tsdb/db.go index 08d041e4da..9ab34767b2 100644 --- a/tsdb/db.go +++ b/tsdb/db.go @@ -34,11 +34,11 @@ import ( "github.com/oklog/ulid" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/chunkenc" tsdb_errors "github.com/prometheus/prometheus/tsdb/errors" "github.com/prometheus/prometheus/tsdb/fileutil" _ "github.com/prometheus/prometheus/tsdb/goversion" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/wal" "golang.org/x/sync/errgroup" ) @@ -1247,7 +1247,7 @@ func rangeForTimestamp(t int64, width int64) (maxt int64) { } // Delete implements deletion of metrics. It only has atomicity guarantees on a per-block basis. -func (db *DB) Delete(mint, maxt int64, ms ...labels.Matcher) error { +func (db *DB) Delete(mint, maxt int64, ms ...*labels.Matcher) error { db.cmtx.Lock() defer db.cmtx.Unlock() diff --git a/tsdb/db_test.go b/tsdb/db_test.go index 4c44c70f4a..6135d3a850 100644 --- a/tsdb/db_test.go +++ b/tsdb/db_test.go @@ -32,9 +32,9 @@ import ( "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" prom_testutil "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/chunks" "github.com/prometheus/prometheus/tsdb/index" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/record" "github.com/prometheus/prometheus/tsdb/tombstones" "github.com/prometheus/prometheus/tsdb/tsdbutil" @@ -56,7 +56,7 @@ func openTestDB(t testing.TB, opts *Options) (db *DB, close func()) { } // query runs a matcher query against the querier and fully expands its data. -func query(t testing.TB, q Querier, matchers ...labels.Matcher) map[string][]tsdbutil.Sample { +func query(t testing.TB, q Querier, matchers ...*labels.Matcher) map[string][]tsdbutil.Sample { ss, err := q.Select(matchers...) defer func() { testutil.Ok(t, q.Close()) @@ -127,7 +127,7 @@ func TestDataAvailableOnlyAfterCommit(t *testing.T) { querier, err := db.Querier(0, 1) testutil.Ok(t, err) - seriesSet := query(t, querier, labels.NewEqualMatcher("foo", "bar")) + seriesSet := query(t, querier, labels.MustNewMatcher(labels.MatchEqual, "foo", "bar")) testutil.Equals(t, map[string][]tsdbutil.Sample{}, seriesSet) err = app.Commit() @@ -137,7 +137,7 @@ func TestDataAvailableOnlyAfterCommit(t *testing.T) { testutil.Ok(t, err) defer querier.Close() - seriesSet = query(t, querier, labels.NewEqualMatcher("foo", "bar")) + seriesSet = query(t, querier, labels.MustNewMatcher(labels.MatchEqual, "foo", "bar")) testutil.Equals(t, map[string][]tsdbutil.Sample{`{foo="bar"}`: {sample{t: 0, v: 0}}}, seriesSet) } @@ -160,7 +160,7 @@ func TestDataNotAvailableAfterRollback(t *testing.T) { testutil.Ok(t, err) defer querier.Close() - seriesSet := query(t, querier, labels.NewEqualMatcher("foo", "bar")) + seriesSet := query(t, querier, labels.MustNewMatcher(labels.MatchEqual, "foo", "bar")) testutil.Equals(t, map[string][]tsdbutil.Sample{}, seriesSet) } @@ -207,7 +207,7 @@ func TestDBAppenderAddRef(t *testing.T) { q, err := db.Querier(0, 200) testutil.Ok(t, err) - res := query(t, q, labels.NewEqualMatcher("a", "b")) + res := query(t, q, labels.MustNewMatcher(labels.MatchEqual, "a", "b")) testutil.Equals(t, map[string][]tsdbutil.Sample{ labels.FromStrings("a", "b").String(): { @@ -293,14 +293,14 @@ Outer: // TODO(gouthamve): Reset the tombstones somehow. // Delete the ranges. for _, r := range c.Intervals { - testutil.Ok(t, db.Delete(r.Mint, r.Maxt, labels.NewEqualMatcher("a", "b"))) + testutil.Ok(t, db.Delete(r.Mint, r.Maxt, labels.MustNewMatcher(labels.MatchEqual, "a", "b"))) } // Compare the result. q, err := db.Querier(0, numSamples) testutil.Ok(t, err) - res, err := q.Select(labels.NewEqualMatcher("a", "b")) + res, err := q.Select(labels.MustNewMatcher(labels.MatchEqual, "a", "b")) testutil.Ok(t, err) expSamples := make([]tsdbutil.Sample, 0, len(c.remaint)) @@ -419,7 +419,7 @@ func TestSkippingInvalidValuesInSameTxn(t *testing.T) { q, err := db.Querier(0, 10) testutil.Ok(t, err) - ssMap := query(t, q, labels.NewEqualMatcher("a", "b")) + ssMap := query(t, q, labels.MustNewMatcher(labels.MatchEqual, "a", "b")) testutil.Equals(t, map[string][]tsdbutil.Sample{ labels.New(labels.Label{Name: "a", Value: "b"}).String(): {sample{0, 1}}, @@ -436,7 +436,7 @@ func TestSkippingInvalidValuesInSameTxn(t *testing.T) { q, err = db.Querier(0, 10) testutil.Ok(t, err) - ssMap = query(t, q, labels.NewEqualMatcher("a", "b")) + ssMap = query(t, q, labels.MustNewMatcher(labels.MatchEqual, "a", "b")) testutil.Equals(t, map[string][]tsdbutil.Sample{ labels.New(labels.Label{Name: "a", Value: "b"}).String(): {sample{0, 1}, sample{10, 3}}, @@ -477,7 +477,7 @@ func TestDB_Snapshot(t *testing.T) { defer func() { testutil.Ok(t, querier.Close()) }() // sum values - seriesSet, err := querier.Select(labels.NewEqualMatcher("foo", "bar")) + seriesSet, err := querier.Select(labels.MustNewMatcher(labels.MatchEqual, "foo", "bar")) testutil.Ok(t, err) sum := 0.0 @@ -531,7 +531,7 @@ func TestDB_Snapshot_ChunksOutsideOfCompactedRange(t *testing.T) { defer func() { testutil.Ok(t, querier.Close()) }() // Sum values. - seriesSet, err := querier.Select(labels.NewEqualMatcher("foo", "bar")) + seriesSet, err := querier.Select(labels.MustNewMatcher(labels.MatchEqual, "foo", "bar")) testutil.Ok(t, err) sum := 0.0 @@ -579,7 +579,7 @@ Outer: // TODO(gouthamve): Reset the tombstones somehow. // Delete the ranges. for _, r := range c.intervals { - testutil.Ok(t, db.Delete(r.Mint, r.Maxt, labels.NewEqualMatcher("a", "b"))) + testutil.Ok(t, db.Delete(r.Mint, r.Maxt, labels.MustNewMatcher(labels.MatchEqual, "a", "b"))) } // create snapshot @@ -602,7 +602,7 @@ Outer: testutil.Ok(t, err) defer func() { testutil.Ok(t, q.Close()) }() - res, err := q.Select(labels.NewEqualMatcher("a", "b")) + res, err := q.Select(labels.MustNewMatcher(labels.MatchEqual, "a", "b")) testutil.Ok(t, err) expSamples := make([]tsdbutil.Sample, 0, len(c.remaint)) @@ -647,7 +647,7 @@ func TestDB_e2e(t *testing.T) { timeInterval = int64(3) ) // Create 8 series with 1000 data-points of different ranges and run queries. - lbls := [][]labels.Label{ + lbls := []labels.Labels{ { {Name: "a", Value: "b"}, {Name: "instance", Value: "localhost:9090"}, @@ -726,22 +726,22 @@ func TestDB_e2e(t *testing.T) { // Query each selector on 1000 random time-ranges. queries := []struct { - ms []labels.Matcher + ms []*labels.Matcher }{ { - ms: []labels.Matcher{labels.NewEqualMatcher("a", "b")}, + ms: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "a", "b")}, }, { - ms: []labels.Matcher{ - labels.NewEqualMatcher("a", "b"), - labels.NewEqualMatcher("job", "prom-k8s"), + ms: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "a", "b"), + labels.MustNewMatcher(labels.MatchEqual, "job", "prom-k8s"), }, }, { - ms: []labels.Matcher{ - labels.NewEqualMatcher("a", "c"), - labels.NewEqualMatcher("instance", "localhost:9090"), - labels.NewEqualMatcher("job", "prometheus"), + ms: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "a", "c"), + labels.MustNewMatcher(labels.MatchEqual, "instance", "localhost:9090"), + labels.MustNewMatcher(labels.MatchEqual, "job", "prometheus"), }, }, // TODO: Add Regexp Matchers. @@ -920,7 +920,7 @@ func TestTombstoneClean(t *testing.T) { defer db.Close() for _, r := range c.intervals { - testutil.Ok(t, db.Delete(r.Mint, r.Maxt, labels.NewEqualMatcher("a", "b"))) + testutil.Ok(t, db.Delete(r.Mint, r.Maxt, labels.MustNewMatcher(labels.MatchEqual, "a", "b"))) } // All of the setup for THIS line. @@ -931,7 +931,7 @@ func TestTombstoneClean(t *testing.T) { testutil.Ok(t, err) defer q.Close() - res, err := q.Select(labels.NewEqualMatcher("a", "b")) + res, err := q.Select(labels.MustNewMatcher(labels.MatchEqual, "a", "b")) testutil.Ok(t, err) expSamples := make([]tsdbutil.Sample, 0, len(c.remaint)) @@ -1232,39 +1232,39 @@ func TestNotMatcherSelectsLabelsUnsetSeries(t *testing.T) { series []labels.Labels }{{ selector: labels.Selector{ - labels.Not(labels.NewEqualMatcher("lname", "lvalue")), + labels.MustNewMatcher(labels.MatchNotEqual, "lname", "lvalue"), }, series: labelpairs, }, { selector: labels.Selector{ - labels.NewEqualMatcher("a", "abcd"), - labels.Not(labels.NewEqualMatcher("b", "abcde")), + labels.MustNewMatcher(labels.MatchEqual, "a", "abcd"), + labels.MustNewMatcher(labels.MatchNotEqual, "b", "abcde"), }, series: []labels.Labels{}, }, { selector: labels.Selector{ - labels.NewEqualMatcher("a", "abcd"), - labels.Not(labels.NewEqualMatcher("b", "abc")), + labels.MustNewMatcher(labels.MatchEqual, "a", "abcd"), + labels.MustNewMatcher(labels.MatchNotEqual, "b", "abc"), }, series: []labels.Labels{labelpairs[0]}, }, { selector: labels.Selector{ - labels.Not(labels.NewMustRegexpMatcher("a", "abd.*")), + labels.MustNewMatcher(labels.MatchNotRegexp, "a", "abd.*"), }, series: labelpairs, }, { selector: labels.Selector{ - labels.Not(labels.NewMustRegexpMatcher("a", "abc.*")), + labels.MustNewMatcher(labels.MatchNotRegexp, "a", "abc.*"), }, series: labelpairs[1:], }, { selector: labels.Selector{ - labels.Not(labels.NewMustRegexpMatcher("c", "abd.*")), + labels.MustNewMatcher(labels.MatchNotRegexp, "c", "abd.*"), }, series: labelpairs, }, { selector: labels.Selector{ - labels.Not(labels.NewMustRegexpMatcher("labelname", "labelvalue")), + labels.MustNewMatcher(labels.MatchNotRegexp, "labelname", "labelvalue"), }, series: labelpairs[:1], }} @@ -1605,7 +1605,7 @@ func TestNoEmptyBlocks(t *testing.T) { rangeToTriggerCompaction := db.opts.BlockRanges[0]/2*3 - 1 defaultLabel := labels.FromStrings("foo", "bar") - defaultMatcher := labels.NewMustRegexpMatcher("", ".*") + defaultMatcher := labels.MustNewMatcher(labels.MatchRegexp, "", ".*") t.Run("Test no blocks after compact with empty head.", func(t *testing.T) { testutil.Ok(t, db.compact()) @@ -1807,7 +1807,7 @@ func TestCorrectNumTombstones(t *testing.T) { blockRange := DefaultOptions.BlockRanges[0] defaultLabel := labels.FromStrings("foo", "bar") - defaultMatcher := labels.NewEqualMatcher(defaultLabel[0].Name, defaultLabel[0].Value) + defaultMatcher := labels.MustNewMatcher(labels.MatchEqual, defaultLabel[0].Name, defaultLabel[0].Value) app := db.Appender() for i := int64(0); i < 3; i++ { @@ -2152,7 +2152,7 @@ func TestVerticalCompaction(t *testing.T) { }, } - defaultMatcher := labels.NewMustRegexpMatcher("__name__", ".*") + defaultMatcher := labels.MustNewMatcher(labels.MatchRegexp, "__name__", ".*") for _, c := range cases { if ok := t.Run("", func(t *testing.T) { @@ -2311,7 +2311,7 @@ func TestDBReadOnly(t *testing.T) { expSeries map[string][]tsdbutil.Sample expSeriesCount int expDBHash []byte - matchAll = labels.NewEqualMatcher("", "") + matchAll = labels.MustNewMatcher(labels.MatchEqual, "", "") err error ) @@ -2465,7 +2465,7 @@ func TestDBReadOnly_FlushWAL(t *testing.T) { defer func() { testutil.Ok(t, querier.Close()) }() // Sum the values. - seriesSet, err := querier.Select(labels.NewEqualMatcher(defaultLabelName, "flush")) + seriesSet, err := querier.Select(labels.MustNewMatcher(labels.MatchEqual, defaultLabelName, "flush")) testutil.Ok(t, err) sum := 0.0 diff --git a/tsdb/head.go b/tsdb/head.go index ea4bde3cb3..34d40bb713 100644 --- a/tsdb/head.go +++ b/tsdb/head.go @@ -28,11 +28,11 @@ import ( "github.com/oklog/ulid" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/chunkenc" "github.com/prometheus/prometheus/tsdb/chunks" "github.com/prometheus/prometheus/tsdb/encoding" "github.com/prometheus/prometheus/tsdb/index" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/record" "github.com/prometheus/prometheus/tsdb/tombstones" "github.com/prometheus/prometheus/tsdb/wal" @@ -1047,7 +1047,7 @@ func (a *headAppender) Rollback() error { // Delete all samples in the range of [mint, maxt] for series that satisfy the given // label matchers. -func (h *Head) Delete(mint, maxt int64, ms ...labels.Matcher) error { +func (h *Head) Delete(mint, maxt int64, ms ...*labels.Matcher) error { // Do not delete anything beyond the currently valid range. mint, maxt = clampInterval(mint, maxt, h.MinTime(), h.MaxTime()) @@ -1516,7 +1516,7 @@ type seriesHashmap map[uint64][]*memSeries func (m seriesHashmap) get(hash uint64, lset labels.Labels) *memSeries { for _, s := range m[hash] { - if s.lset.Equals(lset) { + if labels.Equal(s.lset, lset) { return s } } @@ -1526,7 +1526,7 @@ func (m seriesHashmap) get(hash uint64, lset labels.Labels) *memSeries { func (m seriesHashmap) set(hash uint64, s *memSeries) { l := m[hash] for i, prev := range l { - if prev.lset.Equals(s.lset) { + if labels.Equal(prev.lset, s.lset) { l[i] = s return } @@ -1537,7 +1537,7 @@ func (m seriesHashmap) set(hash uint64, s *memSeries) { func (m seriesHashmap) del(hash uint64, lset labels.Labels) { var rem []*memSeries for _, s := range m[hash] { - if !s.lset.Equals(lset) { + if !labels.Equal(s.lset, lset) { rem = append(rem, s) } } diff --git a/tsdb/head_bench_test.go b/tsdb/head_bench_test.go index 85542d1efe..6fee2122fc 100644 --- a/tsdb/head_bench_test.go +++ b/tsdb/head_bench_test.go @@ -18,7 +18,7 @@ import ( "sync/atomic" "testing" - "github.com/prometheus/prometheus/tsdb/labels" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/util/testutil" ) @@ -74,39 +74,39 @@ func BenchmarkHeadPostingForMatchers(b *testing.B) { } } - n1 := labels.NewEqualMatcher("n", "1") + n1 := labels.MustNewMatcher(labels.MatchEqual, "n", "1") - jFoo := labels.NewEqualMatcher("j", "foo") - jNotFoo := labels.Not(jFoo) + jFoo := labels.MustNewMatcher(labels.MatchEqual, "j", "foo") + jNotFoo := labels.MustNewMatcher(labels.MatchNotEqual, "j", "foo") - iStar := labels.NewMustRegexpMatcher("i", "^.*$") - iPlus := labels.NewMustRegexpMatcher("i", "^.+$") - i1Plus := labels.NewMustRegexpMatcher("i", "^1.+$") - iEmptyRe := labels.NewMustRegexpMatcher("i", "^$") - iNotEmpty := labels.Not(labels.NewEqualMatcher("i", "")) - iNot2 := labels.Not(labels.NewEqualMatcher("n", "2")) - iNot2Star := labels.Not(labels.NewMustRegexpMatcher("i", "^2.*$")) + iStar := labels.MustNewMatcher(labels.MatchRegexp, "i", "^.*$") + iPlus := labels.MustNewMatcher(labels.MatchRegexp, "i", "^.+$") + i1Plus := labels.MustNewMatcher(labels.MatchRegexp, "i", "^1.+$") + iEmptyRe := labels.MustNewMatcher(labels.MatchRegexp, "i", "^$") + iNotEmpty := labels.MustNewMatcher(labels.MatchNotEqual, "i", "") + iNot2 := labels.MustNewMatcher(labels.MatchNotEqual, "n", "2") + iNot2Star := labels.MustNewMatcher(labels.MatchNotRegexp, "i", "^2.*$") cases := []struct { name string - matchers []labels.Matcher + matchers []*labels.Matcher }{ - {`n="1"`, []labels.Matcher{n1}}, - {`n="1",j="foo"`, []labels.Matcher{n1, jFoo}}, - {`j="foo",n="1"`, []labels.Matcher{jFoo, n1}}, - {`n="1",j!="foo"`, []labels.Matcher{n1, jNotFoo}}, - {`i=~".*"`, []labels.Matcher{iStar}}, - {`i=~".+"`, []labels.Matcher{iPlus}}, - {`i=~""`, []labels.Matcher{iEmptyRe}}, - {`i!=""`, []labels.Matcher{iNotEmpty}}, - {`n="1",i=~".*",j="foo"`, []labels.Matcher{n1, iStar, jFoo}}, - {`n="1",i=~".*",i!="2",j="foo"`, []labels.Matcher{n1, iStar, iNot2, jFoo}}, - {`n="1",i!=""`, []labels.Matcher{n1, iNotEmpty}}, - {`n="1",i!="",j="foo"`, []labels.Matcher{n1, iNotEmpty, jFoo}}, - {`n="1",i=~".+",j="foo"`, []labels.Matcher{n1, iPlus, jFoo}}, - {`n="1",i=~"1.+",j="foo"`, []labels.Matcher{n1, i1Plus, jFoo}}, - {`n="1",i=~".+",i!="2",j="foo"`, []labels.Matcher{n1, iPlus, iNot2, jFoo}}, - {`n="1",i=~".+",i!~"2.*",j="foo"`, []labels.Matcher{n1, iPlus, iNot2Star, jFoo}}, + {`n="1"`, []*labels.Matcher{n1}}, + {`n="1",j="foo"`, []*labels.Matcher{n1, jFoo}}, + {`j="foo",n="1"`, []*labels.Matcher{jFoo, n1}}, + {`n="1",j!="foo"`, []*labels.Matcher{n1, jNotFoo}}, + {`i=~".*"`, []*labels.Matcher{iStar}}, + {`i=~".+"`, []*labels.Matcher{iPlus}}, + {`i=~""`, []*labels.Matcher{iEmptyRe}}, + {`i!=""`, []*labels.Matcher{iNotEmpty}}, + {`n="1",i=~".*",j="foo"`, []*labels.Matcher{n1, iStar, jFoo}}, + {`n="1",i=~".*",i!="2",j="foo"`, []*labels.Matcher{n1, iStar, iNot2, jFoo}}, + {`n="1",i!=""`, []*labels.Matcher{n1, iNotEmpty}}, + {`n="1",i!="",j="foo"`, []*labels.Matcher{n1, iNotEmpty, jFoo}}, + {`n="1",i=~".+",j="foo"`, []*labels.Matcher{n1, iPlus, jFoo}}, + {`n="1",i=~"1.+",j="foo"`, []*labels.Matcher{n1, i1Plus, jFoo}}, + {`n="1",i=~".+",i!="2",j="foo"`, []*labels.Matcher{n1, iPlus, iNot2, jFoo}}, + {`n="1",i=~".+",i!~"2.*",j="foo"`, []*labels.Matcher{n1, iPlus, iNot2Star, jFoo}}, } for _, c := range cases { diff --git a/tsdb/head_test.go b/tsdb/head_test.go index 39350f08ff..9c042ed283 100644 --- a/tsdb/head_test.go +++ b/tsdb/head_test.go @@ -27,10 +27,10 @@ import ( "github.com/pkg/errors" prom_testutil "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/chunkenc" "github.com/prometheus/prometheus/tsdb/chunks" "github.com/prometheus/prometheus/tsdb/index" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/record" "github.com/prometheus/prometheus/tsdb/tombstones" "github.com/prometheus/prometheus/tsdb/tsdbutil" @@ -290,7 +290,7 @@ func TestHead_WALMultiRef(t *testing.T) { q, err := NewBlockQuerier(head, 0, 300) testutil.Ok(t, err) - series := query(t, q, labels.NewEqualMatcher("foo", "bar")) + series := query(t, q, labels.MustNewMatcher(labels.MatchEqual, "foo", "bar")) testutil.Equals(t, map[string][]tsdbutil.Sample{`{foo="bar"}`: {sample{100, 1}, sample{300, 2}}}, series) } @@ -437,7 +437,7 @@ func TestHeadDeleteSeriesWithoutSamples(t *testing.T) { testutil.Ok(t, head.Init(math.MinInt64)) - testutil.Ok(t, head.Delete(0, 100, labels.NewEqualMatcher("a", "1"))) + testutil.Ok(t, head.Delete(0, 100, labels.MustNewMatcher(labels.MatchEqual, "a", "1"))) }) } } @@ -507,7 +507,7 @@ func TestHeadDeleteSimple(t *testing.T) { // Delete the ranges. for _, r := range c.dranges { - testutil.Ok(t, head.Delete(r.Mint, r.Maxt, labels.NewEqualMatcher(lblDefault.Name, lblDefault.Value))) + testutil.Ok(t, head.Delete(r.Mint, r.Maxt, labels.MustNewMatcher(labels.MatchEqual, lblDefault.Name, lblDefault.Value))) } // Compare the samples for both heads - before and after the reload. @@ -522,7 +522,7 @@ func TestHeadDeleteSimple(t *testing.T) { indexr, err := h.Index() testutil.Ok(t, err) // Use an emptyTombstoneReader explicitly to get all the samples. - css, err := LookupChunkSeries(indexr, emptyTombstoneReader, labels.NewEqualMatcher(lblDefault.Name, lblDefault.Value)) + css, err := LookupChunkSeries(indexr, emptyTombstoneReader, labels.MustNewMatcher(labels.MatchEqual, lblDefault.Name, lblDefault.Value)) testutil.Ok(t, err) // Getting the actual samples. @@ -564,7 +564,7 @@ func TestHeadDeleteSimple(t *testing.T) { for _, h := range []*Head{head, reloadedHead} { q, err := NewBlockQuerier(h, h.MinTime(), h.MaxTime()) testutil.Ok(t, err) - actSeriesSet, err := q.Select(labels.NewEqualMatcher(lblDefault.Name, lblDefault.Value)) + actSeriesSet, err := q.Select(labels.MustNewMatcher(labels.MatchEqual, lblDefault.Name, lblDefault.Value)) testutil.Ok(t, err) lns, err := q.LabelNames() @@ -623,12 +623,12 @@ func TestDeleteUntilCurMax(t *testing.T) { testutil.Ok(t, err) } testutil.Ok(t, app.Commit()) - testutil.Ok(t, hb.Delete(0, 10000, labels.NewEqualMatcher("a", "b"))) + testutil.Ok(t, hb.Delete(0, 10000, labels.MustNewMatcher(labels.MatchEqual, "a", "b"))) // Test the series have been deleted. q, err := NewBlockQuerier(hb, 0, 100000) testutil.Ok(t, err) - res, err := q.Select(labels.NewEqualMatcher("a", "b")) + res, err := q.Select(labels.MustNewMatcher(labels.MatchEqual, "a", "b")) testutil.Ok(t, err) testutil.Assert(t, !res.Next(), "series didn't get deleted") @@ -639,7 +639,7 @@ func TestDeleteUntilCurMax(t *testing.T) { testutil.Ok(t, app.Commit()) q, err = NewBlockQuerier(hb, 0, 100000) testutil.Ok(t, err) - res, err = q.Select(labels.NewEqualMatcher("a", "b")) + res, err = q.Select(labels.MustNewMatcher(labels.MatchEqual, "a", "b")) testutil.Ok(t, err) testutil.Assert(t, res.Next(), "series don't exist") exps := res.At() @@ -669,7 +669,7 @@ func TestDeletedSamplesAndSeriesStillInWALAfterCheckpoint(t *testing.T) { testutil.Ok(t, err) testutil.Ok(t, app.Commit()) } - testutil.Ok(t, hb.Delete(0, int64(numSamples), labels.NewEqualMatcher("a", "b"))) + testutil.Ok(t, hb.Delete(0, int64(numSamples), labels.MustNewMatcher(labels.MatchEqual, "a", "b"))) testutil.Ok(t, hb.Truncate(1)) testutil.Ok(t, hb.Close()) @@ -774,25 +774,25 @@ func TestDelete_e2e(t *testing.T) { testutil.Ok(t, app.Commit()) // Delete a time-range from each-selector. dels := []struct { - ms []labels.Matcher + ms []*labels.Matcher drange tombstones.Intervals }{ { - ms: []labels.Matcher{labels.NewEqualMatcher("a", "b")}, + ms: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "a", "b")}, drange: tombstones.Intervals{{Mint: 300, Maxt: 500}, {Mint: 600, Maxt: 670}}, }, { - ms: []labels.Matcher{ - labels.NewEqualMatcher("a", "b"), - labels.NewEqualMatcher("job", "prom-k8s"), + ms: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "a", "b"), + labels.MustNewMatcher(labels.MatchEqual, "job", "prom-k8s"), }, drange: tombstones.Intervals{{Mint: 300, Maxt: 500}, {Mint: 100, Maxt: 670}}, }, { - ms: []labels.Matcher{ - labels.NewEqualMatcher("a", "c"), - labels.NewEqualMatcher("instance", "localhost:9090"), - labels.NewEqualMatcher("job", "prometheus"), + ms: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "a", "c"), + labels.MustNewMatcher(labels.MatchEqual, "instance", "localhost:9090"), + labels.MustNewMatcher(labels.MatchEqual, "job", "prometheus"), }, drange: tombstones.Intervals{{Mint: 300, Maxt: 400}, {Mint: 100, Maxt: 6700}}, }, @@ -1077,7 +1077,7 @@ func TestUncommittedSamplesNotLostOnTruncate(t *testing.T) { testutil.Ok(t, err) defer q.Close() - ss, err := q.Select(labels.NewEqualMatcher("a", "1")) + ss, err := q.Select(labels.MustNewMatcher(labels.MatchEqual, "a", "1")) testutil.Ok(t, err) testutil.Equals(t, true, ss.Next()) @@ -1104,7 +1104,7 @@ func TestRemoveSeriesAfterRollbackAndTruncate(t *testing.T) { testutil.Ok(t, err) defer q.Close() - ss, err := q.Select(labels.NewEqualMatcher("a", "1")) + ss, err := q.Select(labels.MustNewMatcher(labels.MatchEqual, "a", "1")) testutil.Ok(t, err) testutil.Equals(t, false, ss.Next()) diff --git a/tsdb/index/index.go b/tsdb/index/index.go index 48ab96ba76..ded55d6f37 100644 --- a/tsdb/index/index.go +++ b/tsdb/index/index.go @@ -27,11 +27,11 @@ import ( "strings" "github.com/pkg/errors" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/chunks" "github.com/prometheus/prometheus/tsdb/encoding" tsdb_errors "github.com/prometheus/prometheus/tsdb/errors" "github.com/prometheus/prometheus/tsdb/fileutil" - "github.com/prometheus/prometheus/tsdb/labels" ) const ( diff --git a/tsdb/index/index_test.go b/tsdb/index/index_test.go index cfb00c3338..947541bac1 100644 --- a/tsdb/index/index_test.go +++ b/tsdb/index/index_test.go @@ -22,10 +22,10 @@ import ( "testing" "github.com/pkg/errors" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/chunkenc" "github.com/prometheus/prometheus/tsdb/chunks" "github.com/prometheus/prometheus/tsdb/encoding" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/util/testutil" ) diff --git a/tsdb/index/postings.go b/tsdb/index/postings.go index 51bbd92647..44c9b4c609 100644 --- a/tsdb/index/postings.go +++ b/tsdb/index/postings.go @@ -21,7 +21,7 @@ import ( "strings" "sync" - "github.com/prometheus/prometheus/tsdb/labels" + "github.com/prometheus/prometheus/pkg/labels" ) var allPostingsKey = labels.Label{} diff --git a/tsdb/index/postings_test.go b/tsdb/index/postings_test.go index 643d3254a9..d0da789d19 100644 --- a/tsdb/index/postings_test.go +++ b/tsdb/index/postings_test.go @@ -20,7 +20,7 @@ import ( "sort" "testing" - "github.com/prometheus/prometheus/tsdb/labels" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/util/testutil" ) diff --git a/tsdb/labels/labels.go b/tsdb/labels/labels.go deleted file mode 100644 index aab8e42be9..0000000000 --- a/tsdb/labels/labels.go +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2017 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package labels - -import ( - "bufio" - "bytes" - "os" - "sort" - "strconv" - "strings" - - "github.com/cespare/xxhash" - "github.com/pkg/errors" -) - -const sep = '\xff' - -// Label is a key/value pair of strings. -type Label struct { - Name, Value string -} - -// Labels is a sorted set of labels. Order has to be guaranteed upon -// instantiation. -type Labels []Label - -func (ls Labels) Len() int { return len(ls) } -func (ls Labels) Swap(i, j int) { ls[i], ls[j] = ls[j], ls[i] } -func (ls Labels) Less(i, j int) bool { return ls[i].Name < ls[j].Name } - -func (ls Labels) String() string { - var b bytes.Buffer - - b.WriteByte('{') - for i, l := range ls { - if i > 0 { - b.WriteByte(',') - } - b.WriteString(l.Name) - b.WriteByte('=') - b.WriteString(strconv.Quote(l.Value)) - } - b.WriteByte('}') - - return b.String() -} - -// Hash returns a hash value for the label set. -func (ls Labels) Hash() uint64 { - b := make([]byte, 0, 1024) - - for _, v := range ls { - b = append(b, v.Name...) - b = append(b, sep) - b = append(b, v.Value...) - b = append(b, sep) - } - return xxhash.Sum64(b) -} - -// Get returns the value for the label with the given name. -// Returns an empty string if the label doesn't exist. -func (ls Labels) Get(name string) string { - for _, l := range ls { - if l.Name == name { - return l.Value - } - } - return "" -} - -// Equals returns whether the two label sets are equal. -func (ls Labels) Equals(o Labels) bool { - if len(ls) != len(o) { - return false - } - for i, l := range ls { - if o[i] != l { - return false - } - } - return true -} - -// Map returns a string map of the labels. -func (ls Labels) Map() map[string]string { - m := make(map[string]string, len(ls)) - for _, l := range ls { - m[l.Name] = l.Value - } - return m -} - -// WithoutEmpty returns the labelset without empty labels. -// May return the same labelset. -func (ls Labels) WithoutEmpty() Labels { - for _, v := range ls { - if v.Value == "" { - els := make(Labels, 0, len(ls)-1) - for _, v := range ls { - if v.Value != "" { - els = append(els, v) - } - } - return els - } - } - return ls -} - -// New returns a sorted Labels from the given labels. -// The caller has to guarantee that all label names are unique. -func New(ls ...Label) Labels { - set := make(Labels, 0, len(ls)) - for _, l := range ls { - set = append(set, l) - } - sort.Sort(set) - - return set -} - -// FromMap returns new sorted Labels from the given map. -func FromMap(m map[string]string) Labels { - l := make(Labels, 0, len(m)) - for k, v := range m { - if v != "" { - l = append(l, Label{Name: k, Value: v}) - } - } - sort.Sort(l) - - return l -} - -// FromStrings creates new labels from pairs of strings. -func FromStrings(ss ...string) Labels { - if len(ss)%2 != 0 { - panic("invalid number of strings") - } - var res Labels - for i := 0; i < len(ss); i += 2 { - if ss[i+1] != "" { - res = append(res, Label{Name: ss[i], Value: ss[i+1]}) - } - } - - sort.Sort(res) - return res -} - -// Compare compares the two label sets. -// The result will be 0 if a==b, <0 if a < b, and >0 if a > b. -func Compare(a, b Labels) int { - l := len(a) - if len(b) < l { - l = len(b) - } - - for i := 0; i < l; i++ { - if d := strings.Compare(a[i].Name, b[i].Name); d != 0 { - return d - } - if d := strings.Compare(a[i].Value, b[i].Value); d != 0 { - return d - } - } - // If all labels so far were in common, the set with fewer labels comes first. - return len(a) - len(b) -} - -// Slice is a sortable slice of label sets. -type Slice []Labels - -func (s Slice) Len() int { return len(s) } -func (s Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s Slice) Less(i, j int) bool { return Compare(s[i], s[j]) < 0 } - -// ReadLabels reads up to n label sets in a JSON formatted file fn. It is mostly useful -// to load testing data. -func ReadLabels(fn string, n int) ([]Labels, error) { - f, err := os.Open(fn) - if err != nil { - return nil, err - } - defer f.Close() - - scanner := bufio.NewScanner(f) - - var mets []Labels - hashes := map[uint64]struct{}{} - i := 0 - - for scanner.Scan() && i < n { - m := make(Labels, 0, 10) - - r := strings.NewReplacer("\"", "", "{", "", "}", "") - s := r.Replace(scanner.Text()) - - labelChunks := strings.Split(s, ",") - for _, labelChunk := range labelChunks { - split := strings.Split(labelChunk, ":") - m = append(m, Label{Name: split[0], Value: split[1]}) - } - // Order of the k/v labels matters, don't assume we'll always receive them already sorted. - sort.Sort(m) - - h := m.Hash() - if _, ok := hashes[h]; ok { - continue - } - mets = append(mets, m) - hashes[h] = struct{}{} - i++ - } - - if i != n { - return mets, errors.Errorf("requested %d metrics but found %d", n, i) - } - return mets, nil -} diff --git a/tsdb/labels/labels_test.go b/tsdb/labels/labels_test.go deleted file mode 100644 index c2599781e1..0000000000 --- a/tsdb/labels/labels_test.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2017 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package labels - -import ( - "fmt" - "math/rand" - "path/filepath" - "sort" - "testing" - - "github.com/prometheus/prometheus/util/testutil" -) - -func TestCompareAndEquals(t *testing.T) { - cases := []struct { - a, b []Label - res int - }{ - { - a: []Label{}, - b: []Label{}, - res: 0, - }, - { - a: []Label{{"a", ""}}, - b: []Label{{"a", ""}, {"b", ""}}, - res: -1, - }, - { - a: []Label{{"a", ""}}, - b: []Label{{"a", ""}}, - res: 0, - }, - { - a: []Label{{"aa", ""}, {"aa", ""}}, - b: []Label{{"aa", ""}, {"ab", ""}}, - res: -1, - }, - { - a: []Label{{"aa", ""}, {"abb", ""}}, - b: []Label{{"aa", ""}, {"ab", ""}}, - res: 1, - }, - { - a: []Label{ - {"__name__", "go_gc_duration_seconds"}, - {"job", "prometheus"}, - {"quantile", "0.75"}, - }, - b: []Label{ - {"__name__", "go_gc_duration_seconds"}, - {"job", "prometheus"}, - {"quantile", "1"}, - }, - res: -1, - }, - { - a: []Label{ - {"handler", "prometheus"}, - {"instance", "localhost:9090"}, - }, - b: []Label{ - {"handler", "query"}, - {"instance", "localhost:9090"}, - }, - res: -1, - }, - } - for _, c := range cases { - // Use constructor to ensure sortedness. - a, b := New(c.a...), New(c.b...) - - testutil.Equals(t, c.res, Compare(a, b)) - testutil.Equals(t, c.res == 0, a.Equals(b)) - } -} - -func BenchmarkSliceSort(b *testing.B) { - lbls, err := ReadLabels(filepath.Join("..", "testdata", "20kseries.json"), 20000) - testutil.Ok(b, err) - - for len(lbls) < 20e6 { - lbls = append(lbls, lbls...) - } - for i := range lbls { - j := rand.Intn(i + 1) - lbls[i], lbls[j] = lbls[j], lbls[i] - } - - for _, k := range []int{ - 100, 5000, 50000, 300000, 900000, 5e6, 20e6, - } { - b.Run(fmt.Sprintf("%d", k), func(b *testing.B) { - b.ReportAllocs() - - for a := 0; a < b.N; a++ { - b.StopTimer() - cl := make(Slice, k) - copy(cl, Slice(lbls[:k])) - b.StartTimer() - - sort.Sort(cl) - } - }) - } -} - -func BenchmarkLabelSetFromMap(b *testing.B) { - m := map[string]string{ - "job": "node", - "instance": "123.123.1.211:9090", - "path": "/api/v1/namespaces//deployments/", - "method": "GET", - "namespace": "system", - "status": "500", - } - var ls Labels - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - ls = FromMap(m) - } - _ = ls -} - -func BenchmarkMapFromLabels(b *testing.B) { - m := map[string]string{ - "job": "node", - "instance": "123.123.1.211:9090", - "path": "/api/v1/namespaces//deployments/", - "method": "GET", - "namespace": "system", - "status": "500", - } - ls := FromMap(m) - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - _ = ls.Map() - } -} - -func BenchmarkLabelSetEquals(b *testing.B) { - // The vast majority of comparisons will be against a matching label set. - m := map[string]string{ - "job": "node", - "instance": "123.123.1.211:9090", - "path": "/api/v1/namespaces//deployments/", - "method": "GET", - "namespace": "system", - "status": "500", - } - ls := FromMap(m) - var res bool - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - res = ls.Equals(ls) - } - _ = res -} - -func BenchmarkLabelSetHash(b *testing.B) { - // The vast majority of comparisons will be against a matching label set. - m := map[string]string{ - "job": "node", - "instance": "123.123.1.211:9090", - "path": "/api/v1/namespaces//deployments/", - "method": "GET", - "namespace": "system", - "status": "500", - } - ls := FromMap(m) - var res uint64 - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - res += ls.Hash() - } - fmt.Println(res) -} diff --git a/tsdb/labels/selector.go b/tsdb/labels/selector.go deleted file mode 100644 index c94ebb3321..0000000000 --- a/tsdb/labels/selector.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2017 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package labels - -import ( - "fmt" - "regexp" -) - -// Selector holds constraints for matching against a label set. -type Selector []Matcher - -// Matches returns whether the labels satisfy all matchers. -func (s Selector) Matches(labels Labels) bool { - for _, m := range s { - if v := labels.Get(m.Name()); !m.Matches(v) { - return false - } - } - return true -} - -// Matcher specifies a constraint for the value of a label. -type Matcher interface { - // Name returns the label name the matcher should apply to. - Name() string - // Matches checks whether a value fulfills the constraints. - Matches(v string) bool - // String returns a human readable matcher. - String() string -} - -// EqualMatcher matches on equality. -type EqualMatcher struct { - name, value string -} - -// Name implements Matcher interface. -func (m EqualMatcher) Name() string { return m.name } - -// Matches implements Matcher interface. -func (m EqualMatcher) Matches(v string) bool { return v == m.value } - -// String implements Matcher interface. -func (m EqualMatcher) String() string { return fmt.Sprintf("%s=%q", m.name, m.value) } - -// Value returns the matched value. -func (m EqualMatcher) Value() string { return m.value } - -// NewEqualMatcher returns a new matcher matching an exact label value. -func NewEqualMatcher(name, value string) Matcher { - return &EqualMatcher{name: name, value: value} -} - -type RegexpMatcher struct { - name string - re *regexp.Regexp -} - -func (m RegexpMatcher) Name() string { return m.name } -func (m RegexpMatcher) Matches(v string) bool { return m.re.MatchString(v) } -func (m RegexpMatcher) String() string { return fmt.Sprintf("%s=~%q", m.name, m.re.String()) } -func (m RegexpMatcher) Value() string { return m.re.String() } - -// NewRegexpMatcher returns a new matcher verifying that a value matches -// the regular expression pattern. -func NewRegexpMatcher(name, pattern string) (Matcher, error) { - re, err := regexp.Compile(pattern) - if err != nil { - return nil, err - } - return &RegexpMatcher{name: name, re: re}, nil -} - -// NewMustRegexpMatcher returns a new matcher verifying that a value matches -// the regular expression pattern. Will panic if the pattern is not a valid -// regular expression. -func NewMustRegexpMatcher(name, pattern string) Matcher { - re, err := regexp.Compile(pattern) - if err != nil { - panic(err) - } - return &RegexpMatcher{name: name, re: re} - -} - -// NotMatcher inverts the matching result for a matcher. -type NotMatcher struct { - Matcher -} - -func (m NotMatcher) Matches(v string) bool { return !m.Matcher.Matches(v) } -func (m NotMatcher) String() string { return fmt.Sprintf("not(%s)", m.Matcher.String()) } - -// Not inverts the matcher's matching result. -func Not(m Matcher) Matcher { - return &NotMatcher{m} -} diff --git a/tsdb/mocks_test.go b/tsdb/mocks_test.go index fa46420547..d9b1056563 100644 --- a/tsdb/mocks_test.go +++ b/tsdb/mocks_test.go @@ -14,10 +14,10 @@ package tsdb import ( + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/chunkenc" "github.com/prometheus/prometheus/tsdb/chunks" "github.com/prometheus/prometheus/tsdb/index" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/tombstones" ) @@ -29,7 +29,7 @@ func (mockIndexWriter) AddSymbols(sym map[string]struct{}) error { return nil } func (m *mockIndexWriter) AddSeries(ref uint64, l labels.Labels, chunks ...chunks.Meta) error { i := -1 for j, s := range m.series { - if !labels.FromMap(s.lset).Equals(l) { + if !labels.Equal(labels.FromMap(s.lset), l) { continue } i = j diff --git a/tsdb/querier.go b/tsdb/querier.go index 4672cba9b3..59ffdaa85b 100644 --- a/tsdb/querier.go +++ b/tsdb/querier.go @@ -20,11 +20,11 @@ import ( "unicode/utf8" "github.com/pkg/errors" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/chunkenc" "github.com/prometheus/prometheus/tsdb/chunks" tsdb_errors "github.com/prometheus/prometheus/tsdb/errors" "github.com/prometheus/prometheus/tsdb/index" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/tombstones" ) @@ -32,7 +32,7 @@ import ( // time range. type Querier interface { // Select returns a set of series that matches the given label matchers. - Select(...labels.Matcher) (SeriesSet, error) + Select(...*labels.Matcher) (SeriesSet, error) // LabelValues returns all potential values for a label name. LabelValues(string) ([]string, error) @@ -112,7 +112,7 @@ func (q *querier) LabelValuesFor(string, labels.Label) ([]string, error) { return nil, fmt.Errorf("not implemented") } -func (q *querier) Select(ms ...labels.Matcher) (SeriesSet, error) { +func (q *querier) Select(ms ...*labels.Matcher) (SeriesSet, error) { if len(q.blocks) == 0 { return EmptySeriesSet(), nil } @@ -145,11 +145,11 @@ type verticalQuerier struct { querier } -func (q *verticalQuerier) Select(ms ...labels.Matcher) (SeriesSet, error) { +func (q *verticalQuerier) Select(ms ...*labels.Matcher) (SeriesSet, error) { return q.sel(q.blocks, ms) } -func (q *verticalQuerier) sel(qs []Querier, ms []labels.Matcher) (SeriesSet, error) { +func (q *verticalQuerier) sel(qs []Querier, ms []*labels.Matcher) (SeriesSet, error) { if len(qs) == 0 { return EmptySeriesSet(), nil } @@ -206,7 +206,7 @@ type blockQuerier struct { mint, maxt int64 } -func (q *blockQuerier) Select(ms ...labels.Matcher) (SeriesSet, error) { +func (q *blockQuerier) Select(ms ...*labels.Matcher) (SeriesSet, error) { base, err := LookupChunkSeries(q.index, q.tombstones, ms...) if err != nil { return nil, err @@ -320,26 +320,31 @@ func findSetMatches(pattern string) []string { // PostingsForMatchers assembles a single postings iterator against the index reader // based on the given matchers. -func PostingsForMatchers(ix IndexReader, ms ...labels.Matcher) (index.Postings, error) { +func PostingsForMatchers(ix IndexReader, ms ...*labels.Matcher) (index.Postings, error) { var its, notIts []index.Postings // See which label must be non-empty. // Optimization for case like {l=~".", l!="1"}. labelMustBeSet := make(map[string]bool, len(ms)) for _, m := range ms { if !m.Matches("") { - labelMustBeSet[m.Name()] = true + labelMustBeSet[m.Name] = true } } for _, m := range ms { - if labelMustBeSet[m.Name()] { + if labelMustBeSet[m.Name] { // If this matcher must be non-empty, we can be smarter. matchesEmpty := m.Matches("") - nm, isNot := m.(*labels.NotMatcher) + isNot := m.Type == labels.MatchNotEqual || m.Type == labels.MatchNotRegexp if isNot && matchesEmpty { // l!="foo" // If the label can't be empty and is a Not and the inner matcher // doesn't match empty, then subtract it out at the end. - it, err := postingsForMatcher(ix, nm.Matcher) + inverse, err := m.Inverse() + if err != nil { + return nil, err + } + + it, err := postingsForMatcher(ix, inverse) if err != nil { return nil, err } @@ -347,7 +352,12 @@ func PostingsForMatchers(ix IndexReader, ms ...labels.Matcher) (index.Postings, } else if isNot && !matchesEmpty { // l!="" // If the label can't be empty and is a Not, but the inner matcher can // be empty we need to use inversePostingsForMatcher. - it, err := inversePostingsForMatcher(ix, nm.Matcher) + inverse, err := m.Inverse() + if err != nil { + return nil, err + } + + it, err := inversePostingsForMatcher(ix, inverse) if err != nil { return nil, err } @@ -391,23 +401,23 @@ func PostingsForMatchers(ix IndexReader, ms ...labels.Matcher) (index.Postings, return ix.SortedPostings(it), nil } -func postingsForMatcher(ix IndexReader, m labels.Matcher) (index.Postings, error) { +func postingsForMatcher(ix IndexReader, m *labels.Matcher) (index.Postings, error) { // This method will not return postings for missing labels. // Fast-path for equal matching. - if em, ok := m.(*labels.EqualMatcher); ok { - return ix.Postings(em.Name(), em.Value()) + if m.Type == labels.MatchEqual { + return ix.Postings(m.Name, m.Value) } // Fast-path for set matching. - if em, ok := m.(*labels.RegexpMatcher); ok { - setMatches := findSetMatches(em.Value()) + if m.Type == labels.MatchRegexp { + setMatches := findSetMatches(m.Value) if len(setMatches) > 0 { - return postingsForSetMatcher(ix, em.Name(), setMatches) + return postingsForSetMatcher(ix, m.Name, setMatches) } } - tpls, err := ix.LabelValues(m.Name()) + tpls, err := ix.LabelValues(m.Name) if err != nil { return nil, err } @@ -430,7 +440,7 @@ func postingsForMatcher(ix IndexReader, m labels.Matcher) (index.Postings, error var rit []index.Postings for _, v := range res { - it, err := ix.Postings(m.Name(), v) + it, err := ix.Postings(m.Name, v) if err != nil { return nil, err } @@ -441,8 +451,8 @@ func postingsForMatcher(ix IndexReader, m labels.Matcher) (index.Postings, error } // inversePostingsForMatcher returns the postings for the series with the label name set but not matching the matcher. -func inversePostingsForMatcher(ix IndexReader, m labels.Matcher) (index.Postings, error) { - tpls, err := ix.LabelValues(m.Name()) +func inversePostingsForMatcher(ix IndexReader, m *labels.Matcher) (index.Postings, error) { + tpls, err := ix.LabelValues(m.Name) if err != nil { return nil, err } @@ -461,7 +471,7 @@ func inversePostingsForMatcher(ix IndexReader, m labels.Matcher) (index.Postings var rit []index.Postings for _, v := range res { - it, err := ix.Postings(m.Name(), v) + it, err := ix.Postings(m.Name, v) if err != nil { return nil, err } @@ -737,7 +747,7 @@ type baseChunkSeries struct { // LookupChunkSeries retrieves all series for the given matchers and returns a ChunkSeriesSet // over them. It drops chunks based on tombstones in the given reader. -func LookupChunkSeries(ir IndexReader, tr tombstones.Reader, ms ...labels.Matcher) (ChunkSeriesSet, error) { +func LookupChunkSeries(ir IndexReader, tr tombstones.Reader, ms ...*labels.Matcher) (ChunkSeriesSet, error) { if tr == nil { tr = tombstones.NewMemTombstones() } diff --git a/tsdb/querier_test.go b/tsdb/querier_test.go index e1cda90157..0029c60c02 100644 --- a/tsdb/querier_test.go +++ b/tsdb/querier_test.go @@ -25,10 +25,10 @@ import ( "testing" "github.com/pkg/errors" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/chunkenc" "github.com/prometheus/prometheus/tsdb/chunks" "github.com/prometheus/prometheus/tsdb/index" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/tombstones" "github.com/prometheus/prometheus/tsdb/tsdbutil" "github.com/prometheus/prometheus/util/testutil" @@ -271,7 +271,7 @@ func TestBlockQuerier(t *testing.T) { type query struct { mint, maxt int64 - ms []labels.Matcher + ms []*labels.Matcher exp SeriesSet } @@ -327,25 +327,25 @@ func TestBlockQuerier(t *testing.T) { { mint: 0, maxt: 0, - ms: []labels.Matcher{}, + ms: []*labels.Matcher{}, exp: newMockSeriesSet([]Series{}), }, { mint: 0, maxt: 0, - ms: []labels.Matcher{labels.NewEqualMatcher("a", "a")}, + ms: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "a", "a")}, exp: newMockSeriesSet([]Series{}), }, { mint: 1, maxt: 0, - ms: []labels.Matcher{labels.NewEqualMatcher("a", "a")}, + ms: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "a", "a")}, exp: newMockSeriesSet([]Series{}), }, { mint: 2, maxt: 6, - ms: []labels.Matcher{labels.NewEqualMatcher("a", "a")}, + ms: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "a", "a")}, exp: newMockSeriesSet([]Series{ newSeries(map[string]string{ "a": "a", @@ -409,7 +409,7 @@ func TestBlockQuerierDelete(t *testing.T) { type query struct { mint, maxt int64 - ms []labels.Matcher + ms []*labels.Matcher exp SeriesSet } @@ -470,7 +470,7 @@ func TestBlockQuerierDelete(t *testing.T) { { mint: 2, maxt: 7, - ms: []labels.Matcher{labels.NewEqualMatcher("a", "a")}, + ms: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "a", "a")}, exp: newMockSeriesSet([]Series{ newSeries(map[string]string{ "a": "a", @@ -488,7 +488,7 @@ func TestBlockQuerierDelete(t *testing.T) { { mint: 2, maxt: 7, - ms: []labels.Matcher{labels.NewEqualMatcher("b", "b")}, + ms: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "b", "b")}, exp: newMockSeriesSet([]Series{ newSeries(map[string]string{ "a": "a", @@ -506,7 +506,7 @@ func TestBlockQuerierDelete(t *testing.T) { { mint: 1, maxt: 4, - ms: []labels.Matcher{labels.NewEqualMatcher("a", "a")}, + ms: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "a", "a")}, exp: newMockSeriesSet([]Series{ newSeries(map[string]string{ "a": "a", @@ -519,7 +519,7 @@ func TestBlockQuerierDelete(t *testing.T) { { mint: 1, maxt: 3, - ms: []labels.Matcher{labels.NewEqualMatcher("a", "a")}, + ms: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "a", "a")}, exp: newMockSeriesSet([]Series{}), }, }, @@ -1539,7 +1539,7 @@ func BenchmarkQueryIterator(b *testing.B) { } defer sq.Close() - benchQuery(b, c.numSeries, sq, labels.Selector{labels.NewMustRegexpMatcher("__name__", ".*")}) + benchQuery(b, c.numSeries, sq, labels.Selector{labels.MustNewMatcher(labels.MatchRegexp, "__name__", ".*")}) }) } } @@ -1619,7 +1619,7 @@ func BenchmarkQuerySeek(b *testing.B) { b.ResetTimer() b.ReportAllocs() - ss, err := sq.Select(labels.NewMustRegexpMatcher("__name__", ".*")) + ss, err := sq.Select(labels.MustNewMatcher(labels.MatchRegexp, "__name__", ".*")) for ss.Next() { it := ss.At().Iterator() for t := mint; t <= maxt; t++ { @@ -1756,7 +1756,7 @@ func BenchmarkSetMatcher(b *testing.B) { b.ResetTimer() b.ReportAllocs() for n := 0; n < b.N; n++ { - _, err := que.Select(labels.NewMustRegexpMatcher("test", c.pattern)) + _, err := que.Select(labels.MustNewMatcher(labels.MatchRegexp, "test", c.pattern)) testutil.Ok(b, err) } @@ -1836,12 +1836,12 @@ func TestPostingsForMatchers(t *testing.T) { testutil.Ok(t, app.Commit()) cases := []struct { - matchers []labels.Matcher + matchers []*labels.Matcher exp []labels.Labels }{ // Simple equals. { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1")}, exp: []labels.Labels{ labels.FromStrings("n", "1"), labels.FromStrings("n", "1", "i", "a"), @@ -1849,17 +1849,17 @@ func TestPostingsForMatchers(t *testing.T) { }, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.NewEqualMatcher("i", "a")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchEqual, "i", "a")}, exp: []labels.Labels{ labels.FromStrings("n", "1", "i", "a"), }, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.NewEqualMatcher("i", "missing")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchEqual, "i", "missing")}, exp: []labels.Labels{}, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("missing", "")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "missing", "")}, exp: []labels.Labels{ labels.FromStrings("n", "1"), labels.FromStrings("n", "1", "i", "a"), @@ -1870,32 +1870,32 @@ func TestPostingsForMatchers(t *testing.T) { }, // Not equals. { - matchers: []labels.Matcher{labels.Not(labels.NewEqualMatcher("n", "1"))}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchNotEqual, "n", "1")}, exp: []labels.Labels{ labels.FromStrings("n", "2"), labels.FromStrings("n", "2.5"), }, }, { - matchers: []labels.Matcher{labels.Not(labels.NewEqualMatcher("i", ""))}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchNotEqual, "i", "")}, exp: []labels.Labels{ labels.FromStrings("n", "1", "i", "a"), labels.FromStrings("n", "1", "i", "b"), }, }, { - matchers: []labels.Matcher{labels.Not(labels.NewEqualMatcher("missing", ""))}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchNotEqual, "missing", "")}, exp: []labels.Labels{}, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.Not(labels.NewEqualMatcher("i", "a"))}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchNotEqual, "i", "a")}, exp: []labels.Labels{ labels.FromStrings("n", "1"), labels.FromStrings("n", "1", "i", "b"), }, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.Not(labels.NewEqualMatcher("i", ""))}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchNotEqual, "i", "")}, exp: []labels.Labels{ labels.FromStrings("n", "1", "i", "a"), labels.FromStrings("n", "1", "i", "b"), @@ -1903,7 +1903,7 @@ func TestPostingsForMatchers(t *testing.T) { }, // Regex. { - matchers: []labels.Matcher{labels.NewMustRegexpMatcher("n", "^1$")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchRegexp, "n", "^1$")}, exp: []labels.Labels{ labels.FromStrings("n", "1"), labels.FromStrings("n", "1", "i", "a"), @@ -1911,20 +1911,20 @@ func TestPostingsForMatchers(t *testing.T) { }, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.NewMustRegexpMatcher("i", "^a$")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchRegexp, "i", "^a$")}, exp: []labels.Labels{ labels.FromStrings("n", "1", "i", "a"), }, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.NewMustRegexpMatcher("i", "^a?$")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchRegexp, "i", "^a?$")}, exp: []labels.Labels{ labels.FromStrings("n", "1"), labels.FromStrings("n", "1", "i", "a"), }, }, { - matchers: []labels.Matcher{labels.NewMustRegexpMatcher("i", "^$")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchRegexp, "i", "^$")}, exp: []labels.Labels{ labels.FromStrings("n", "1"), labels.FromStrings("n", "2"), @@ -1932,13 +1932,13 @@ func TestPostingsForMatchers(t *testing.T) { }, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.NewMustRegexpMatcher("i", "^$")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchRegexp, "i", "^$")}, exp: []labels.Labels{ labels.FromStrings("n", "1"), }, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.NewMustRegexpMatcher("i", "^.*$")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchRegexp, "i", "^.*$")}, exp: []labels.Labels{ labels.FromStrings("n", "1"), labels.FromStrings("n", "1", "i", "a"), @@ -1946,7 +1946,7 @@ func TestPostingsForMatchers(t *testing.T) { }, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.NewMustRegexpMatcher("i", "^.+$")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchRegexp, "i", "^.+$")}, exp: []labels.Labels{ labels.FromStrings("n", "1", "i", "a"), labels.FromStrings("n", "1", "i", "b"), @@ -1954,51 +1954,51 @@ func TestPostingsForMatchers(t *testing.T) { }, // Not regex. { - matchers: []labels.Matcher{labels.Not(labels.NewMustRegexpMatcher("n", "^1$"))}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchNotRegexp, "n", "^1$")}, exp: []labels.Labels{ labels.FromStrings("n", "2"), labels.FromStrings("n", "2.5"), }, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.Not(labels.NewMustRegexpMatcher("i", "^a$"))}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchNotRegexp, "i", "^a$")}, exp: []labels.Labels{ labels.FromStrings("n", "1"), labels.FromStrings("n", "1", "i", "b"), }, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.Not(labels.NewMustRegexpMatcher("i", "^a?$"))}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchNotRegexp, "i", "^a?$")}, exp: []labels.Labels{ labels.FromStrings("n", "1", "i", "b"), }, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.Not(labels.NewMustRegexpMatcher("i", "^$"))}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchNotRegexp, "i", "^$")}, exp: []labels.Labels{ labels.FromStrings("n", "1", "i", "a"), labels.FromStrings("n", "1", "i", "b"), }, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.Not(labels.NewMustRegexpMatcher("i", "^.*$"))}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchNotRegexp, "i", "^.*$")}, exp: []labels.Labels{}, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.Not(labels.NewMustRegexpMatcher("i", "^.+$"))}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchNotRegexp, "i", "^.+$")}, exp: []labels.Labels{ labels.FromStrings("n", "1"), }, }, // Combinations. { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.Not(labels.NewEqualMatcher("i", "")), labels.NewEqualMatcher("i", "a")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchNotEqual, "i", ""), labels.MustNewMatcher(labels.MatchEqual, "i", "a")}, exp: []labels.Labels{ labels.FromStrings("n", "1", "i", "a"), }, }, { - matchers: []labels.Matcher{labels.NewEqualMatcher("n", "1"), labels.Not(labels.NewEqualMatcher("i", "b")), labels.NewMustRegexpMatcher("i", "^(b|a).*$")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "n", "1"), labels.MustNewMatcher(labels.MatchNotEqual, "i", "b"), labels.MustNewMatcher(labels.MatchRegexp, "i", "^(b|a).*$")}, exp: []labels.Labels{ labels.FromStrings("n", "1", "i", "a"), }, @@ -2006,7 +2006,7 @@ func TestPostingsForMatchers(t *testing.T) { // Set optimization for Regex. // Refer to https://github.com/prometheus/prometheus/issues/2651. { - matchers: []labels.Matcher{labels.NewMustRegexpMatcher("n", "^(?:1|2)$")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchRegexp, "n", "^(?:1|2)$")}, exp: []labels.Labels{ labels.FromStrings("n", "1"), labels.FromStrings("n", "1", "i", "a"), @@ -2015,20 +2015,20 @@ func TestPostingsForMatchers(t *testing.T) { }, }, { - matchers: []labels.Matcher{labels.NewMustRegexpMatcher("i", "^(?:a|b)$")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchRegexp, "i", "^(?:a|b)$")}, exp: []labels.Labels{ labels.FromStrings("n", "1", "i", "a"), labels.FromStrings("n", "1", "i", "b"), }, }, { - matchers: []labels.Matcher{labels.NewMustRegexpMatcher("n", "^(?:x1|2)$")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchRegexp, "n", "^(?:x1|2)$")}, exp: []labels.Labels{ labels.FromStrings("n", "2"), }, }, { - matchers: []labels.Matcher{labels.NewMustRegexpMatcher("n", "^(?:2|2\\.5)$")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchRegexp, "n", "^(?:2|2\\.5)$")}, exp: []labels.Labels{ labels.FromStrings("n", "2"), labels.FromStrings("n", "2.5"), @@ -2036,7 +2036,7 @@ func TestPostingsForMatchers(t *testing.T) { }, // Empty value. { - matchers: []labels.Matcher{labels.NewMustRegexpMatcher("i", "^(?:c||d)$")}, + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchRegexp, "i", "^(?:c||d)$")}, exp: []labels.Labels{ labels.FromStrings("n", "1"), labels.FromStrings("n", "2"), @@ -2103,29 +2103,29 @@ func TestClose(t *testing.T) { func BenchmarkQueries(b *testing.B) { cases := map[string]labels.Selector{ "Eq Matcher: Expansion - 1": { - labels.NewEqualMatcher("la", "va"), + labels.MustNewMatcher(labels.MatchEqual, "la", "va"), }, "Eq Matcher: Expansion - 2": { - labels.NewEqualMatcher("la", "va"), - labels.NewEqualMatcher("lb", "vb"), + labels.MustNewMatcher(labels.MatchEqual, "la", "va"), + labels.MustNewMatcher(labels.MatchEqual, "lb", "vb"), }, "Eq Matcher: Expansion - 3": { - labels.NewEqualMatcher("la", "va"), - labels.NewEqualMatcher("lb", "vb"), - labels.NewEqualMatcher("lc", "vc"), + labels.MustNewMatcher(labels.MatchEqual, "la", "va"), + labels.MustNewMatcher(labels.MatchEqual, "lb", "vb"), + labels.MustNewMatcher(labels.MatchEqual, "lc", "vc"), }, "Regex Matcher: Expansion - 1": { - labels.NewMustRegexpMatcher("la", ".*va"), + labels.MustNewMatcher(labels.MatchRegexp, "la", ".*va"), }, "Regex Matcher: Expansion - 2": { - labels.NewMustRegexpMatcher("la", ".*va"), - labels.NewMustRegexpMatcher("lb", ".*vb"), + labels.MustNewMatcher(labels.MatchRegexp, "la", ".*va"), + labels.MustNewMatcher(labels.MatchRegexp, "lb", ".*vb"), }, "Regex Matcher: Expansion - 3": { - labels.NewMustRegexpMatcher("la", ".*va"), - labels.NewMustRegexpMatcher("lb", ".*vb"), - labels.NewMustRegexpMatcher("lc", ".*vc"), + labels.MustNewMatcher(labels.MatchRegexp, "la", ".*va"), + labels.MustNewMatcher(labels.MatchRegexp, "lb", ".*vb"), + labels.MustNewMatcher(labels.MatchRegexp, "lc", ".*vc"), }, } @@ -2154,11 +2154,11 @@ func BenchmarkQueries(b *testing.B) { { var commonLbls labels.Labels for _, selector := range selectors { - switch sel := selector.(type) { - case *labels.EqualMatcher: - commonLbls = append(commonLbls, labels.Label{Name: sel.Name(), Value: sel.Value()}) - case *labels.RegexpMatcher: - commonLbls = append(commonLbls, labels.Label{Name: sel.Name(), Value: sel.Value()}) + switch selector.Type { + case labels.MatchEqual: + commonLbls = append(commonLbls, labels.Label{Name: selector.Name, Value: selector.Value}) + case labels.MatchRegexp: + commonLbls = append(commonLbls, labels.Label{Name: selector.Name, Value: selector.Value}) } } for i := range commonLbls { diff --git a/tsdb/record/record.go b/tsdb/record/record.go index 87b1c83784..d63198f977 100644 --- a/tsdb/record/record.go +++ b/tsdb/record/record.go @@ -19,8 +19,8 @@ import ( "sort" "github.com/pkg/errors" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/encoding" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/tombstones" ) diff --git a/tsdb/record/record_test.go b/tsdb/record/record_test.go index feed8069d3..1203609ae1 100644 --- a/tsdb/record/record_test.go +++ b/tsdb/record/record_test.go @@ -18,8 +18,8 @@ import ( "testing" "github.com/pkg/errors" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/encoding" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/tombstones" "github.com/prometheus/prometheus/util/testutil" ) diff --git a/tsdb/repair_test.go b/tsdb/repair_test.go index a40baf3005..596e357eb9 100644 --- a/tsdb/repair_test.go +++ b/tsdb/repair_test.go @@ -18,10 +18,10 @@ import ( "path/filepath" "testing" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/chunks" "github.com/prometheus/prometheus/tsdb/fileutil" "github.com/prometheus/prometheus/tsdb/index" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/util/testutil" ) diff --git a/tsdb/test/labels_test.go b/tsdb/test/labels_test.go index c8a246c228..07242181da 100644 --- a/tsdb/test/labels_test.go +++ b/tsdb/test/labels_test.go @@ -18,7 +18,7 @@ import ( "crypto/rand" "testing" - "github.com/prometheus/prometheus/tsdb/labels" + "github.com/prometheus/prometheus/pkg/labels" ) func BenchmarkMapClone(b *testing.B) { diff --git a/tsdb/wal.go b/tsdb/wal.go index da11e4198f..17f8963b7e 100644 --- a/tsdb/wal.go +++ b/tsdb/wal.go @@ -31,9 +31,9 @@ import ( "github.com/go-kit/kit/log/level" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/encoding" "github.com/prometheus/prometheus/tsdb/fileutil" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/record" "github.com/prometheus/prometheus/tsdb/tombstones" "github.com/prometheus/prometheus/tsdb/wal" diff --git a/tsdb/wal/checkpoint_test.go b/tsdb/wal/checkpoint_test.go index c8542781dd..48ae842367 100644 --- a/tsdb/wal/checkpoint_test.go +++ b/tsdb/wal/checkpoint_test.go @@ -23,8 +23,8 @@ import ( "testing" "github.com/pkg/errors" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/fileutil" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/record" "github.com/prometheus/prometheus/util/testutil" ) diff --git a/tsdb/wal/watcher_test.go b/tsdb/wal/watcher_test.go index 86364e3f79..9cd9286a24 100644 --- a/tsdb/wal/watcher_test.go +++ b/tsdb/wal/watcher_test.go @@ -23,7 +23,7 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/prometheus/tsdb/labels" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/record" "github.com/prometheus/prometheus/util/testutil" ) diff --git a/tsdb/wal_test.go b/tsdb/wal_test.go index 319dc4f731..15f1c8fc17 100644 --- a/tsdb/wal_test.go +++ b/tsdb/wal_test.go @@ -27,8 +27,8 @@ import ( "time" "github.com/go-kit/kit/log" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/tsdb/fileutil" - "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/tsdb/record" "github.com/prometheus/prometheus/tsdb/tombstones" "github.com/prometheus/prometheus/tsdb/wal" diff --git a/web/api/v1/api.go b/web/api/v1/api.go index 0ef719e7e4..61a97554ce 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -36,9 +36,6 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/model" "github.com/prometheus/common/route" - "github.com/prometheus/prometheus/tsdb" - "github.com/prometheus/prometheus/tsdb/index" - tsdbLabels "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/pkg/gate" @@ -51,6 +48,8 @@ import ( "github.com/prometheus/prometheus/scrape" "github.com/prometheus/prometheus/storage" "github.com/prometheus/prometheus/storage/remote" + "github.com/prometheus/prometheus/tsdb" + "github.com/prometheus/prometheus/tsdb/index" "github.com/prometheus/prometheus/util/httputil" "github.com/prometheus/prometheus/util/stats" ) @@ -157,7 +156,7 @@ type apiFunc func(r *http.Request) apiFuncResult // TSDBAdmin defines the tsdb interfaces used by the v1 API for admin operations. type TSDBAdmin interface { CleanTombstones() error - Delete(mint, maxt int64, ms ...tsdbLabels.Matcher) error + Delete(mint, maxt int64, ms ...*labels.Matcher) error Dir() string Snapshot(dir string, withHead bool) error Head() *tsdb.Head @@ -1173,12 +1172,7 @@ func (api *API) deleteSeries(r *http.Request) apiFuncResult { return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil} } - var selector tsdbLabels.Selector - for _, m := range matchers { - selector = append(selector, convertMatcher(m)) - } - - if err := db.Delete(timestamp.FromTime(start), timestamp.FromTime(end), selector...); err != nil { + if err := db.Delete(timestamp.FromTime(start), timestamp.FromTime(end), matchers...); err != nil { return apiFuncResult{nil, &apiError{errorInternal, err}, nil, nil} } } @@ -1241,31 +1235,6 @@ func (api *API) cleanTombstones(r *http.Request) apiFuncResult { return apiFuncResult{nil, nil, nil, nil} } -func convertMatcher(m *labels.Matcher) tsdbLabels.Matcher { - switch m.Type { - case labels.MatchEqual: - return tsdbLabels.NewEqualMatcher(m.Name, m.Value) - - case labels.MatchNotEqual: - return tsdbLabels.Not(tsdbLabels.NewEqualMatcher(m.Name, m.Value)) - - case labels.MatchRegexp: - res, err := tsdbLabels.NewRegexpMatcher(m.Name, "^(?:"+m.Value+")$") - if err != nil { - panic(err) - } - return res - - case labels.MatchNotRegexp: - res, err := tsdbLabels.NewRegexpMatcher(m.Name, "^(?:"+m.Value+")$") - if err != nil { - panic(err) - } - return tsdbLabels.Not(res) - } - panic("storage.convertMatcher: invalid matcher type") -} - func (api *API) respond(w http.ResponseWriter, data interface{}, warnings storage.Warnings) { statusMessage := statusSuccess var warningStrings []string diff --git a/web/api/v1/api_test.go b/web/api/v1/api_test.go index 63ab63e878..13bce6cfa0 100644 --- a/web/api/v1/api_test.go +++ b/web/api/v1/api_test.go @@ -39,8 +39,6 @@ import ( "github.com/prometheus/common/model" "github.com/prometheus/common/promlog" "github.com/prometheus/common/route" - "github.com/prometheus/prometheus/tsdb" - tsdbLabels "github.com/prometheus/prometheus/tsdb/labels" "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/pkg/gate" @@ -52,6 +50,7 @@ import ( "github.com/prometheus/prometheus/scrape" "github.com/prometheus/prometheus/storage" "github.com/prometheus/prometheus/storage/remote" + "github.com/prometheus/prometheus/tsdb" "github.com/prometheus/prometheus/util/teststorage" "github.com/prometheus/prometheus/util/testutil" ) @@ -1323,8 +1322,8 @@ type fakeDB struct { closer func() } -func (f *fakeDB) CleanTombstones() error { return f.err } -func (f *fakeDB) Delete(mint, maxt int64, ms ...tsdbLabels.Matcher) error { return f.err } +func (f *fakeDB) CleanTombstones() error { return f.err } +func (f *fakeDB) Delete(mint, maxt int64, ms ...*labels.Matcher) error { return f.err } func (f *fakeDB) Dir() string { dir, _ := ioutil.TempDir("", "fakeDB") f.closer = func() { diff --git a/web/api/v2/api.go b/web/api/v2/api.go index 83e6b33ef4..f657b30647 100644 --- a/web/api/v2/api.go +++ b/web/api/v2/api.go @@ -26,14 +26,15 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/pkg/errors" - "github.com/prometheus/prometheus/tsdb" - tsdbLabels "github.com/prometheus/prometheus/tsdb/labels" + "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/pkg/timestamp" pb "github.com/prometheus/prometheus/prompb" + "github.com/prometheus/prometheus/tsdb" ) // API encapsulates all API services. @@ -186,32 +187,29 @@ func (s *Admin) DeleteSeries(_ context.Context, r *pb.SeriesDeleteRequest) (*pb. if err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } - var matchers tsdbLabels.Selector + var matchers []*labels.Matcher for _, m := range r.Matchers { - var lm tsdbLabels.Matcher + var lm *labels.Matcher var err error switch m.Type { case pb.LabelMatcher_EQ: - lm = tsdbLabels.NewEqualMatcher(m.Name, m.Value) + lm, err = labels.NewMatcher(labels.MatchEqual, m.Name, m.Value) case pb.LabelMatcher_NEQ: - lm = tsdbLabels.Not(tsdbLabels.NewEqualMatcher(m.Name, m.Value)) + lm, err = labels.NewMatcher(labels.MatchNotEqual, m.Name, m.Value) case pb.LabelMatcher_RE: - lm, err = tsdbLabels.NewRegexpMatcher(m.Name, m.Value) - if err != nil { - return nil, status.Errorf(codes.InvalidArgument, "bad regexp matcher: %s", err) - } + lm, err = labels.NewMatcher(labels.MatchRegexp, m.Name, m.Value) case pb.LabelMatcher_NRE: - lm, err = tsdbLabels.NewRegexpMatcher(m.Name, m.Value) - if err != nil { - return nil, status.Errorf(codes.InvalidArgument, "bad regexp matcher: %s", err) - } - lm = tsdbLabels.Not(lm) + lm, err = labels.NewMatcher(labels.MatchNotRegexp, m.Name, m.Value) default: return nil, status.Error(codes.InvalidArgument, "unknown matcher type") } + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "bad matcher: %s", err) + } + matchers = append(matchers, lm) } db := s.db()