Skip to content
This repository was archived by the owner on Aug 23, 2023. It is now read-only.

Commit 39e35e2

Browse files
committed
optimize performance by using map lookup
looking up a key from a map is faster than iterating over the values and comparing them to what we are looking for. to take advantage of the faster map lookup this now passes an index lookup method into the metric definition filters.
1 parent 4ac5a6d commit 39e35e2

16 files changed

+113
-70
lines changed

expr/tagquery/expression.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"regexp"
66
"sort"
77
"strings"
8+
9+
"github.com/raintank/schema"
810
)
911

1012
const invalidExpressionError = "Invalid expression: %s"
@@ -161,7 +163,7 @@ type Expression interface {
161163
// GetMetricDefinitionFilter returns a MetricDefinitionFilter
162164
// The MetricDefinitionFilter takes a metric definition, looks at its tags and returns a decision
163165
// regarding this query expression applied to its tags
164-
GetMetricDefinitionFilter() MetricDefinitionFilter
166+
GetMetricDefinitionFilter(lookup IdTagLookup) MetricDefinitionFilter
165167

166168
// StringIntoBuilder takes a builder and writes a string representation of this expression into it
167169
StringIntoBuilder(builder *strings.Builder)
@@ -369,7 +371,7 @@ func ExpressionsAreEqual(expr1, expr2 Expression) bool {
369371
}
370372

371373
// MetricDefinitionFilter takes a metric name together with its tags and returns a FilterDecision
372-
type MetricDefinitionFilter func(name string, tags []string) FilterDecision
374+
type MetricDefinitionFilter func(id schema.MKey, name string, tags []string) FilterDecision
373375

374376
type FilterDecision uint8
375377

expr/tagquery/expression_equal.go

+14-16
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package tagquery
22

33
import (
44
"strings"
5+
6+
"github.com/raintank/schema"
57
)
68

79
type expressionEqual struct {
@@ -20,40 +22,36 @@ func (e *expressionEqual) ValuePasses(value string) bool {
2022
return value == e.value
2123
}
2224

23-
func (e *expressionEqual) GetMetricDefinitionFilter() MetricDefinitionFilter {
25+
func (e *expressionEqual) GetMetricDefinitionFilter(lookup IdTagLookup) MetricDefinitionFilter {
2426
if e.key == "name" {
2527
if e.value == "" {
2628
// every metric has a name, the value will never be empty
27-
return func(_ string, _ []string) FilterDecision { return Fail }
29+
return func(id schema.MKey, name string, tags []string) FilterDecision { return Fail }
2830
}
29-
return func(name string, _ []string) FilterDecision {
31+
return func(id schema.MKey, name string, tags []string) FilterDecision {
3032
if name == e.value {
3133
return Pass
3234
}
3335
return Fail
3436
}
3537
}
3638

37-
prefix := e.key + "="
38-
matchString := prefix + e.value
3939
if !metaTagSupport {
40-
return func(name string, tags []string) FilterDecision {
41-
for _, tag := range tags {
42-
if tag == matchString {
43-
return Pass
44-
}
40+
return func(id schema.MKey, name string, tags []string) FilterDecision {
41+
if lookup(id, e.key, e.value) {
42+
return Pass
4543
}
46-
4744
return Fail
4845
}
4946
}
5047

51-
return func(name string, tags []string) FilterDecision {
52-
for _, tag := range tags {
53-
if tag == matchString {
54-
return Pass
55-
}
48+
prefix := e.key + "="
49+
return func(id schema.MKey, name string, tags []string) FilterDecision {
50+
if lookup(id, e.key, e.value) {
51+
return Pass
52+
}
5653

54+
for _, tag := range tags {
5755
// the tag is set, but it has a different value,
5856
// no need to keep looking at other indexes
5957
if strings.HasPrefix(tag, prefix) {

expr/tagquery/expression_has_tag.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package tagquery
22

33
import (
44
"strings"
5+
6+
"github.com/raintank/schema"
57
)
68

79
type expressionHasTag struct {
@@ -24,9 +26,9 @@ func (e *expressionHasTag) ValuePasses(value string) bool {
2426
return value == e.key
2527
}
2628

27-
func (e *expressionHasTag) GetMetricDefinitionFilter() MetricDefinitionFilter {
29+
func (e *expressionHasTag) GetMetricDefinitionFilter(_ IdTagLookup) MetricDefinitionFilter {
2830
if e.key == "name" {
29-
return func(_ string, _ []string) FilterDecision { return Pass }
31+
return func(id schema.MKey, name string, tags []string) FilterDecision { return Pass }
3032
}
3133

3234
resultIfTagIsAbsent := None
@@ -35,7 +37,7 @@ func (e *expressionHasTag) GetMetricDefinitionFilter() MetricDefinitionFilter {
3537
}
3638

3739
matchPrefix := e.key + "="
38-
return func(_ string, tags []string) FilterDecision {
40+
return func(id schema.MKey, name string, tags []string) FilterDecision {
3941
for _, tag := range tags {
4042
if strings.HasPrefix(tag, matchPrefix) {
4143
return Pass

expr/tagquery/expression_match.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ func (e *expressionMatch) ValuePasses(value string) bool {
4141
return e.valueRe.MatchString(value)
4242
}
4343

44-
func (e *expressionMatch) GetMetricDefinitionFilter() MetricDefinitionFilter {
44+
func (e *expressionMatch) GetMetricDefinitionFilter(_ IdTagLookup) MetricDefinitionFilter {
4545
if e.key == "name" {
4646
if e.value == "" {
4747
// silly query, always fails
48-
return func(_ string, _ []string) FilterDecision { return Fail }
48+
return func(id schema.MKey, name string, tags []string) FilterDecision { return Fail }
4949
}
50-
return func(name string, _ []string) FilterDecision {
50+
return func(id schema.MKey, name string, tags []string) FilterDecision {
5151
if e.valueRe.MatchString(schema.SanitizeNameAsTagValue(name)) {
5252
return Pass
5353
} else {
@@ -61,11 +61,10 @@ func (e *expressionMatch) GetMetricDefinitionFilter() MetricDefinitionFilter {
6161
resultIfTagIsAbsent = Fail
6262
}
6363

64+
prefix := e.key + "="
6465
var matchCache, missCache sync.Map
6566
var currentMatchCacheSize, currentMissCacheSize int32
66-
prefix := e.key + "="
67-
68-
return func(_ string, tags []string) FilterDecision {
67+
return func(id schema.MKey, name string, tags []string) FilterDecision {
6968
for _, tag := range tags {
7069
if !strings.HasPrefix(tag, prefix) {
7170
continue

expr/tagquery/expression_match_all.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package tagquery
22

33
import (
44
"strings"
5+
6+
"github.com/raintank/schema"
57
)
68

79
type expressionMatchAll struct {
@@ -38,8 +40,8 @@ func (e *expressionMatchAll) ValuePasses(value string) bool {
3840
return true
3941
}
4042

41-
func (e *expressionMatchAll) GetMetricDefinitionFilter() MetricDefinitionFilter {
42-
return func(_ string, _ []string) FilterDecision { return Pass }
43+
func (e *expressionMatchAll) GetMetricDefinitionFilter(_ IdTagLookup) MetricDefinitionFilter {
44+
return func(id schema.MKey, name string, tags []string) FilterDecision { return Pass }
4345
}
4446

4547
func (e *expressionMatchAll) StringIntoBuilder(builder *strings.Builder) {

expr/tagquery/expression_match_none.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package tagquery
22

33
import (
44
"strings"
5+
6+
"github.com/raintank/schema"
57
)
68

79
type expressionMatchNone struct {
@@ -38,8 +40,8 @@ func (e *expressionMatchNone) ValuePasses(value string) bool {
3840
return false
3941
}
4042

41-
func (e *expressionMatchNone) GetMetricDefinitionFilter() MetricDefinitionFilter {
42-
return func(_ string, _ []string) FilterDecision { return Fail }
43+
func (e *expressionMatchNone) GetMetricDefinitionFilter(_ IdTagLookup) MetricDefinitionFilter {
44+
return func(id schema.MKey, name string, tags []string) FilterDecision { return Fail }
4345
}
4446

4547
func (e *expressionMatchNone) StringIntoBuilder(builder *strings.Builder) {

expr/tagquery/expression_match_tag.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"strings"
55
"sync"
66
"sync/atomic"
7+
8+
"github.com/raintank/schema"
79
)
810

911
type expressionMatchTag struct {
@@ -34,10 +36,10 @@ func (e *expressionMatchTag) ValuePasses(tag string) bool {
3436
return e.valueRe.MatchString(tag)
3537
}
3638

37-
func (e *expressionMatchTag) GetMetricDefinitionFilter() MetricDefinitionFilter {
39+
func (e *expressionMatchTag) GetMetricDefinitionFilter(_ IdTagLookup) MetricDefinitionFilter {
3840
if e.valueRe.Match([]byte("name")) {
3941
// every metric has a tag name, so we can always return Pass
40-
return func(_ string, _ []string) FilterDecision { return Pass }
42+
return func(id schema.MKey, name string, tags []string) FilterDecision { return Pass }
4143
}
4244

4345
resultIfTagIsAbsent := None
@@ -48,7 +50,7 @@ func (e *expressionMatchTag) GetMetricDefinitionFilter() MetricDefinitionFilter
4850
var matchCache, missCache sync.Map
4951
var currentMatchCacheSize, currentMissCacheSize int32
5052

51-
return func(_ string, tags []string) FilterDecision {
53+
return func(id schema.MKey, name string, tags []string) FilterDecision {
5254
for _, tag := range tags {
5355
values := strings.SplitN(tag, "=", 2)
5456
if len(values) < 2 {

expr/tagquery/expression_not_equal.go

+16-16
Original file line numberDiff line numberDiff line change
@@ -26,42 +26,42 @@ func (e *expressionNotEqual) ValuePasses(value string) bool {
2626
return value != e.value
2727
}
2828

29-
func (e *expressionNotEqual) GetMetricDefinitionFilter() MetricDefinitionFilter {
29+
func (e *expressionNotEqual) GetMetricDefinitionFilter(lookup IdTagLookup) MetricDefinitionFilter {
3030
if e.key == "name" {
3131
if e.value == "" {
32-
return func(_ string, _ []string) FilterDecision { return Pass }
32+
return func(id schema.MKey, name string, tags []string) FilterDecision { return Pass }
3333
}
34-
return func(name string, _ []string) FilterDecision {
34+
return func(id schema.MKey, name string, tags []string) FilterDecision {
3535
if schema.SanitizeNameAsTagValue(name) == e.value {
3636
return Fail
3737
}
3838
return Pass
3939
}
4040
}
4141

42-
prefix := e.key + "="
43-
matchString := prefix + e.value
4442
if !metaTagSupport {
45-
return func(name string, tags []string) FilterDecision {
46-
for _, tag := range tags {
47-
if tag == matchString {
48-
return Fail
49-
}
43+
return func(id schema.MKey, name string, tags []string) FilterDecision {
44+
if lookup(id, e.key, e.value) {
45+
return Fail
5046
}
5147
return Pass
5248
}
5349
}
5450

55-
return func(_ string, tags []string) FilterDecision {
51+
prefix := e.key + "="
52+
return func(id schema.MKey, name string, tags []string) FilterDecision {
53+
if lookup(id, e.key, e.value) {
54+
return Fail
55+
}
56+
5657
for _, tag := range tags {
58+
// the tag is set, but it has a different value,
59+
// no need to keep looking at other indexes
5760
if strings.HasPrefix(tag, prefix) {
58-
if tag == matchString {
59-
return Fail
60-
} else {
61-
return Pass
62-
}
61+
return Pass
6362
}
6463
}
64+
6565
return None
6666
}
6767
}

expr/tagquery/expression_not_has_tag.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package tagquery
22

33
import (
44
"strings"
5+
6+
"github.com/raintank/schema"
57
)
68

79
type expressionNotHasTag struct {
@@ -28,9 +30,9 @@ func (e *expressionNotHasTag) ValuePasses(value string) bool {
2830
return value == e.key
2931
}
3032

31-
func (e *expressionNotHasTag) GetMetricDefinitionFilter() MetricDefinitionFilter {
33+
func (e *expressionNotHasTag) GetMetricDefinitionFilter(_ IdTagLookup) MetricDefinitionFilter {
3234
if e.key == "name" {
33-
return func(_ string, _ []string) FilterDecision { return Fail }
35+
return func(id schema.MKey, name string, tags []string) FilterDecision { return Fail }
3436
}
3537

3638
resultIfTagIsAbsent := None
@@ -39,7 +41,7 @@ func (e *expressionNotHasTag) GetMetricDefinitionFilter() MetricDefinitionFilter
3941
}
4042

4143
matchPrefix := e.key + "="
42-
return func(_ string, tags []string) FilterDecision {
44+
return func(id schema.MKey, name string, tags []string) FilterDecision {
4345
for _, tag := range tags {
4446
if strings.HasPrefix(tag, matchPrefix) {
4547
return Fail

expr/tagquery/expression_not_match.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ func (e *expressionNotMatch) ValuePasses(value string) bool {
4141
return !e.valueRe.MatchString(value)
4242
}
4343

44-
func (e *expressionNotMatch) GetMetricDefinitionFilter() MetricDefinitionFilter {
44+
func (e *expressionNotMatch) GetMetricDefinitionFilter(_ IdTagLookup) MetricDefinitionFilter {
4545
if e.key == "name" {
4646
if e.value == "" {
4747
// every metric has a name
48-
return func(_ string, _ []string) FilterDecision { return Pass }
48+
return func(id schema.MKey, name string, tags []string) FilterDecision { return Pass }
4949
}
5050

51-
return func(name string, _ []string) FilterDecision {
51+
return func(id schema.MKey, name string, tags []string) FilterDecision {
5252
if e.valueRe.MatchString(schema.SanitizeNameAsTagValue(name)) {
5353
return Fail
5454
}
@@ -61,11 +61,10 @@ func (e *expressionNotMatch) GetMetricDefinitionFilter() MetricDefinitionFilter
6161
resultIfTagIsAbsent = Pass
6262
}
6363

64+
prefix := e.key + "="
6465
var matchCache, missCache sync.Map
6566
var currentMatchCacheSize, currentMissCacheSize int32
66-
prefix := e.key + "="
67-
68-
return func(_ string, tags []string) FilterDecision {
67+
return func(id schema.MKey, name string, tags []string) FilterDecision {
6968
for _, tag := range tags {
7069
if !strings.HasPrefix(tag, prefix) {
7170
continue

expr/tagquery/expression_prefix.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ func (e *expressionPrefix) ValuePasses(value string) bool {
2828
return strings.HasPrefix(value, e.value)
2929
}
3030

31-
func (e *expressionPrefix) GetMetricDefinitionFilter() MetricDefinitionFilter {
31+
func (e *expressionPrefix) GetMetricDefinitionFilter(_ IdTagLookup) MetricDefinitionFilter {
3232
prefix := e.key + "="
3333
matchString := prefix + e.value
3434

3535
if e.key == "name" {
36-
return func(name string, _ []string) FilterDecision {
36+
return func(id schema.MKey, name string, tags []string) FilterDecision {
3737
if strings.HasPrefix(schema.SanitizeNameAsTagValue(name), e.value) {
3838
return Pass
3939
}
@@ -47,7 +47,7 @@ func (e *expressionPrefix) GetMetricDefinitionFilter() MetricDefinitionFilter {
4747
resultIfTagIsAbsent = Fail
4848
}
4949

50-
return func(name string, tags []string) FilterDecision {
50+
return func(_ schema.MKey, _ string, tags []string) FilterDecision {
5151
for _, tag := range tags {
5252
if strings.HasPrefix(tag, matchString) {
5353
return Pass

expr/tagquery/expression_prefix_tag.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package tagquery
22

33
import (
44
"strings"
5+
6+
"github.com/raintank/schema"
57
)
68

79
type expressionPrefixTag struct {
@@ -30,18 +32,18 @@ func (e *expressionPrefixTag) ValuePasses(tag string) bool {
3032
return strings.HasPrefix(tag, e.value)
3133
}
3234

33-
func (e *expressionPrefixTag) GetMetricDefinitionFilter() MetricDefinitionFilter {
35+
func (e *expressionPrefixTag) GetMetricDefinitionFilter(_ IdTagLookup) MetricDefinitionFilter {
3436
if strings.HasPrefix("name", e.value) {
3537
// every metric has a name
36-
return func(_ string, _ []string) FilterDecision { return Pass }
38+
return func(id schema.MKey, name string, tags []string) FilterDecision { return Pass }
3739
}
3840

3941
resultIfTagIsAbsent := None
4042
if !metaTagSupport {
4143
resultIfTagIsAbsent = Fail
4244
}
4345

44-
return func(name string, tags []string) FilterDecision {
46+
return func(_ schema.MKey, _ string, tags []string) FilterDecision {
4547
for _, tag := range tags {
4648
if strings.HasPrefix(tag, e.value) {
4749
return Pass

0 commit comments

Comments
 (0)