commit
49327f69f1
|
@ -4,6 +4,7 @@
|
||||||
- [#4141](https://github.com/influxdb/influxdb/pull/4141): Control whether each query should be logged
|
- [#4141](https://github.com/influxdb/influxdb/pull/4141): Control whether each query should be logged
|
||||||
- [#4065](https://github.com/influxdb/influxdb/pull/4065): Added precision support in cmd client. Thanks @sbouchex
|
- [#4065](https://github.com/influxdb/influxdb/pull/4065): Added precision support in cmd client. Thanks @sbouchex
|
||||||
- [#4140](https://github.com/influxdb/influxdb/pull/4140): Make storage engine configurable
|
- [#4140](https://github.com/influxdb/influxdb/pull/4140): Make storage engine configurable
|
||||||
|
- [#4161](https://github.com/influxdb/influxdb/pull/4161): Implement bottom selector function
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
- [#3457](https://github.com/influxdb/influxdb/issues/3457): [0.9.3] cannot select field names with prefix + "." that match the measurement name
|
- [#3457](https://github.com/influxdb/influxdb/issues/3457): [0.9.3] cannot select field names with prefix + "." that match the measurement name
|
||||||
|
|
|
@ -77,9 +77,9 @@ func initializeMapFunc(c *influxql.Call) (mapFunc, error) {
|
||||||
return MapFirst, nil
|
return MapFirst, nil
|
||||||
case "last":
|
case "last":
|
||||||
return MapLast, nil
|
return MapLast, nil
|
||||||
case "top":
|
case "top", "bottom":
|
||||||
return func(itr iterator) interface{} {
|
return func(itr iterator) interface{} {
|
||||||
return MapTop(itr, c)
|
return MapTopBottom(itr, c)
|
||||||
}, nil
|
}, nil
|
||||||
case "percentile":
|
case "percentile":
|
||||||
return MapEcho, nil
|
return MapEcho, nil
|
||||||
|
@ -129,9 +129,9 @@ func initializeReduceFunc(c *influxql.Call) (reduceFunc, error) {
|
||||||
return ReduceFirst, nil
|
return ReduceFirst, nil
|
||||||
case "last":
|
case "last":
|
||||||
return ReduceLast, nil
|
return ReduceLast, nil
|
||||||
case "top":
|
case "top", "bottom":
|
||||||
return func(values []interface{}) interface{} {
|
return func(values []interface{}) interface{} {
|
||||||
return ReduceTop(values, c)
|
return ReduceTopBottom(values, c)
|
||||||
}, nil
|
}, nil
|
||||||
case "percentile":
|
case "percentile":
|
||||||
return func(values []interface{}) interface{} {
|
return func(values []interface{}) interface{} {
|
||||||
|
@ -1164,23 +1164,27 @@ type PositionPoint struct {
|
||||||
Tags map[string]string
|
Tags map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
type topMapOut struct {
|
type topBottomMapOut struct {
|
||||||
*positionOut
|
*positionOut
|
||||||
|
bottom bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *topMapOut) Len() int { return len(t.points) }
|
func (t *topBottomMapOut) 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 *topBottomMapOut) 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) Less(i, j int) bool {
|
||||||
return t.positionPointLess(&t.points[i], &t.points[j])
|
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
|
// old C trick makes this code easier to read. Imagine
|
||||||
// that the OP in "cmp(i, j) OP 0" is the comparison you want
|
// that the OP in "cmp(i, j) OP 0" is the comparison you want
|
||||||
// between i and j
|
// between i and j
|
||||||
cmpt, a, b := typeCompare(pa.Value, pb.Value)
|
cmpt, a, b := typeCompare(pa.Value, pb.Value)
|
||||||
cmpv := valueCompare(a, b)
|
cmpv := valueCompare(a, b)
|
||||||
if cmpv != 0 {
|
if cmpv != 0 {
|
||||||
|
if t.bottom {
|
||||||
|
return cmpv > 0
|
||||||
|
}
|
||||||
return cmpv < 0
|
return cmpv < 0
|
||||||
}
|
}
|
||||||
if cmpt != 0 {
|
if cmpt != 0 {
|
||||||
|
@ -1194,29 +1198,30 @@ func (t *topMapOut) positionPointLess(pa, pb *PositionPoint) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We never use this function, so make it a no-op.
|
// 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")
|
panic("someone used the function")
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function doesn't return anything meaningful, since we don't look at the
|
// 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.
|
// 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]
|
t.points = t.points[:len(t.points)-1]
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *topMapOut) insert(p PositionPoint) {
|
func (t *topBottomMapOut) insert(p PositionPoint) {
|
||||||
t.points[0] = p
|
t.points[0] = p
|
||||||
heap.Fix(t, 0)
|
heap.Fix(t, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
type topReduceOut struct {
|
type topBottomReduceOut struct {
|
||||||
positionOut
|
positionOut
|
||||||
|
bottom bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t topReduceOut) Len() int { return len(t.points) }
|
func (t topBottomReduceOut) 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 topBottomReduceOut) 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) Less(i, j int) bool {
|
||||||
// Now sort by time first, not value
|
// Now sort by time first, not value
|
||||||
|
|
||||||
k1, k2 := t.points[i].Time, t.points[j].Time
|
k1, k2 := t.points[i].Time, t.points[j].Time
|
||||||
|
@ -1226,6 +1231,9 @@ func (t topReduceOut) Less(i, j int) bool {
|
||||||
cmpt, a, b := typeCompare(t.points[i].Value, t.points[j].Value)
|
cmpt, a, b := typeCompare(t.points[i].Value, t.points[j].Value)
|
||||||
cmpv := valueCompare(a, b)
|
cmpv := valueCompare(a, b)
|
||||||
if cmpv != 0 {
|
if cmpv != 0 {
|
||||||
|
if t.bottom {
|
||||||
|
return cmpv < 0
|
||||||
|
}
|
||||||
return cmpv > 0
|
return cmpv > 0
|
||||||
}
|
}
|
||||||
if cmpt != 0 {
|
if cmpt != 0 {
|
||||||
|
@ -1292,17 +1300,24 @@ func (m *mapIter) Next() (time int64, value interface{}) {
|
||||||
return -1, nil
|
return -1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MapTop emits the top data points for each group by interval
|
// MapTopBottom emits the top/bottom data points for each group by interval
|
||||||
func MapTop(itr iterator, c *influxql.Call) interface{} {
|
func MapTopBottom(itr iterator, c *influxql.Call) interface{} {
|
||||||
// Capture the limit if it was specified in the call
|
// Capture the limit if it was specified in the call
|
||||||
lit, _ := c.Args[len(c.Args)-1].(*influxql.NumberLiteral)
|
lit, _ := c.Args[len(c.Args)-1].(*influxql.NumberLiteral)
|
||||||
limit := int(lit.Val)
|
limit := int(lit.Val)
|
||||||
|
|
||||||
out := positionOut{callArgs: topCallArgs(c)}
|
out := positionOut{callArgs: topCallArgs(c)}
|
||||||
out.points = make([]PositionPoint, 0, limit)
|
out.points = make([]PositionPoint, 0, limit)
|
||||||
minheap := topMapOut{&out}
|
minheap := topBottomMapOut{
|
||||||
|
&out,
|
||||||
|
c.Name == "bottom",
|
||||||
|
}
|
||||||
tagmap := make(map[string]PositionPoint)
|
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
|
// buffer so we don't allocate every time through
|
||||||
var pp PositionPoint
|
var pp PositionPoint
|
||||||
if len(c.Args) > 2 {
|
if len(c.Args) > 2 {
|
||||||
|
@ -1357,7 +1372,7 @@ func MapTop(itr iterator, c *influxql.Call) interface{} {
|
||||||
// rid of another sort order.
|
// rid of another sort order.
|
||||||
heap.Init(&minheap)
|
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.
|
// during iteration.
|
||||||
//
|
//
|
||||||
// we want these values in ascending sorted order. We can achieve this by iteratively
|
// we want these values in ascending sorted order. We can achieve this by iteratively
|
||||||
|
@ -1379,12 +1394,12 @@ func MapTop(itr iterator, c *influxql.Call) interface{} {
|
||||||
|
|
||||||
// ReduceTop computes the top values for each key.
|
// ReduceTop computes the top values for each key.
|
||||||
// This function assumes that its inputs are in sorted ascending order.
|
// 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)
|
lit, _ := c.Args[len(c.Args)-1].(*influxql.NumberLiteral)
|
||||||
limit := int(lit.Val)
|
limit := int(lit.Val)
|
||||||
|
|
||||||
out := positionOut{callArgs: topCallArgs(c)}
|
out := positionOut{callArgs: topCallArgs(c)}
|
||||||
minheap := topMapOut{&out}
|
minheap := topBottomMapOut{&out, c.Name == "bottom"}
|
||||||
results := make([]PositionPoints, 0, len(values))
|
results := make([]PositionPoints, 0, len(values))
|
||||||
out.points = make([]PositionPoint, 0, limit)
|
out.points = make([]PositionPoint, 0, limit)
|
||||||
for _, v := range values {
|
for _, v := range values {
|
||||||
|
@ -1411,7 +1426,7 @@ func ReduceTop(values []interface{}, c *influxql.Call) interface{} {
|
||||||
if whichselected == -1 {
|
if whichselected == -1 {
|
||||||
// none of the points have any values
|
// none of the points have any values
|
||||||
// so we can return what we have now
|
// so we can return what we have now
|
||||||
sort.Sort(topReduceOut{out})
|
sort.Sort(topBottomReduceOut{out, c.Name == "bottom"})
|
||||||
return out.points
|
return out.points
|
||||||
}
|
}
|
||||||
v := results[whichselected]
|
v := results[whichselected]
|
||||||
|
@ -1420,7 +1435,7 @@ func ReduceTop(values []interface{}, c *influxql.Call) interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we need to resort the tops by time
|
// now we need to resort the tops by time
|
||||||
sort.Sort(topReduceOut{out})
|
sort.Sort(topBottomReduceOut{out, c.Name == "bottom"})
|
||||||
return out.points
|
return out.points
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -480,7 +480,7 @@ func BenchmarkGetSortedRangeBySort(b *testing.B) {
|
||||||
benchGetSortedRangeResults = results
|
benchGetSortedRangeResults = results
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMapTop(t *testing.T) {
|
func TestMapTopBottom(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
skip bool
|
skip bool
|
||||||
|
@ -489,7 +489,7 @@ func TestMapTop(t *testing.T) {
|
||||||
call *influxql.Call
|
call *influxql.Call
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "int64 - basic",
|
name: "top int64 - basic",
|
||||||
iter: &testIterator{
|
iter: &testIterator{
|
||||||
values: []testPoint{
|
values: []testPoint{
|
||||||
{"", 10, int64(99), map[string]string{"host": "a"}},
|
{"", 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}}},
|
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{
|
iter: &testIterator{
|
||||||
values: []testPoint{
|
values: []testPoint{
|
||||||
{"", 10, int64(99), map[string]string{"host": "a"}},
|
{"", 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}}},
|
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{
|
iter: &testIterator{
|
||||||
values: []testPoint{
|
values: []testPoint{
|
||||||
{"", 20, int64(99), map[string]string{"host": "a"}},
|
{"", 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}}},
|
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{
|
iter: &testIterator{
|
||||||
values: []testPoint{
|
values: []testPoint{
|
||||||
{"", 10, int64(99), map[string]string{"host": "b"}},
|
{"", 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}}},
|
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{
|
iter: &testIterator{
|
||||||
values: []testPoint{
|
values: []testPoint{
|
||||||
{"", 10, int64(99), map[string]string{"host": "a"}},
|
{"", 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}}},
|
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{
|
iter: &testIterator{
|
||||||
values: []testPoint{
|
values: []testPoint{
|
||||||
{"", 10, float64(99), map[string]string{"host": "a"}},
|
{"", 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}}},
|
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{
|
iter: &testIterator{
|
||||||
values: []testPoint{
|
values: []testPoint{
|
||||||
{"", 10, float64(99), map[string]string{"host": "a"}},
|
{"", 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}}},
|
call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bools",
|
name: "top bools",
|
||||||
iter: &testIterator{
|
iter: &testIterator{
|
||||||
values: []testPoint{
|
values: []testPoint{
|
||||||
{"", 10, true, map[string]string{"host": "a"}},
|
{"", 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}}},
|
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 {
|
for _, test := range tests {
|
||||||
if test.skip {
|
if test.skip {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
values := MapTop(test.iter, test.call).(PositionPoints)
|
values := MapTopBottom(test.iter, test.call).(PositionPoints)
|
||||||
t.Logf("Test: %s", test.name)
|
t.Logf("Test: %s", test.name)
|
||||||
if exp, got := len(test.exp.points), len(values); exp != got {
|
if exp, got := len(test.exp.points), len(values); exp != got {
|
||||||
t.Errorf("Wrong number of values. exp %v got %v", 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 {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
skip bool
|
skip bool
|
||||||
|
@ -653,7 +792,7 @@ func TestReduceTop(t *testing.T) {
|
||||||
call *influxql.Call
|
call *influxql.Call
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "int64 - single map",
|
name: "top int64 - single map",
|
||||||
values: []interface{}{
|
values: []interface{}{
|
||||||
PositionPoints{
|
PositionPoints{
|
||||||
{10, int64(99), map[string]string{"host": "a"}},
|
{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}}},
|
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{}{
|
values: []interface{}{
|
||||||
PositionPoints{
|
PositionPoints{
|
||||||
{10, int64(99), map[string]string{"host": "a"}},
|
{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}}},
|
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{}{
|
values: []interface{}{
|
||||||
PositionPoints{
|
PositionPoints{
|
||||||
{10, int64(99), map[string]string{"host": "a"}},
|
{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}}},
|
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{}{
|
values: []interface{}{
|
||||||
PositionPoints{
|
PositionPoints{
|
||||||
{10, int64(99), map[string]string{"host": "a"}},
|
{10, int64(99), map[string]string{"host": "a"}},
|
||||||
|
@ -718,7 +857,7 @@ func TestReduceTop(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
skip: true,
|
skip: true,
|
||||||
name: "int64 - double map with non-matching tags",
|
name: "top int64 - double map with non-matching tags",
|
||||||
values: []interface{}{
|
values: []interface{}{
|
||||||
PositionPoints{
|
PositionPoints{
|
||||||
{10, int64(99), map[string]string{"host": "a"}},
|
{10, int64(99), map[string]string{"host": "a"}},
|
||||||
|
@ -731,7 +870,88 @@ func TestReduceTop(t *testing.T) {
|
||||||
PositionPoint{10, int64(99), map[string]string{"host": "a"}},
|
PositionPoint{10, int64(99), map[string]string{"host": "a"}},
|
||||||
PositionPoint{20, int64(55), map[string]string{"host": "b"}},
|
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}}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,7 +959,7 @@ func TestReduceTop(t *testing.T) {
|
||||||
if test.skip {
|
if test.skip {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
values := ReduceTop(test.values, test.call)
|
values := ReduceTopBottom(test.values, test.call)
|
||||||
t.Logf("Test: %s", test.name)
|
t.Logf("Test: %s", test.name)
|
||||||
if values != nil {
|
if values != nil {
|
||||||
v, _ := values.(PositionPoints)
|
v, _ := values.(PositionPoints)
|
||||||
|
|
Loading…
Reference in New Issue