From b5fc2a96b1c4aaf5e3854c9866e793c623e2fb53 Mon Sep 17 00:00:00 2001 From: Daniel Morsing Date: Fri, 18 Sep 2015 12:56:12 +0000 Subject: [PATCH 1/3] Implement bottom After the rework of the ordering for top, this was just a matter of adding a flag telling the minheap which way the values should be sorted. --- tsdb/functions.go | 55 +++++---- tsdb/functions_test.go | 257 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 274 insertions(+), 38 deletions(-) diff --git a/tsdb/functions.go b/tsdb/functions.go index 65f26768a7..1e9b21a532 100644 --- a/tsdb/functions.go +++ b/tsdb/functions.go @@ -77,9 +77,9 @@ func initializeMapFunc(c *influxql.Call) (mapFunc, error) { return MapFirst, nil case "last": return MapLast, nil - case "top": + case "top", "bottom": return func(itr iterator) interface{} { - return MapTop(itr, c) + return MapTopBottom(itr, c) }, nil case "percentile": return MapEcho, nil @@ -129,9 +129,9 @@ func initializeReduceFunc(c *influxql.Call) (reduceFunc, error) { return ReduceFirst, nil case "last": return ReduceLast, nil - case "top": + case "top", "bottom": return func(values []interface{}) interface{} { - return ReduceTop(values, c) + return ReduceTopBottom(values, c) }, nil case "percentile": return func(values []interface{}) interface{} { @@ -1160,23 +1160,27 @@ type PositionPoint struct { Tags map[string]string } -type topMapOut struct { +type topBottomMapOut struct { *positionOut + bottom bool } -func (t *topMapOut) Len() int { return len(t.points) } -func (t *topMapOut) Swap(i, j int) { t.points[i], t.points[j] = t.points[j], t.points[i] } -func (t *topMapOut) Less(i, j int) bool { +func (t *topBottomMapOut) Len() int { return len(t.points) } +func (t *topBottomMapOut) Swap(i, j int) { t.points[i], t.points[j] = t.points[j], t.points[i] } +func (t *topBottomMapOut) Less(i, j int) bool { return t.positionPointLess(&t.points[i], &t.points[j]) } -func (t *topMapOut) positionPointLess(pa, pb *PositionPoint) bool { +func (t *topBottomMapOut) positionPointLess(pa, pb *PositionPoint) bool { // old C trick makes this code easier to read. Imagine // that the OP in "cmp(i, j) OP 0" is the comparison you want // between i and j cmpt, a, b := typeCompare(pa.Value, pb.Value) cmpv := valueCompare(a, b) if cmpv != 0 { + if t.bottom { + return cmpv > 0 + } return cmpv < 0 } if cmpt != 0 { @@ -1190,24 +1194,25 @@ func (t *topMapOut) positionPointLess(pa, pb *PositionPoint) bool { } // We never use this function, so make it a no-op. -func (t *topMapOut) Push(i interface{}) { +func (t *topBottomMapOut) Push(i interface{}) { panic("someone used the function") } // this function doesn't return anything meaningful, since we don't look at the // return value and we don't want to allocate for generating an interface. -func (t *topMapOut) Pop() interface{} { +func (t *topBottomMapOut) Pop() interface{} { t.points = t.points[:len(t.points)-1] return nil } -func (t *topMapOut) insert(p PositionPoint) { +func (t *topBottomMapOut) insert(p PositionPoint) { t.points[0] = p heap.Fix(t, 0) } type topReduceOut struct { positionOut + bottom bool } func (t topReduceOut) Len() int { return len(t.points) } @@ -1222,6 +1227,9 @@ func (t topReduceOut) Less(i, j int) bool { cmpt, a, b := typeCompare(t.points[i].Value, t.points[j].Value) cmpv := valueCompare(a, b) if cmpv != 0 { + if t.bottom { + return cmpv < 0 + } return cmpv > 0 } if cmpt != 0 { @@ -1288,17 +1296,24 @@ func (m *mapIter) Next() (time int64, value interface{}) { return -1, nil } -// MapTop emits the top data points for each group by interval -func MapTop(itr iterator, c *influxql.Call) interface{} { +// MapTopBottom emits the top/bottom data points for each group by interval +func MapTopBottom(itr iterator, c *influxql.Call) interface{} { // Capture the limit if it was specified in the call lit, _ := c.Args[len(c.Args)-1].(*influxql.NumberLiteral) limit := int(lit.Val) out := positionOut{callArgs: topCallArgs(c)} out.points = make([]PositionPoint, 0, limit) - minheap := topMapOut{&out} + minheap := topBottomMapOut{ + &out, + c.Name == "bottom", + } tagmap := make(map[string]PositionPoint) + // throughout this function, we refer to max and top. This is by the ordering specified by + // minheap, not the ordering based on value. Since this function handles both top and bottom + // max can be the lowest valued entry. + // buffer so we don't allocate every time through var pp PositionPoint if len(c.Args) > 2 { @@ -1353,7 +1368,7 @@ func MapTop(itr iterator, c *influxql.Call) interface{} { // rid of another sort order. heap.Init(&minheap) } - // minheap should now contain the largest values that were encountered + // minheap should now contain the largest/smallest values that were encountered // during iteration. // // we want these values in ascending sorted order. We can achieve this by iteratively @@ -1375,12 +1390,12 @@ func MapTop(itr iterator, c *influxql.Call) interface{} { // ReduceTop computes the top values for each key. // This function assumes that its inputs are in sorted ascending order. -func ReduceTop(values []interface{}, c *influxql.Call) interface{} { +func ReduceTopBottom(values []interface{}, c *influxql.Call) interface{} { lit, _ := c.Args[len(c.Args)-1].(*influxql.NumberLiteral) limit := int(lit.Val) out := positionOut{callArgs: topCallArgs(c)} - minheap := topMapOut{&out} + minheap := topBottomMapOut{&out, c.Name == "bottom"} results := make([]PositionPoints, 0, len(values)) out.points = make([]PositionPoint, 0, limit) for _, v := range values { @@ -1407,7 +1422,7 @@ func ReduceTop(values []interface{}, c *influxql.Call) interface{} { if whichselected == -1 { // none of the points have any values // so we can return what we have now - sort.Sort(topReduceOut{out}) + sort.Sort(topReduceOut{out, c.Name == "bottom"}) return out.points } v := results[whichselected] @@ -1416,7 +1431,7 @@ func ReduceTop(values []interface{}, c *influxql.Call) interface{} { } // now we need to resort the tops by time - sort.Sort(topReduceOut{out}) + sort.Sort(topReduceOut{out, c.Name == "bottom"}) return out.points } diff --git a/tsdb/functions_test.go b/tsdb/functions_test.go index e43751923c..31925ae02b 100644 --- a/tsdb/functions_test.go +++ b/tsdb/functions_test.go @@ -480,7 +480,7 @@ func BenchmarkGetSortedRangeBySort(b *testing.B) { benchGetSortedRangeResults = results } -func TestMapTop(t *testing.T) { +func TestMapTopBottom(t *testing.T) { tests := []struct { name string skip bool @@ -489,7 +489,7 @@ func TestMapTop(t *testing.T) { call *influxql.Call }{ { - name: "int64 - basic", + name: "top int64 - basic", iter: &testIterator{ values: []testPoint{ {"", 10, int64(99), map[string]string{"host": "a"}}, @@ -506,7 +506,7 @@ func TestMapTop(t *testing.T) { call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { - name: "int64 - basic with tag", + name: "top int64 - basic with tag", iter: &testIterator{ values: []testPoint{ {"", 10, int64(99), map[string]string{"host": "a"}}, @@ -524,7 +524,7 @@ func TestMapTop(t *testing.T) { call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.VarRef{Val: "host"}, &influxql.NumberLiteral{Val: 2}}}, }, { - name: "int64 - tie on value, resolve based on time", + name: "top int64 - tie on value, resolve based on time", iter: &testIterator{ values: []testPoint{ {"", 20, int64(99), map[string]string{"host": "a"}}, @@ -542,7 +542,7 @@ func TestMapTop(t *testing.T) { call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { - name: "int64 - tie on value, time, resolve based on tags", + name: "top int64 - tie on value, time, resolve based on tags", iter: &testIterator{ values: []testPoint{ {"", 10, int64(99), map[string]string{"host": "b"}}, @@ -560,7 +560,7 @@ func TestMapTop(t *testing.T) { call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.VarRef{Val: "host"}, &influxql.NumberLiteral{Val: 2}}}, }, { - name: "mixed numerics - ints", + name: "top mixed numerics - ints", iter: &testIterator{ values: []testPoint{ {"", 10, int64(99), map[string]string{"host": "a"}}, @@ -577,7 +577,7 @@ func TestMapTop(t *testing.T) { call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { - name: "mixed numerics - ints & floats", + name: "top mixed numerics - ints & floats", iter: &testIterator{ values: []testPoint{ {"", 10, float64(99), map[string]string{"host": "a"}}, @@ -594,7 +594,7 @@ func TestMapTop(t *testing.T) { call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { - name: "mixed numerics - ints, floats, & strings", + name: "top mixed numerics - ints, floats, & strings", iter: &testIterator{ values: []testPoint{ {"", 10, float64(99), map[string]string{"host": "a"}}, @@ -611,7 +611,7 @@ func TestMapTop(t *testing.T) { call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { - name: "bools", + name: "top bools", iter: &testIterator{ values: []testPoint{ {"", 10, true, map[string]string{"host": "a"}}, @@ -627,13 +627,152 @@ func TestMapTop(t *testing.T) { }, call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, + { + name: "bottom int64 - basic", + iter: &testIterator{ + values: []testPoint{ + {"", 10, int64(99), map[string]string{"host": "a"}}, + {"", 10, int64(53), map[string]string{"host": "b"}}, + {"", 20, int64(88), map[string]string{"host": "a"}}, + }, + }, + exp: positionOut{ + points: PositionPoints{ + PositionPoint{10, int64(53), map[string]string{"host": "b"}}, + PositionPoint{20, int64(88), map[string]string{"host": "a"}}, + }, + }, + call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, + }, + { + name: "bottom int64 - basic with tag", + iter: &testIterator{ + values: []testPoint{ + {"", 10, int64(20), map[string]string{"host": "a"}}, + {"", 20, int64(53), map[string]string{"host": "b"}}, + {"", 30, int64(30), map[string]string{"host": "a"}}, + }, + }, + exp: positionOut{ + callArgs: []string{"host"}, + points: PositionPoints{ + PositionPoint{10, int64(20), map[string]string{"host": "a"}}, + PositionPoint{20, int64(53), map[string]string{"host": "b"}}, + }, + }, + call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.VarRef{Val: "host"}, &influxql.NumberLiteral{Val: 2}}}, + }, + { + name: "bottom int64 - tie on value, resolve based on time", + iter: &testIterator{ + values: []testPoint{ + {"", 10, int64(53), map[string]string{"host": "a"}}, + {"", 20, int64(53), map[string]string{"host": "a"}}, + {"", 20, int64(53), map[string]string{"host": "a"}}, + }, + }, + exp: positionOut{ + callArgs: []string{"host"}, + points: PositionPoints{ + PositionPoint{10, int64(53), map[string]string{"host": "a"}}, + PositionPoint{20, int64(53), map[string]string{"host": "a"}}, + }, + }, + call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, + }, + { + name: "bottom int64 - tie on value, time, resolve based on tags", + iter: &testIterator{ + values: []testPoint{ + {"", 10, int64(99), map[string]string{"host": "b"}}, + {"", 10, int64(99), map[string]string{"host": "a"}}, + {"", 20, int64(100), map[string]string{"host": "a"}}, + }, + }, + exp: positionOut{ + callArgs: []string{"host"}, + points: PositionPoints{ + PositionPoint{10, int64(99), map[string]string{"host": "a"}}, + PositionPoint{10, int64(99), map[string]string{"host": "b"}}, + }, + }, + call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.VarRef{Val: "host"}, &influxql.NumberLiteral{Val: 2}}}, + }, + { + name: "bottom mixed numerics - ints", + iter: &testIterator{ + values: []testPoint{ + {"", 10, int64(99), map[string]string{"host": "a"}}, + {"", 10, int64(53), map[string]string{"host": "b"}}, + {"", 20, uint64(88), map[string]string{"host": "a"}}, + }, + }, + exp: positionOut{ + points: PositionPoints{ + PositionPoint{10, int64(53), map[string]string{"host": "b"}}, + PositionPoint{20, uint64(88), map[string]string{"host": "a"}}, + }, + }, + call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, + }, + { + name: "bottom mixed numerics - ints & floats", + iter: &testIterator{ + values: []testPoint{ + {"", 10, int64(99), map[string]string{"host": "a"}}, + {"", 10, float64(53), map[string]string{"host": "b"}}, + {"", 20, uint64(88), map[string]string{"host": "a"}}, + }, + }, + exp: positionOut{ + points: PositionPoints{ + PositionPoint{10, float64(53), map[string]string{"host": "b"}}, + PositionPoint{20, uint64(88), map[string]string{"host": "a"}}, + }, + }, + call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, + }, + { + name: "bottom mixed numerics - ints, floats, & strings", + iter: &testIterator{ + values: []testPoint{ + {"", 10, float64(99), map[string]string{"host": "a"}}, + {"", 10, int64(53), map[string]string{"host": "b"}}, + {"", 20, "88", map[string]string{"host": "a"}}, + }, + }, + exp: positionOut{ + points: PositionPoints{ + PositionPoint{10, int64(53), map[string]string{"host": "b"}}, + PositionPoint{10, float64(99), map[string]string{"host": "a"}}, + }, + }, + call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, + }, + { + name: "bottom bools", + iter: &testIterator{ + values: []testPoint{ + {"", 10, true, map[string]string{"host": "a"}}, + {"", 10, true, map[string]string{"host": "b"}}, + {"", 20, false, map[string]string{"host": "a"}}, + }, + }, + exp: positionOut{ + points: PositionPoints{ + PositionPoint{20, false, map[string]string{"host": "a"}}, + PositionPoint{10, true, map[string]string{"host": "a"}}, + }, + }, + call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, + }, } for _, test := range tests { if test.skip { continue } - values := MapTop(test.iter, test.call).(PositionPoints) + values := MapTopBottom(test.iter, test.call).(PositionPoints) t.Logf("Test: %s", test.name) if exp, got := len(test.exp.points), len(values); exp != got { t.Errorf("Wrong number of values. exp %v got %v", exp, got) @@ -644,7 +783,7 @@ func TestMapTop(t *testing.T) { } } -func TestReduceTop(t *testing.T) { +func TestReduceTopBottom(t *testing.T) { tests := []struct { name string skip bool @@ -653,7 +792,7 @@ func TestReduceTop(t *testing.T) { call *influxql.Call }{ { - name: "int64 - single map", + name: "top int64 - single map", values: []interface{}{ PositionPoints{ {10, int64(99), map[string]string{"host": "a"}}, @@ -668,7 +807,7 @@ func TestReduceTop(t *testing.T) { call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { - name: "int64 - double map", + name: "top int64 - double map", values: []interface{}{ PositionPoints{ {10, int64(99), map[string]string{"host": "a"}}, @@ -685,7 +824,7 @@ func TestReduceTop(t *testing.T) { call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { - name: "int64 - double map with nil", + name: "top int64 - double map with nil", values: []interface{}{ PositionPoints{ {10, int64(99), map[string]string{"host": "a"}}, @@ -701,7 +840,7 @@ func TestReduceTop(t *testing.T) { call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { - name: "int64 - double map with non-matching tags and tag selected", + name: "top int64 - double map with non-matching tags and tag selected", values: []interface{}{ PositionPoints{ {10, int64(99), map[string]string{"host": "a"}}, @@ -718,7 +857,7 @@ func TestReduceTop(t *testing.T) { }, { skip: true, - name: "int64 - double map with non-matching tags", + name: "top int64 - double map with non-matching tags", values: []interface{}{ PositionPoints{ {10, int64(99), map[string]string{"host": "a"}}, @@ -731,15 +870,97 @@ func TestReduceTop(t *testing.T) { PositionPoint{10, int64(99), map[string]string{"host": "a"}}, PositionPoint{20, int64(55), map[string]string{"host": "b"}}, }, - call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, + call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, + { + name: "bottom int64 - single map", + values: []interface{}{ + PositionPoints{ + {10, int64(53), map[string]string{"host": "b"}}, + {20, int64(88), map[string]string{"host": "a"}}, + {10, int64(99), map[string]string{"host": "a"}}, + }, + }, + exp: PositionPoints{ + PositionPoint{10, int64(53), map[string]string{"host": "b"}}, + PositionPoint{20, int64(88), map[string]string{"host": "a"}}, + }, + call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, + }, + { + name: "bottom int64 - double map", + values: []interface{}{ + PositionPoints{ + {10, int64(99), map[string]string{"host": "a"}}, + }, + PositionPoints{ + {10, int64(53), map[string]string{"host": "b"}}, + {20, int64(88), map[string]string{"host": "a"}}, + }, + }, + exp: PositionPoints{ + PositionPoint{10, int64(53), map[string]string{"host": "b"}}, + PositionPoint{20, int64(88), map[string]string{"host": "a"}}, + }, + call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, + }, + { + name: "bottom int64 - double map with nil", + values: []interface{}{ + PositionPoints{ + {10, int64(53), map[string]string{"host": "b"}}, + {20, int64(88), map[string]string{"host": "a"}}, + {10, int64(99), map[string]string{"host": "a"}}, + }, + nil, + }, + exp: PositionPoints{ + PositionPoint{10, int64(53), map[string]string{"host": "b"}}, + PositionPoint{20, int64(88), map[string]string{"host": "a"}}, + }, + call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, + }, + { + name: "bottom int64 - double map with non-matching tags and tag selected", + values: []interface{}{ + PositionPoints{ + {10, int64(53), map[string]string{"host": "b"}}, + {20, int64(88), map[string]string{}}, + {10, int64(99), map[string]string{"host": "a"}}, + }, + nil, + }, + exp: PositionPoints{ + PositionPoint{10, int64(53), map[string]string{"host": "b"}}, + PositionPoint{20, int64(88), map[string]string{}}, + }, + call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.VarRef{Val: "host"}, &influxql.NumberLiteral{Val: 2}}}, + }, + { + skip: true, + name: "bottom int64 - double map with non-matching tags", + values: []interface{}{ + PositionPoints{ + {10, int64(53), map[string]string{"host": "b"}}, + {20, int64(88), map[string]string{}}, + {10, int64(99), map[string]string{"host": "a"}}, + }, + nil, + }, + exp: PositionPoints{ + PositionPoint{10, int64(99), map[string]string{"host": "a"}}, + PositionPoint{20, int64(55), map[string]string{"host": "b"}}, + }, + call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, + }, + } for _, test := range tests { if test.skip { continue } - values := ReduceTop(test.values, test.call) + values := ReduceTopBottom(test.values, test.call) t.Logf("Test: %s", test.name) if values != nil { v, _ := values.(PositionPoints) From 5b248419733da8292c1b5a323cdefd6f9e2cce71 Mon Sep 17 00:00:00 2001 From: Daniel Morsing Date: Fri, 18 Sep 2015 15:04:09 +0000 Subject: [PATCH 2/3] rename topReduceOut Also, gofmt --- tsdb/functions.go | 12 ++++++------ tsdb/functions_test.go | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/tsdb/functions.go b/tsdb/functions.go index 1e9b21a532..6f0db60beb 100644 --- a/tsdb/functions.go +++ b/tsdb/functions.go @@ -1210,14 +1210,14 @@ func (t *topBottomMapOut) insert(p PositionPoint) { heap.Fix(t, 0) } -type topReduceOut struct { +type topBottomReduceOut struct { positionOut bottom bool } -func (t topReduceOut) Len() int { return len(t.points) } -func (t topReduceOut) Swap(i, j int) { t.points[i], t.points[j] = t.points[j], t.points[i] } -func (t topReduceOut) Less(i, j int) bool { +func (t topBottomReduceOut) Len() int { return len(t.points) } +func (t topBottomReduceOut) Swap(i, j int) { t.points[i], t.points[j] = t.points[j], t.points[i] } +func (t topBottomReduceOut) Less(i, j int) bool { // Now sort by time first, not value k1, k2 := t.points[i].Time, t.points[j].Time @@ -1422,7 +1422,7 @@ func ReduceTopBottom(values []interface{}, c *influxql.Call) interface{} { if whichselected == -1 { // none of the points have any values // so we can return what we have now - sort.Sort(topReduceOut{out, c.Name == "bottom"}) + sort.Sort(topBottomReduceOut{out, c.Name == "bottom"}) return out.points } v := results[whichselected] @@ -1431,7 +1431,7 @@ func ReduceTopBottom(values []interface{}, c *influxql.Call) interface{} { } // now we need to resort the tops by time - sort.Sort(topReduceOut{out, c.Name == "bottom"}) + sort.Sort(topBottomReduceOut{out, c.Name == "bottom"}) return out.points } diff --git a/tsdb/functions_test.go b/tsdb/functions_test.go index 31925ae02b..59fb948cfd 100644 --- a/tsdb/functions_test.go +++ b/tsdb/functions_test.go @@ -953,7 +953,6 @@ func TestReduceTopBottom(t *testing.T) { }, call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, - } for _, test := range tests { From 43f0a825eb9607e5d13aef4c9abe0d50731e1f65 Mon Sep 17 00:00:00 2001 From: Daniel Morsing Date: Mon, 21 Sep 2015 12:06:23 +0000 Subject: [PATCH 3/3] update CHANGLOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 402249c1b8..95c1141819 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features - [#4065](https://github.com/influxdb/influxdb/pull/4065): Added precision support in cmd client. Thanks @sbouchex +- [#4161](https://github.com/influxdb/influxdb/pull/4161): Implement bottom selector function. ## v0.9.4 [2015-09-14]