// Ensure that a integer iterator can be created for a min() call. func TestCallIterator_Min_Integer(t *testing.T) { itr, _ := influxql.NewCallIterator( &IntegerIterator{Points: []influxql.IntegerPoint{ {Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")}, {Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")}, {Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")}, {Time: 4, Value: 12, Tags: ParseTags("region=us-east,host=hostA")}, {Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")}, {Time: 5, Value: 20, Tags: ParseTags("region=us-east,host=hostA")}, {Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")}, }}, influxql.IteratorOptions{ Expr: MustParseExpr(`min("value")`), Dimensions: []string{"host"}, Interval: influxql.Interval{Duration: 5 * time.Nanosecond}, }, ) if a := Iterators([]influxql.Iterator{itr}).ReadAll(); !deep.Equal(a, [][]influxql.Point{ {&influxql.IntegerPoint{Time: 1, Value: 10, Tags: ParseTags("host=hostA"), Aggregated: 4}}, {&influxql.IntegerPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}}, {&influxql.IntegerPoint{Time: 5, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}}, {&influxql.IntegerPoint{Time: 23, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}}, }) { t.Fatalf("unexpected points: %s", spew.Sdump(a)) } }
// Ensure that a string iterator can be created for a count() call. func TestCallIterator_Count_String(t *testing.T) { itr, _ := influxql.NewCallIterator( &StringIterator{Points: []influxql.StringPoint{ {Name: "cpu", Time: 0, Value: "d", Tags: ParseTags("region=us-east,host=hostA")}, {Name: "cpu", Time: 1, Value: "c", Tags: ParseTags("region=us-west,host=hostB")}, {Name: "cpu", Time: 2, Value: "b", Tags: ParseTags("region=us-east,host=hostA")}, {Name: "cpu", Time: 1, Value: "b", Tags: ParseTags("region=us-west,host=hostA")}, {Name: "cpu", Time: 5, Value: "e", Tags: ParseTags("region=us-east,host=hostA")}, {Name: "cpu", Time: 23, Value: "a", Tags: ParseTags("region=us-west,host=hostB")}, {Name: "mem", Time: 23, Value: "b", Tags: ParseTags("region=us-west,host=hostB")}, }}, influxql.IteratorOptions{ Expr: MustParseExpr(`count("value")`), Dimensions: []string{"host"}, Interval: influxql.Interval{Duration: 5 * time.Nanosecond}, }, ) if a := Iterators([]influxql.Iterator{itr}).ReadAll(); !deep.Equal(a, [][]influxql.Point{ {&influxql.IntegerPoint{Name: "cpu", Time: 0, Value: 3, Tags: ParseTags("host=hostA"), Aggregated: 3}}, {&influxql.IntegerPoint{Name: "cpu", Time: 0, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}}, {&influxql.IntegerPoint{Name: "cpu", Time: 5, Value: 1, Tags: ParseTags("host=hostA"), Aggregated: 1}}, {&influxql.IntegerPoint{Name: "cpu", Time: 20, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}}, {&influxql.IntegerPoint{Name: "mem", Time: 20, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}}, }) { t.Fatalf("unexpected points: %s", spew.Sdump(a)) } }
// Ensure that a boolean iterator can be created for a last() call. func TestCallIterator_Last_Boolean(t *testing.T) { itr, _ := influxql.NewCallIterator( &BooleanIterator{Points: []influxql.BooleanPoint{ {Time: 1, Value: true, Tags: ParseTags("region=us-west,host=hostB")}, {Time: 2, Value: false, Tags: ParseTags("region=us-east,host=hostA")}, {Time: 0, Value: true, Tags: ParseTags("region=us-east,host=hostA")}, {Time: 1, Value: false, Tags: ParseTags("region=us-west,host=hostA")}, {Time: 6, Value: false, Tags: ParseTags("region=us-east,host=hostA")}, {Time: 23, Value: false, Tags: ParseTags("region=us-west,host=hostB")}, }}, influxql.IteratorOptions{ Expr: MustParseExpr(`last("value")`), Dimensions: []string{"host"}, Interval: influxql.Interval{Duration: 5 * time.Nanosecond}, }, ) if a := Iterators([]influxql.Iterator{itr}).ReadAll(); !deep.Equal(a, [][]influxql.Point{ {&influxql.BooleanPoint{Time: 2, Value: false, Tags: ParseTags("host=hostA"), Aggregated: 3}}, {&influxql.BooleanPoint{Time: 1, Value: true, Tags: ParseTags("host=hostB"), Aggregated: 1}}, {&influxql.BooleanPoint{Time: 6, Value: false, Tags: ParseTags("host=hostA"), Aggregated: 1}}, {&influxql.BooleanPoint{Time: 23, Value: false, Tags: ParseTags("host=hostB"), Aggregated: 1}}, }) { t.Fatalf("unexpected points: %s", spew.Sdump(a)) } }
// Ensure that a float iterator can be created for a last() call. func TestCallIterator_Last_Float(t *testing.T) { itr, _ := influxql.NewCallIterator( &FloatIterator{Points: []influxql.FloatPoint{ {Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")}, {Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")}, {Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")}, {Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")}, {Time: 6, Value: 20, Tags: ParseTags("region=us-east,host=hostA")}, {Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")}, }}, influxql.IteratorOptions{ Expr: MustParseExpr(`last("value")`), Dimensions: []string{"host"}, Interval: influxql.Interval{Duration: 5 * time.Nanosecond}, }, ) if a, err := Iterators([]influxql.Iterator{itr}).ReadAll(); err != nil { t.Fatalf("unexpected error: %s", err) } else if !deep.Equal(a, [][]influxql.Point{ {&influxql.FloatPoint{Time: 2, Value: 10, Tags: ParseTags("host=hostA"), Aggregated: 3}}, {&influxql.FloatPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}}, {&influxql.FloatPoint{Time: 6, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}}, {&influxql.FloatPoint{Time: 23, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}}, }) { t.Fatalf("unexpected points: %s", spew.Sdump(a)) } }
// Ensure that a float iterator can be created for a min() call. func TestCallIterator_Min_Float(t *testing.T) { itr := influxql.NewCallIterator( &FloatIterator{Points: []influxql.FloatPoint{ {Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")}, {Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")}, {Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")}, {Time: 4, Value: 12, Tags: ParseTags("region=us-east,host=hostA")}, {Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")}, {Time: 5, Value: 20, Tags: ParseTags("region=us-east,host=hostA")}, {Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")}, }}, influxql.IteratorOptions{ Expr: MustParseExpr(`min("value")`), Dimensions: []string{"host"}, Interval: influxql.Interval{Duration: 5 * time.Nanosecond}, }, ) if a, ok := CompareFloatIterator(itr, []influxql.FloatPoint{ {Time: 0, Value: 10, Tags: ParseTags("host=hostA")}, {Time: 0, Value: 11, Tags: ParseTags("host=hostB")}, {Time: 5, Value: 20, Tags: ParseTags("host=hostA")}, {Time: 20, Value: 8, Tags: ParseTags("host=hostB")}, }); !ok { t.Fatalf("unexpected points: %s", spew.Sdump(a)) } }
func (e *Engine) CreateIterator(opt influxql.IteratorOptions) (influxql.Iterator, error) { if call, ok := opt.Expr.(*influxql.Call); ok { refOpt := opt refOpt.Expr = call.Args[0].(*influxql.VarRef) inputs, err := e.createVarRefIterator(refOpt) if err != nil { return nil, err } input := influxql.NewMergeIterator(inputs, opt) if opt.InterruptCh != nil { input = influxql.NewInterruptIterator(input, opt.InterruptCh) } return influxql.NewCallIterator(input, opt) } itrs, err := e.createVarRefIterator(opt) if err != nil { return nil, err } itr := influxql.NewSortedMergeIterator(itrs, opt) if opt.InterruptCh != nil { itr = influxql.NewInterruptIterator(itr, opt.InterruptCh) } return itr, nil }
func BenchmarkCallIterator_Min_Float(b *testing.B) { input := GenerateFloatIterator(rand.New(rand.NewSource(0)), b.N) b.ResetTimer() b.ReportAllocs() itr, err := influxql.NewCallIterator(input, influxql.IteratorOptions{ Expr: MustParseExpr("min(value)"), Interval: influxql.Interval{Duration: 1 * time.Hour}, InterruptCh: make(chan struct{}), }) if err != nil { b.Fatal(err) } switch itr := itr.(type) { case influxql.FloatIterator: for { if p := itr.Next(); p == nil { break } } default: b.Fatalf("incorrect iterator type: %T", itr) } }
func TestNewCallIterator_UnsupportedExprName(t *testing.T) { _, err := influxql.NewCallIterator( &FloatIterator{}, influxql.IteratorOptions{ Expr: MustParseExpr(`foobar("value")`), }, ) if err == nil || err.Error() != "unsupported function call: foobar" { t.Errorf("unexpected error: %s", err) } }
func (e *Engine) CreateIterator(opt influxql.IteratorOptions) (influxql.Iterator, error) { if call, ok := opt.Expr.(*influxql.Call); ok { refOpt := opt refOpt.Expr = call.Args[0].(*influxql.VarRef) aggregate := true if opt.Interval.IsZero() { switch call.Name { case "first": aggregate = false refOpt.Limit = 1 refOpt.Ascending = true case "last": aggregate = false refOpt.Limit = 1 refOpt.Ascending = false } } inputs, err := e.createVarRefIterator(refOpt, aggregate) if err != nil { return nil, err } else if len(inputs) == 0 { return nil, nil } // Wrap each series in a call iterator. for i, input := range inputs { if opt.InterruptCh != nil { input = influxql.NewInterruptIterator(input, opt.InterruptCh) } itr, err := influxql.NewCallIterator(input, opt) if err != nil { return nil, err } inputs[i] = itr } return influxql.NewParallelMergeIterator(inputs, opt, runtime.GOMAXPROCS(0)), nil } itrs, err := e.createVarRefIterator(opt, false) if err != nil { return nil, err } itr := influxql.NewSortedMergeIterator(itrs, opt) if itr != nil && opt.InterruptCh != nil { itr = influxql.NewInterruptIterator(itr, opt.InterruptCh) } return itr, nil }
func BenchmarkCallIterator_Min_Float(b *testing.B) { input := GenerateFloatIterator(rand.New(rand.NewSource(0)), b.N) b.ResetTimer() b.ReportAllocs() itr := influxql.NewCallIterator(input, influxql.IteratorOptions{ Expr: MustParseExpr("min(value)"), Interval: influxql.Interval{Duration: 1 * time.Hour}, }).(influxql.FloatIterator) for { if p := itr.Next(); p == nil { break } } }
func benchmarkCallIterator(b *testing.B, opt influxql.IteratorOptions, pointN int) { b.ReportAllocs() for i := 0; i < b.N; i++ { // Create a lightweight point generator. p := influxql.FloatPoint{Name: "cpu", Value: 100} input := FloatPointGenerator{ N: pointN, Fn: func(i int) *influxql.FloatPoint { return &p }, } // Execute call against input. itr, err := influxql.NewCallIterator(&input, opt) if err != nil { b.Fatal(err) } influxql.DrainIterator(itr) } }
func (e *Engine) CreateIterator(opt influxql.IteratorOptions) (influxql.Iterator, error) { if call, ok := opt.Expr.(*influxql.Call); ok { refOpt := opt refOpt.Expr = call.Args[0].(*influxql.VarRef) inputs, err := e.createVarRefIterator(refOpt) if err != nil { return nil, err } else if len(inputs) == 0 { return nil, nil } // Wrap each series in a call iterator. for i, input := range inputs { if opt.InterruptCh != nil { input = influxql.NewInterruptIterator(input, opt.InterruptCh) } itr, err := influxql.NewCallIterator(input, opt) if err != nil { return nil, err } inputs[i] = itr } return influxql.NewParallelMergeIterator(inputs, opt, runtime.GOMAXPROCS(0)), nil } itrs, err := e.createVarRefIterator(opt) if err != nil { return nil, err } itr := influxql.NewSortedMergeIterator(itrs, opt) if itr != nil && opt.InterruptCh != nil { itr = influxql.NewInterruptIterator(itr, opt.InterruptCh) } return itr, nil }
// CreateIterator returns a single combined iterator for the shards. func (a Shards) CreateIterator(opt influxql.IteratorOptions) (influxql.Iterator, error) { if influxql.Sources(opt.Sources).HasSystemSource() { return a.createSystemIterator(opt) } // Create iterators for each shard. // Ensure that they are closed if an error occurs. itrs := make([]influxql.Iterator, 0, len(a)) if err := func() error { for _, sh := range a { itr, err := sh.CreateIterator(opt) if err != nil { return err } itrs = append(itrs, itr) } return nil }(); err != nil { influxql.Iterators(itrs).Close() return nil, err } // Merge into a single iterator. if opt.MergeSorted() { return influxql.NewSortedMergeIterator(itrs, opt), nil } itr := influxql.NewMergeIterator(itrs, opt) if opt.Expr != nil { if expr, ok := opt.Expr.(*influxql.Call); ok && expr.Name == "count" { opt.Expr = &influxql.Call{ Name: "sum", Args: expr.Args, } } } return influxql.NewCallIterator(itr, opt), nil }