Skip to content
This repository has been archived by the owner on Oct 17, 2018. It is now read-only.

Commit

Permalink
Move ID interface to m3metrics and add m3 id implementation (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
xichen2020 committed May 11, 2017
1 parent 6e2512d commit 5a4ec9a
Show file tree
Hide file tree
Showing 30 changed files with 896 additions and 226 deletions.
10 changes: 6 additions & 4 deletions filters/filter_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (
"bytes"
"fmt"
"testing"

"github.com/m3db/m3metrics/metric/id"
)

var (
Expand Down Expand Up @@ -64,7 +66,7 @@ func BenchmarkEquityFilterByValue(b *testing.B) {
}

func BenchmarkTagsFilterOne(b *testing.B) {
filter, _ := NewTagsFilter(testTagsFilterMapOne, NewMockSortedTagIterator, Conjunction)
filter, _ := NewTagsFilter(testTagsFilterMapOne, Conjunction, testTagsFilterOptions())
benchTagsFilter(b, testFlatID, filter)
}

Expand All @@ -73,7 +75,7 @@ func BenchmarkMapTagsFilterOne(b *testing.B) {
}

func BenchmarkTagsFilterThree(b *testing.B) {
filter, _ := NewTagsFilter(testTagsFilterMapThree, NewMockSortedTagIterator, Conjunction)
filter, _ := NewTagsFilter(testTagsFilterMapThree, Conjunction, testTagsFilterOptions())
benchTagsFilter(b, testFlatID, filter)
}

Expand Down Expand Up @@ -225,10 +227,10 @@ func (f testEqualityFilter) Matches(id []byte) bool {

type testMapTagsFilter struct {
filters map[string]Filter
iterFn NewSortedTagIteratorFn
iterFn id.SortedTagIteratorFn
}

func newTestMapTagsFilter(tagFilters map[string]string, iterFn NewSortedTagIteratorFn) Filter {
func newTestMapTagsFilter(tagFilters map[string]string, iterFn id.SortedTagIteratorFn) Filter {
filters := make(map[string]Filter, len(tagFilters))
for name, value := range tagFilters {
filter, _ := NewFilter([]byte(value))
Expand Down
16 changes: 12 additions & 4 deletions filters/mock_filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ package filters

import (
"strings"

"github.com/m3db/m3metrics/metric/id"
)

const (
Expand All @@ -45,8 +47,8 @@ type mockSortedTagIterator struct {
pairs []mockTagPair
}

func idToMockTagPairs(id []byte) []mockTagPair {
tagPairs := strings.Split(string(id), mockTagPairSeparator)
func tagsToPairs(tags []byte) []mockTagPair {
tagPairs := strings.Split(string(tags), mockTagPairSeparator)
var pairs []mockTagPair
for _, pair := range tagPairs {
p := strings.Split(pair, mockTagValueSeparator)
Expand All @@ -56,11 +58,17 @@ func idToMockTagPairs(id []byte) []mockTagPair {
}

// NewMockSortedTagIterator creates a mock SortedTagIterator based on given ID.
func NewMockSortedTagIterator(id []byte) SortedTagIterator {
pairs := idToMockTagPairs(id)
func NewMockSortedTagIterator(tags []byte) id.SortedTagIterator {
pairs := tagsToPairs(tags)
return &mockSortedTagIterator{idx: -1, pairs: pairs}
}

func (it *mockSortedTagIterator) Reset(tags []byte) {
it.idx = -1
it.err = nil
it.pairs = tagsToPairs(tags)
}

func (it *mockSortedTagIterator) Next() bool {
if it.err != nil || it.idx >= len(it.pairs) {
return false
Expand Down
129 changes: 79 additions & 50 deletions filters/tags_filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,9 @@ import (
"bytes"
"fmt"
"sort"
)

// SortedTagIterator iterates over a set of tag names and values
// sorted by tag names in ascending order.
type SortedTagIterator interface {
// Next returns true if there are more tag names and values.
Next() bool

// Current returns the current tag name and value.
Current() ([]byte, []byte)

// Err returns any errors encountered.
Err() error

// Close closes the iterator.
Close()
}

// NewSortedTagIteratorFn creates a tag iterator given an id.
type NewSortedTagIteratorFn func(id []byte) SortedTagIterator
"github.com/m3db/m3metrics/metric/id"
)

// tagFilter is a filter associated with a given tag.
type tagFilter struct {
Expand All @@ -61,60 +44,106 @@ func (tn tagFiltersByNameAsc) Len() int { return len(tn) }
func (tn tagFiltersByNameAsc) Swap(i, j int) { tn[i], tn[j] = tn[j], tn[i] }
func (tn tagFiltersByNameAsc) Less(i, j int) bool { return bytes.Compare(tn[i].name, tn[j].name) < 0 }

// TagsFilterOptions provide a set of tag filter options.
type TagsFilterOptions struct {
// Name of the name tag.
NameTagKey []byte

// Function to extract name and tags from an id.
NameAndTagsFn id.NameAndTagsFn

// Function to create a new sorted tag iterator from id tags.
SortedTagIteratorFn id.SortedTagIteratorFn
}

// tagsFilter contains a list of tag filters.
type tagsFilter struct {
filters []tagFilter
iterFn NewSortedTagIteratorFn
op LogicalOp
nameFilter Filter
tagFilters []tagFilter
op LogicalOp
opts TagsFilterOptions
}

// NewTagsFilter create a new tags filter.
func NewTagsFilter(tagFilters map[string]string, iterFn NewSortedTagIteratorFn, op LogicalOp) (Filter, error) {
filters := make([]tagFilter, 0, len(tagFilters))
for name, value := range tagFilters {
// NewTagsFilter creates a new tags filter.
func NewTagsFilter(
filters map[string]string,
op LogicalOp,
opts TagsFilterOptions,
) (Filter, error) {
var (
nameFilter Filter
tagFilters = make([]tagFilter, 0, len(filters))
)
for name, value := range filters {
valFilter, err := NewFilter([]byte(value))
if err != nil {
return nil, err
}

filters = append(filters, tagFilter{
name: []byte(name),
valueFilter: valFilter,
})
bName := []byte(name)
if bytes.Equal(opts.NameTagKey, bName) {
nameFilter = valFilter
} else {
tagFilters = append(tagFilters, tagFilter{
name: bName,
valueFilter: valFilter,
})
}
}
sort.Sort(tagFiltersByNameAsc(filters))
sort.Sort(tagFiltersByNameAsc(tagFilters))
return &tagsFilter{
filters: filters,
iterFn: iterFn,
op: op,
nameFilter: nameFilter,
tagFilters: tagFilters,
op: op,
opts: opts,
}, nil
}

func (f *tagsFilter) String() string {
separator := " " + string(f.op) + " "
var buf bytes.Buffer
numFilters := len(f.filters)
for i := 0; i < numFilters; i++ {
buf.WriteString(f.filters[i].String())
if i < numFilters-1 {
numTagFilters := len(f.tagFilters)
if f.nameFilter != nil {
buf.WriteString(fmt.Sprintf("%s:%s", f.opts.NameTagKey, f.nameFilter.String()))
if numTagFilters > 0 {
buf.WriteString(separator)
}
}
for i := 0; i < numTagFilters; i++ {
buf.WriteString(f.tagFilters[i].String())
if i < numTagFilters-1 {
buf.WriteString(separator)
}
}
return buf.String()
}

func (f *tagsFilter) Matches(id []byte) bool {
if len(f.filters) == 0 {
if f.nameFilter == nil && len(f.tagFilters) == 0 {
return true
}
iter := f.iterFn(id)

name, tags, err := f.opts.NameAndTagsFn(id)
if err != nil {
return false
}
if f.nameFilter != nil {
match := f.nameFilter.Matches(name)
if match && f.op == Disjunction {
return true
}
if !match && f.op == Conjunction {
return false
}
}

iter := f.opts.SortedTagIteratorFn(tags)
defer iter.Close()

currIdx := 0
for iter.Next() && currIdx < len(f.filters) {
for iter.Next() && currIdx < len(f.tagFilters) {
name, value := iter.Current()

comparison := bytes.Compare(name, f.filters[currIdx].name)
comparison := bytes.Compare(name, f.tagFilters[currIdx].name)
if comparison < 0 {
continue
}
Expand All @@ -125,23 +154,23 @@ func (f *tagsFilter) Matches(id []byte) bool {
return false
}

// Iterate filters for the OR case.
// Iterate tagFilters for the OR case.
currIdx++
for currIdx < len(f.filters) && bytes.Compare(name, f.filters[currIdx].name) > 0 {
for currIdx < len(f.tagFilters) && bytes.Compare(name, f.tagFilters[currIdx].name) > 0 {
currIdx++
}

if currIdx == len(f.filters) {
// Past all filters.
if currIdx == len(f.tagFilters) {
// Past all tagFilters.
return false
}

if bytes.Compare(name, f.filters[currIdx].name) < 0 {
if bytes.Compare(name, f.tagFilters[currIdx].name) < 0 {
continue
}
}

match := f.filters[currIdx].valueFilter.Matches(value)
match := f.tagFilters[currIdx].valueFilter.Matches(value)
if match && f.op == Disjunction {
return true
}
Expand All @@ -157,5 +186,5 @@ func (f *tagsFilter) Matches(id []byte) bool {
return false
}

return currIdx == len(f.filters)
return currIdx == len(f.tagFilters)
}
Loading

0 comments on commit 5a4ec9a

Please sign in to comment.