Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[dbnode][coordinator] Support match[] in label endpoints #3180

Merged
merged 33 commits into from
Feb 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
81e9d4f
WIP matchers for label endpoints
robskillington Feb 5, 2021
bb694af
Add parsing in endpoints
robskillington Feb 5, 2021
f06ce87
Label / label values integration test
wesleyk Feb 5, 2021
2d09465
Add list tags unit test
wesleyk Feb 5, 2021
e50225f
Ensure name matcher is included in tag values API
wesleyk Feb 5, 2021
654728a
Add tag values unit test for match[]
wesleyk Feb 5, 2021
06b3eec
Add ability to skip fields altogether if does not match restrict by q…
robskillington Feb 5, 2021
01d7605
Remove sleep
wesleyk Feb 5, 2021
bda7d06
Use a separate iterator for fields postings list iterator
robskillington Feb 5, 2021
5f0460d
Return new terms iterable each time
robskillington Feb 6, 2021
7f96eb0
Lookup field postings list from the field data offset
robskillington Feb 6, 2021
d3db7a8
Use curr offset always
robskillington Feb 6, 2021
083b3d7
Unmarshal if err == nil
robskillington Feb 6, 2021
4fbfa66
Fixup integration test assertions
wesleyk Feb 6, 2021
e96015d
Close fieldsIter on filterFieldsIterator.Close()
wesleyk Feb 6, 2021
518005f
Update mocks
wesleyk Feb 6, 2021
c283d36
Fixup filter field iterator test
wesleyk Feb 6, 2021
b2d5103
Merge branch 'master' into matchers-for-label-endpoints
wesleyk Feb 7, 2021
277f845
Lint
wesleyk Feb 7, 2021
240bde4
Update fields terms iter tests
wesleyk Feb 7, 2021
560063e
Use fake fields postings list iterator for filter fields iterator test
wesleyk Feb 7, 2021
5f52d8e
Add ParseMatch unit test
wesleyk Feb 7, 2021
9758a9c
Lint
wesleyk Feb 7, 2021
fdfe854
Add unit tests for fst reader fields postings list
wesleyk Feb 7, 2021
bef0c3b
More explicit label assertion
wesleyk Feb 7, 2021
9f0a962
Lint
wesleyk Feb 7, 2021
eba6962
Add test for fields iterator postings list match
robskillington Feb 8, 2021
f94353d
Merge branch 'master' into matchers-for-label-endpoints
robskillington Feb 8, 2021
74a3e3f
Fix lint
robskillington Feb 8, 2021
9fa98b0
Merge branch 'matchers-for-label-endpoints' of github.com:m3db/m3 int…
robskillington Feb 8, 2021
f775ecc
Merge branch 'master' into matchers-for-label-endpoints
robskillington Feb 8, 2021
56f0235
Fix lint
robskillington Feb 8, 2021
98f75e7
Fix not returning err from toSlice
robskillington Feb 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions scripts/docker-integration-tests/prometheus/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,47 @@ function test_series {
'[[ $(curl -s "0.0.0.0:7201/api/v1/series?match[]=prometheus_remote_storage_samples_total&start=-292273086-05-16T16:47:06Z&end=292277025-08-18T07:12:54.999999999Z" | jq -r ".data | length") -eq 1 ]]'
}

function test_labels {
TAG_NAME_0="name_0" TAG_VALUE_0="value_0_1" \
TAG_NAME_1="name_1" TAG_VALUE_1="value_1_1" \
TAG_NAME_2="name_2" TAG_VALUE_2="value_2_1" \
prometheus_remote_write \
label_metric now 42.42 \
true "Expected request to succeed" \
200 "Expected request to return status code 200"

TAG_NAME_0="name_0" TAG_VALUE_0="value_0_2" \
TAG_NAME_1="name_1" TAG_VALUE_1="value_1_2" \
prometheus_remote_write \
label_metric_2 now 42.42 \
true "Expected request to succeed" \
200 "Expected request to return status code 200"

# Test label search with match
ATTEMPTS=5 TIMEOUT=2 MAX_TIMEOUT=4 retry_with_backoff \
'[[ $(curl -s "0.0.0.0:7201/api/v1/labels" | jq -r "[.data[] | select(index(\"name_0\", \"name_1\", \"name_2\"))] | length") -eq 3 ]]'

ATTEMPTS=5 TIMEOUT=2 MAX_TIMEOUT=4 retry_with_backoff \
'[[ $(curl -s "0.0.0.0:7201/api/v1/labels?match[]=label_metric" | jq -r ".data | length") -eq 4 ]]'

ATTEMPTS=5 TIMEOUT=2 MAX_TIMEOUT=4 retry_with_backoff \
'[[ $(curl -s "0.0.0.0:7201/api/v1/labels?match[]=label_metric_2" | jq -r ".data | length") -eq 3 ]]'

# Test label values search with match
ATTEMPTS=5 TIMEOUT=2 MAX_TIMEOUT=4 retry_with_backoff \
'[[ $(curl -s "0.0.0.0:7201/api/v1/label/name_1/values" | jq -r ".data | length") -eq 2 ]]' # two values without a match

ATTEMPTS=5 TIMEOUT=2 MAX_TIMEOUT=4 retry_with_backoff \
'[[ $(curl -s "0.0.0.0:7201/api/v1/label/name_1/values?match[]=label_metric" | jq -r ".data | length") -eq 1 ]]'
ATTEMPTS=5 TIMEOUT=2 MAX_TIMEOUT=4 retry_with_backoff \
'[[ $(curl -s "0.0.0.0:7201/api/v1/label/name_1/values?match[]=label_metric" | jq -r ".data[0]") = "value_1_1" ]]'

ATTEMPTS=5 TIMEOUT=2 MAX_TIMEOUT=4 retry_with_backoff \
'[[ $(curl -s "0.0.0.0:7201/api/v1/label/name_1/values?match[]=label_metric_2" | jq -r ".data | length") -eq 1 ]]'
ATTEMPTS=5 TIMEOUT=2 MAX_TIMEOUT=4 retry_with_backoff \
'[[ $(curl -s "0.0.0.0:7201/api/v1/label/name_1/values?match[]=label_metric_2" | jq -r ".data[0]") = "value_1_2" ]]'
}

echo "Running readiness test"
test_readiness

Expand All @@ -409,6 +450,7 @@ test_prometheus_query_native_timeout
test_query_restrict_tags
test_prometheus_remote_write_map_tags
test_series
test_labels

echo "Running function correctness tests"
test_correctness
Expand Down
4 changes: 2 additions & 2 deletions src/dbnode/storage/index/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ func (b *block) aggregateWithSpan(
}
return aggOpts.FieldFilter.Allow(field)
},
fieldIterFn: func(r segment.Reader) (segment.FieldsIterator, error) {
fieldIterFn: func(r segment.Reader) (segment.FieldsPostingsListIterator, error) {
// NB(prateek): we default to using the regular (FST) fields iterator
// unless we have a predefined list of fields we know we need to restrict
// our search to, in which case we iterate that list and check if known values
Expand All @@ -642,7 +642,7 @@ func (b *block) aggregateWithSpan(
// to this function is expected to have (FieldsFilter) pretty small. If that changes
// in the future, we can revisit this.
if len(aggOpts.FieldFilter) == 0 {
return r.Fields()
return r.FieldsPostingsList()
}
return newFilterFieldsIterator(r, aggOpts.FieldFilter)
},
Expand Down
38 changes: 31 additions & 7 deletions src/dbnode/storage/index/fields_terms_iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ package index
import (
"errors"

pilosaroaring "github.com/m3dbx/pilosa/roaring"

"github.com/m3db/m3/src/m3ninx/index/segment"
"github.com/m3db/m3/src/m3ninx/postings"
"github.com/m3db/m3/src/m3ninx/postings/roaring"
xerrors "github.com/m3db/m3/src/x/errors"
pilosaroaring "github.com/m3dbx/pilosa/roaring"
)

var (
Expand All @@ -49,23 +50,23 @@ func (o fieldsAndTermsIteratorOpts) allow(f []byte) bool {
return o.allowFn(f)
}

func (o fieldsAndTermsIteratorOpts) newFieldIter(r segment.Reader) (segment.FieldsIterator, error) {
func (o fieldsAndTermsIteratorOpts) newFieldIter(r segment.Reader) (segment.FieldsPostingsListIterator, error) {
if o.fieldIterFn == nil {
return r.Fields()
return r.FieldsPostingsList()
}
return o.fieldIterFn(r)
}

type allowFn func(field []byte) bool

type newFieldIterFn func(r segment.Reader) (segment.FieldsIterator, error)
type newFieldIterFn func(r segment.Reader) (segment.FieldsPostingsListIterator, error)

type fieldsAndTermsIter struct {
reader segment.Reader
opts fieldsAndTermsIteratorOpts

err error
fieldIter segment.FieldsIterator
fieldIter segment.FieldsPostingsListIterator
termIter segment.TermsIterator

current struct {
Expand Down Expand Up @@ -145,10 +146,33 @@ func (fti *fieldsAndTermsIter) setNextField() bool {
}

for fieldIter.Next() {
field := fieldIter.Current()
field, pl := fieldIter.Current()
if !fti.opts.allow(field) {
continue
}
if fti.restrictByPostings == nil {
// No restrictions.
fti.current.field = field
return true
}

bitmap, ok := roaring.BitmapFromPostingsList(pl)
if !ok {
fti.err = errUnpackBitmapFromPostingsList
return false
}

// Check field is part of at least some of the documents we're
// restricted to providing results for based on intersection
// count.
// Note: IntersectionCount is significantly faster than intersecting and
// counting results and also does not allocate.
if n := fti.restrictByPostings.IntersectionCount(bitmap); n < 1 {
// No match, not next result.
continue
}

// Matches, this is next result.
fti.current.field = field
return true
}
Expand Down Expand Up @@ -213,7 +237,7 @@ func (fti *fieldsAndTermsIter) nextTermsIterResult() (bool, error) {
return false, errUnpackBitmapFromPostingsList
}

// Check term isn part of at least some of the documents we're
// Check term is part of at least some of the documents we're
// restricted to providing results for based on intersection
// count.
// Note: IntersectionCount is significantly faster than intersecting and
Expand Down
11 changes: 7 additions & 4 deletions src/dbnode/storage/index/fields_terms_iterator_prop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import (
"github.com/leanovate/gopter"
"github.com/leanovate/gopter/gen"
"github.com/leanovate/gopter/prop"
"github.com/stretchr/testify/require"

"github.com/m3db/m3/src/m3ninx/index/segment"
xtest "github.com/m3db/m3/src/x/test"
)
Expand Down Expand Up @@ -62,7 +64,8 @@ func TestFieldsTermsIteratorPropertyTest(t *testing.T) {
if err != nil {
return false, err
}
observed := toSlice(t, iter)
observed, err := toSlice(iter)
require.NoError(t, err)
requireSlicesEqual(t, expected, observed)
return true, nil
},
Expand Down Expand Up @@ -97,7 +100,7 @@ func TestFieldsTermsIteratorPropertyTestNoPanic(t *testing.T) {
if err != nil {
return false, err
}
toSlice(t, iter)
_, _ = toSlice(iter)
return true, nil
},
genIterableSegment(ctrl),
Expand Down Expand Up @@ -149,9 +152,9 @@ func genIterableSegment(ctrl *gomock.Controller) gopter.Gen {

r := segment.NewMockReader(ctrl)

fieldIterator := &stubFieldIterator{points: fields}
fieldsPostingsListIterator := &stubFieldsPostingsListIterator{points: fields}

r.EXPECT().Fields().Return(fieldIterator, nil).AnyTimes()
r.EXPECT().FieldsPostingsList().Return(fieldsPostingsListIterator, nil).AnyTimes()

for f, values := range tagValues {
sort.Slice(values, func(i, j int) bool {
Expand Down
Loading