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

Mean and percentile function fixes #2404

Merged
merged 5 commits into from
Apr 23, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## v0.9.0-rc28 [unreleased]

### Bugfixes
- [#2374](https://github.com/influxdb/influxdb/issues/2374): Two different panics during SELECT percentile
Copy link
Contributor

Choose a reason for hiding this comment

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

I know this is a small thing, but I am pretty sure @pauldix does not want this format. He specially told me links to PRs only a few months back. Not a big deal, but you should check with him when you get a chance.

Copy link
Member

Choose a reason for hiding this comment

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

Link to PR is preferable, but either works. If the PR mentions the issue then they'll be linked together either way.

- [#2404](https://github.com/influxdb/influxdb/pull/2404): Mean and percentile function fixes

## v0.9.0-rc27 [04-23-2015]

### Features
Expand Down
24 changes: 6 additions & 18 deletions cmd/influxd/server_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1456,9 +1456,7 @@ func TestSingleServerDiags(t *testing.T) {
t.Skip(fmt.Sprintf("skipping '%s'", testName))
}
dir := tempfile()
defer func() {
os.RemoveAll(dir)
}()
defer os.RemoveAll(dir)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think go lint will complain about these changes. Not sure, but I think so. We don't run lint right now, so perhaps it doesn't matter.


config := main.NewConfig()
config.Monitoring.Enabled = true
Expand All @@ -1476,9 +1474,7 @@ func TestSingleServer(t *testing.T) {
t.Skip(fmt.Sprintf("skipping '%s'", testName))
}
dir := tempfile()
defer func() {
os.RemoveAll(dir)
}()
defer os.RemoveAll(dir)

nodes := createCombinedNodeCluster(t, testName, dir, 1, nil)
defer nodes.Close()
Expand All @@ -1495,9 +1491,7 @@ func Test3NodeServer(t *testing.T) {
t.Skip(fmt.Sprintf("skipping '%s'", testName))
}
dir := tempfile()
defer func() {
os.RemoveAll(dir)
}()
defer os.RemoveAll(dir)

nodes := createCombinedNodeCluster(t, testName, dir, 3, nil)
defer nodes.Close()
Expand All @@ -1514,9 +1508,7 @@ func Test3NodeServerFailover(t *testing.T) {
t.Skip(fmt.Sprintf("skipping '%s'", testName))
}
dir := tempfile()
defer func() {
os.RemoveAll(dir)
}()
defer os.RemoveAll(dir)

nodes := createCombinedNodeCluster(t, testName, dir, 3, nil)

Expand All @@ -1539,9 +1531,7 @@ func Test5NodeClusterPartiallyReplicated(t *testing.T) {
t.Skip(fmt.Sprintf("skipping '%s'", testName))
}
dir := tempfile()
defer func() {
os.RemoveAll(dir)
}()
defer os.RemoveAll(dir)

nodes := createCombinedNodeCluster(t, testName, dir, 5, nil)
defer nodes.Close()
Expand All @@ -1557,9 +1547,7 @@ func TestClientLibrary(t *testing.T) {
t.Skip(fmt.Sprintf("skipping '%s'", testName))
}
dir := tempfile()
defer func() {
os.RemoveAll(dir)
}()
defer os.RemoveAll(dir)

now := time.Now().UTC()

Expand Down
15 changes: 14 additions & 1 deletion influxql/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ func InitializeReduceFunc(c *Call) (ReduceFunc, error) {
case "last":
return ReduceLast, nil
case "percentile":
if len(c.Args) != 2 {
return nil, fmt.Errorf("expected float argument in percentile()")
}

lit, ok := c.Args[1].(*NumberLiteral)
if !ok {
return nil, fmt.Errorf("expected float argument in percentile()")
Expand Down Expand Up @@ -213,7 +217,12 @@ func MapMean(itr Iterator) interface{} {
out.Count++
out.Mean += (v.(float64) - out.Mean) / float64(out.Count)
}
return out

if out.Count > 0 {
return out
}

return nil
}

type meanMapOutput struct {
Expand Down Expand Up @@ -547,6 +556,10 @@ func ReducePercentile(percentile float64) ReduceFunc {
var allValues []float64

for _, v := range values {
if v == nil {
continue
}

vals := v.([]interface{})
for _, v := range vals {
allValues = append(allValues, v.(float64))
Expand Down
114 changes: 114 additions & 0 deletions influxql/functions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package influxql

import "testing"

type point struct {
seriesID uint64
timestamp int64
value interface{}
}

type testIterator struct {
values []point
}

func (t *testIterator) Next() (seriesID uint64, timestamp int64, value interface{}) {
if len(t.values) > 0 {
v := t.values[0]
t.values = t.values[1:]
return v.seriesID, v.timestamp, v.value
}
return 0, 0, nil
}

func TestMapMeanNoValues(t *testing.T) {
iter := &testIterator{}
if got := MapMean(iter); got != nil {
t.Errorf("output mismatch: exp nil got %v", got)
}
}

func TestMapMean(t *testing.T) {

tests := []struct {
input []point
output *meanMapOutput
}{
{ // Single point
input: []point{
point{0, 1, 1.0},
},
output: &meanMapOutput{1, 1},
},
{ // Two points
input: []point{
point{0, 1, 2.0},
point{0, 2, 8.0},
},
output: &meanMapOutput{2, 5.0},
},
}

for _, test := range tests {
iter := &testIterator{
values: test.input,
}

got := MapMean(iter)
if got == nil {
t.Fatalf("MapMean(%v): output mismatch: exp %v got %v", test.input, test.output, got)
}

if got.(*meanMapOutput).Count != test.output.Count || got.(*meanMapOutput).Mean != test.output.Mean {
t.Errorf("output mismatch: exp %v got %v", test.output, got)
}

}
}

func TestInitializeReduceFuncPercentile(t *testing.T) {
// No args
c := &Call{
Name: "percentile",
Args: []Expr{},
}
_, err := InitializeReduceFunc(c)
if err == nil {
t.Errorf("InitializedReduceFunc(%v) expected error. got nil", c)
}

if exp := "expected float argument in percentile()"; err.Error() != exp {
t.Errorf("InitializedReduceFunc(%v) mismatch. exp %v got %v", c, exp, err.Error())
}

// No percentile arg
c = &Call{
Name: "percentile",
Args: []Expr{
&VarRef{Val: "field1"},
},
}

_, err = InitializeReduceFunc(c)
if err == nil {
t.Errorf("InitializedReduceFunc(%v) expected error. got nil", c)
}

if exp := "expected float argument in percentile()"; err.Error() != exp {
t.Errorf("InitializedReduceFunc(%v) mismatch. exp %v got %v", c, exp, err.Error())
}
}

func TestReducePercentileNil(t *testing.T) {

// ReducePercentile should ignore nil values when calculating the percentile
fn := ReducePercentile(100)
input := []interface{}{
nil,
}

got := fn(input)
if got != nil {
t.Fatalf("ReducePercentile(100) returned wrong type. exp nil got %v", got)
}
}