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

[query] Add support for unary expressions #1647

Merged
merged 10 commits into from
May 24, 2019
Merged

[query] Add support for unary expressions #1647

merged 10 commits into from
May 24, 2019

Conversation

benraskin92
Copy link
Collaborator

@benraskin92 benraskin92 commented May 20, 2019

What this PR does / why we need it:

This PR fixes #1619. It introduces support for unary expressions -- specifically + and -. For example, this query is now supported:

-sum(up)

Special notes for your reviewer:

Does this PR introduce a user-facing and/or backwards incompatible change?:

Yes, this PR adds support for Prometheus unary expressions (`+` and `-`).

Does this PR require updating code package or user-facing documentation?:

NONE

@codecov
Copy link

codecov bot commented May 20, 2019

Codecov Report

Merging #1647 into master will decrease coverage by 0.1%.
The diff coverage is 67.8%.

Impacted file tree graph

@@           Coverage Diff            @@
##           master   #1647     +/-   ##
========================================
- Coverage    72.3%   72.1%   -0.2%     
========================================
  Files         962     961      -1     
  Lines       80157   80051    -106     
========================================
- Hits        57967   57783    -184     
- Misses      18398   18497     +99     
+ Partials     3792    3771     -21
Flag Coverage Δ
#aggregator 82.3% <ø> (-0.1%) ⬇️
#cluster 85.7% <ø> (-0.1%) ⬇️
#collector 63.9% <ø> (ø) ⬆️
#dbnode 80.2% <ø> (ø) ⬆️
#m3em 73.2% <ø> (ø) ⬆️
#m3ninx 74.1% <ø> (ø) ⬆️
#m3nsch 51.1% <ø> (ø) ⬆️
#metrics 17.6% <ø> (ø) ⬆️
#msg 74.7% <ø> (ø) ⬆️
#query 67.3% <67.8%> (-0.7%) ⬇️
#x 86.4% <ø> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 79ee9f5...7ec1709. Read the comment docs.

@codecov
Copy link

codecov bot commented May 20, 2019

Codecov Report

Merging #1647 into master will increase coverage by 6.6%.
The diff coverage is 89.1%.

Impacted file tree graph

@@           Coverage Diff            @@
##           master   #1647     +/-   ##
========================================
+ Coverage    65.3%   71.9%   +6.6%     
========================================
  Files         958     964      +6     
  Lines       80131   80725    +594     
========================================
+ Hits        52369   58092   +5723     
+ Misses      24080   18827   -5253     
- Partials     3682    3806    +124
Flag Coverage Δ
#aggregator 82.4% <ø> (-2.5%) ⬇️
#cluster 85.7% <ø> (+15.7%) ⬆️
#collector 63.9% <ø> (+8.7%) ⬆️
#dbnode 80.1% <ø> (+2.7%) ⬆️
#m3em 73.2% <ø> (ø) ⬆️
#m3ninx 74% <ø> (+5.2%) ⬆️
#m3nsch 51.1% <ø> (ø) ⬆️
#metrics 17.6% <ø> (ø) ⬆️
#msg 74.9% <ø> (+0.1%) ⬆️
#query 66.4% <89.1%> (+19.1%) ⬆️
#x 86.3% <ø> (+8.8%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2ca0202...3dac576. Read the comment docs.

@benraskin92 benraskin92 marked this pull request as ready for review May 20, 2019 17:15
@benraskin92 benraskin92 changed the title [WIP] [query] Add support for unary expressions [query] Add support for unary expressions May 20, 2019
stepVals = c.Values()
)

vals := make([]float64, len(stepVals))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could you use the make([].., 0, ..) formulation and append instead of directly accessing by idx.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it more efficient to allocate the length up front (instead of capacity) and index in? Or is this a better safe than sorry situation and avoid a potential panic?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can get both by doing the other version.

i.e. when using the version with append (below), it's not expanding the slice unless the initial alloc wasn't large enough. so you still get the benefit of the up front alloc but also the safety of not panic'ing.

slice := make([]type, 0, len)
for _, v := range otherThing {
  slice = append(slice, v)
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay, yeah that makes sense.

var (
c = it.it.Current()
vt = it.opts.ValueTransform()
vals = make([]float64, len(c.values))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here too

var (
c = it.it.Current()
stepDPs = c.Values()
dpList = make([]ts.Datapoints, len(stepDPs))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and on line 245 too

@@ -293,6 +293,18 @@ func getBinaryOpType(opType promql.ItemType) string {
}
}

// GetUnaryOpType returns the M3 unary op type based on the Prom op type
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit; full stops at end of comments


unaryType, ok := GetUnaryOpType(n.Op)
if !ok {
return fmt.Errorf("only + and - operators allowed for unary expressions, received: %s", n.Op.String())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit; instead, have GetUnaryOpType return a (unaryType, error) and just return this error there

@@ -293,6 +293,18 @@ func getBinaryOpType(opType promql.ItemType) string {
}
}

// GetUnaryOpType returns the M3 unary op type based on the Prom op type
func GetUnaryOpType(opType promql.ItemType) (string, bool) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit; does this need to be exported?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, good call.

val[i].Value = vt(dp.Value)
var (
c = it.it.Current()
stepDPs = c.Values()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit; values reads a bit better

val[i].Value = vt(dp.Value)
var (
c = it.it.Current()
seriesDPs = c.datapoints
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit; values reads better

@@ -418,3 +419,224 @@ func TestUnconsolidatedSeriesIter(t *testing.T) {

assert.Equal(t, expected, actual.Datapoints())
}

// negative value offset tests

Copy link
Collaborator

@arnikola arnikola May 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: newline

return fmt.Errorf("only + and - operators allowed for unary expressions, received: %s", n.Op.String())
}

return p.addLazyTransform(0, lazy.UnaryType, unaryType)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit janky; I think it's better to split the functions up for now (i.e. noops if it's plus, and creates a value transform otherwise)

@@ -248,7 +248,7 @@ func NewFunctionExpr(
return p, true, err

default:
// TODO: handle other types
// TODO: handle other types.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit; can probably remove this, think we handle all types

@@ -76,6 +77,39 @@ func TestInvalidOffset(t *testing.T) {
require.Error(t, err)
}

func TestUnary(t *testing.T) {
q := "-up"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

worth adding +up case? Can probably generalize this to be like

for _, q := range []string{"+up","-up"} {
....
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+ skips the unary op, so its just a fetch. Will add a test though.

ctrl := gomock.NewController(t)
bb := NewMockBlock(ctrl)
defer ctrl.Finish()
offset := time.Duration(0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mind adding one with both transform and offset?

defer ctrl.Finish()
b := NewMockBlock(ctrl)
offset := time.Duration(0)
off := NewLazyBlock(b, testLazyOpts(offset, -1.0))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can do testLazyOpts(0, -1.0) and it'll typecast it properly

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah just figured I'd be more explicit with it being a duration.

Copy link
Collaborator

@arnikola arnikola left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM; some suggestions for additional tests but up to you

stepVals = c.Values()
)

vals := make([]float64, 0, len(stepVals))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

longer term, instead of allocating for each Current() call, you can reuse a field in the struct. it'd look something like this:

type lazyStepIter struct {
  it   StepIter		
  opts LazyOptions
  values []float64
}

func (it *lazyStepIter) Current() Step {
var (
	c        = it.it.Current()
	tt, vt   = it.opts.TimeTransform(), it.opts.ValueTransform()
	stepVals = c.Values()
)
it.values = it.values[:0]
if cap(it.values) < len(stepVals) {
  it.values = make([]float64, 0, len(stepVals))
}
...
  return ColStep{ 
    ...
    values: it.values,
  }
}

note: this might cause issues if the callers of the this function are relying on the returned value from this function to be valid after multiple calls to Next()/Current(). Dunno how it's used so can't say for sure. Maybe file an issue to look into this

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we do it this way, would make sense to move all this logic into the Next function so we don't have to recalculate 👍

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, Next() would definitely be the better place for it.

Copy link
Collaborator

@prateek prateek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@benraskin92 benraskin92 merged commit 7c01a13 into master May 24, 2019
@benraskin92 benraskin92 deleted the braskin/unary branch May 24, 2019 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

m3query error
3 participants