Merge pull request #8652 from influxdata/sgc-literal-cursor

Reduce allocations using nil cursors and literal value cursors
pull/8655/merge
Stuart Carnie 2017-08-01 10:20:24 -07:00 committed by GitHub
commit 5449285c4c
6 changed files with 77 additions and 135 deletions

View File

@ -12,6 +12,7 @@
- [#8426](https://github.com/influxdata/influxdb/issues/8426): Add `parse-multivalue-plugin` to allow users to choose how multivalue plugins should be handled by the collectd service.
- [#8548](https://github.com/influxdata/influxdb/issues/8548): Allow panic recovery to be disabled when investigating server issues.
- [#8525](https://github.com/influxdata/influxdb/issues/8525): Support http pipelining for /query endpoint.
- [#8652](https://github.com/influxdata/influxdb/pull/8652): Reduce allocations when reading data
### Bugfixes

View File

@ -1852,19 +1852,19 @@ func (e *Engine) createVarRefSeriesIterator(ref *influxql.VarRef, name string, s
// If a field was requested, use a nil cursor of the requested type.
switch ref.Type {
case influxql.Float, influxql.AnyField:
aux[i] = &floatNilLiteralCursor{}
aux[i] = nilFloatLiteralValueCursor
continue
case influxql.Integer:
aux[i] = &integerNilLiteralCursor{}
aux[i] = nilIntegerLiteralValueCursor
continue
case influxql.Unsigned:
aux[i] = &unsignedNilLiteralCursor{}
aux[i] = nilUnsignedLiteralValueCursor
continue
case influxql.String:
aux[i] = &stringNilLiteralCursor{}
aux[i] = nilStringLiteralValueCursor
continue
case influxql.Boolean:
aux[i] = &booleanNilLiteralCursor{}
aux[i] = nilBooleanLiteralValueCursor
continue
}
}
@ -1872,9 +1872,9 @@ func (e *Engine) createVarRefSeriesIterator(ref *influxql.VarRef, name string, s
// If field doesn't exist, use the tag value.
if v := tags.Value(ref.Val); v == "" {
// However, if the tag value is blank then return a null.
aux[i] = &stringNilLiteralCursor{}
aux[i] = nilStringLiteralValueCursor
} else {
aux[i] = &stringLiteralCursor{value: v}
aux[i] = &literalValueCursor{value: v}
}
}
}
@ -1896,19 +1896,19 @@ func (e *Engine) createVarRefSeriesIterator(ref *influxql.VarRef, name string, s
// If a field was requested, use a nil cursor of the requested type.
switch ref.Type {
case influxql.Float, influxql.AnyField:
conds[i] = &floatNilLiteralCursor{}
conds[i] = nilFloatLiteralValueCursor
continue
case influxql.Integer:
conds[i] = &integerNilLiteralCursor{}
conds[i] = nilIntegerLiteralValueCursor
continue
case influxql.Unsigned:
conds[i] = &unsignedNilLiteralCursor{}
conds[i] = nilUnsignedLiteralValueCursor
continue
case influxql.String:
conds[i] = &stringNilLiteralCursor{}
conds[i] = nilStringLiteralValueCursor
continue
case influxql.Boolean:
conds[i] = &booleanNilLiteralCursor{}
conds[i] = nilBooleanLiteralValueCursor
continue
}
}
@ -1916,9 +1916,9 @@ func (e *Engine) createVarRefSeriesIterator(ref *influxql.VarRef, name string, s
// If field doesn't exist, use the tag value.
if v := tags.Value(ref.Val); v == "" {
// However, if the tag value is blank then return a null.
conds[i] = &stringNilLiteralCursor{}
conds[i] = nilStringLiteralValueCursor
} else {
conds[i] = &stringLiteralCursor{value: v}
conds[i] = &literalValueCursor{value: v}
}
}
}

View File

@ -532,26 +532,6 @@ func (c *floatDescendingCursor) nextTSM() {
}
}
// floatLiteralCursor represents a cursor that always returns a single value.
// It doesn't not have a time value so it can only be used with nextAt().
type floatLiteralCursor struct {
value float64
}
func (c *floatLiteralCursor) close() error { return nil }
func (c *floatLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, c.value }
func (c *floatLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, c.value }
func (c *floatLiteralCursor) nextAt(seek int64) interface{} { return c.value }
// floatNilLiteralCursor represents a cursor that always returns a typed nil value.
// It doesn't not have a time value so it can only be used with nextAt().
type floatNilLiteralCursor struct{}
func (c *floatNilLiteralCursor) close() error { return nil }
func (c *floatNilLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, (*float64)(nil) }
func (c *floatNilLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, (*float64)(nil) }
func (c *floatNilLiteralCursor) nextAt(seek int64) interface{} { return (*float64)(nil) }
type integerIterator struct {
cur integerCursor
aux []cursorAt
@ -967,26 +947,6 @@ func (c *integerDescendingCursor) nextTSM() {
}
}
// integerLiteralCursor represents a cursor that always returns a single value.
// It doesn't not have a time value so it can only be used with nextAt().
type integerLiteralCursor struct {
value int64
}
func (c *integerLiteralCursor) close() error { return nil }
func (c *integerLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, c.value }
func (c *integerLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, c.value }
func (c *integerLiteralCursor) nextAt(seek int64) interface{} { return c.value }
// integerNilLiteralCursor represents a cursor that always returns a typed nil value.
// It doesn't not have a time value so it can only be used with nextAt().
type integerNilLiteralCursor struct{}
func (c *integerNilLiteralCursor) close() error { return nil }
func (c *integerNilLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, (*int64)(nil) }
func (c *integerNilLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, (*int64)(nil) }
func (c *integerNilLiteralCursor) nextAt(seek int64) interface{} { return (*int64)(nil) }
type unsignedIterator struct {
cur unsignedCursor
aux []cursorAt
@ -1402,26 +1362,6 @@ func (c *unsignedDescendingCursor) nextTSM() {
}
}
// unsignedLiteralCursor represents a cursor that always returns a single value.
// It doesn't not have a time value so it can only be used with nextAt().
type unsignedLiteralCursor struct {
value uint64
}
func (c *unsignedLiteralCursor) close() error { return nil }
func (c *unsignedLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, c.value }
func (c *unsignedLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, c.value }
func (c *unsignedLiteralCursor) nextAt(seek int64) interface{} { return c.value }
// unsignedNilLiteralCursor represents a cursor that always returns a typed nil value.
// It doesn't not have a time value so it can only be used with nextAt().
type unsignedNilLiteralCursor struct{}
func (c *unsignedNilLiteralCursor) close() error { return nil }
func (c *unsignedNilLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, (*uint64)(nil) }
func (c *unsignedNilLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, (*uint64)(nil) }
func (c *unsignedNilLiteralCursor) nextAt(seek int64) interface{} { return (*uint64)(nil) }
type stringIterator struct {
cur stringCursor
aux []cursorAt
@ -1837,26 +1777,6 @@ func (c *stringDescendingCursor) nextTSM() {
}
}
// stringLiteralCursor represents a cursor that always returns a single value.
// It doesn't not have a time value so it can only be used with nextAt().
type stringLiteralCursor struct {
value string
}
func (c *stringLiteralCursor) close() error { return nil }
func (c *stringLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, c.value }
func (c *stringLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, c.value }
func (c *stringLiteralCursor) nextAt(seek int64) interface{} { return c.value }
// stringNilLiteralCursor represents a cursor that always returns a typed nil value.
// It doesn't not have a time value so it can only be used with nextAt().
type stringNilLiteralCursor struct{}
func (c *stringNilLiteralCursor) close() error { return nil }
func (c *stringNilLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, (*string)(nil) }
func (c *stringNilLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, (*string)(nil) }
func (c *stringNilLiteralCursor) nextAt(seek int64) interface{} { return (*string)(nil) }
type booleanIterator struct {
cur booleanCursor
aux []cursorAt
@ -2272,24 +2192,4 @@ func (c *booleanDescendingCursor) nextTSM() {
}
}
// booleanLiteralCursor represents a cursor that always returns a single value.
// It doesn't not have a time value so it can only be used with nextAt().
type booleanLiteralCursor struct {
value bool
}
func (c *booleanLiteralCursor) close() error { return nil }
func (c *booleanLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, c.value }
func (c *booleanLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, c.value }
func (c *booleanLiteralCursor) nextAt(seek int64) interface{} { return c.value }
// booleanNilLiteralCursor represents a cursor that always returns a typed nil value.
// It doesn't not have a time value so it can only be used with nextAt().
type booleanNilLiteralCursor struct{}
func (c *booleanNilLiteralCursor) close() error { return nil }
func (c *booleanNilLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, (*bool)(nil) }
func (c *booleanNilLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, (*bool)(nil) }
func (c *booleanNilLiteralCursor) nextAt(seek int64) interface{} { return (*bool)(nil) }
var _ = fmt.Print

View File

@ -528,27 +528,6 @@ func (c *{{.name}}DescendingCursor) nextTSM() {
}
}
// {{.name}}LiteralCursor represents a cursor that always returns a single value.
// It doesn't not have a time value so it can only be used with nextAt().
type {{.name}}LiteralCursor struct {
value {{.Type}}
}
func (c *{{.name}}LiteralCursor) close() error { return nil }
func (c *{{.name}}LiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, c.value }
func (c *{{.name}}LiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, c.value }
func (c *{{.name}}LiteralCursor) nextAt(seek int64) interface{} { return c.value }
// {{.name}}NilLiteralCursor represents a cursor that always returns a typed nil value.
// It doesn't not have a time value so it can only be used with nextAt().
type {{.name}}NilLiteralCursor struct {}
func (c *{{.name}}NilLiteralCursor) close() error { return nil }
func (c *{{.name}}NilLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, (*{{.Type}})(nil) }
func (c *{{.name}}NilLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, (*{{.Type}})(nil) }
func (c *{{.name}}NilLiteralCursor) nextAt(seek int64) interface{} { return (*{{.Type}})(nil) }
{{end}}
var _ = fmt.Print

View File

@ -0,0 +1,41 @@
package tsm1
import (
"testing"
"github.com/influxdata/influxdb/influxql"
)
func BenchmarkIntegerIterator_Next(b *testing.B) {
opt := influxql.IteratorOptions{
Aux: []influxql.VarRef{{Val: "f1"}, {Val: "f1"}, {Val: "f1"}, {Val: "f1"}},
}
aux := []cursorAt{
&literalValueCursor{value: "foo bar"},
&literalValueCursor{value: int64(1e3)},
&literalValueCursor{value: float64(1e3)},
&literalValueCursor{value: true},
}
cur := newIntegerIterator("m0", influxql.Tags{}, opt, &infiniteIntegerCursor{}, aux, nil, nil)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
cur.Next()
}
}
type infiniteIntegerCursor struct{}
func (*infiniteIntegerCursor) close() error {
return nil
}
func (*infiniteIntegerCursor) next() (t int64, v interface{}) {
return 0, 0
}
func (*infiniteIntegerCursor) nextInteger() (t int64, v int64) {
return 0, 0
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
"github.com/influxdata/influxdb/influxql"
"github.com/influxdata/influxdb/tsdb"
)
func newLimitIterator(input influxql.Iterator, opt influxql.IteratorOptions) influxql.Iterator {
@ -100,3 +101,23 @@ func (c *unsignedCastIntegerCursor) nextUnsigned() (int64, uint64) {
t, v := c.cursor.nextInteger()
return t, uint64(v)
}
// literalValueCursor represents a cursor that always returns a single value.
// It doesn't not have a time value so it can only be used with nextAt().
type literalValueCursor struct {
value interface{}
}
func (c *literalValueCursor) close() error { return nil }
func (c *literalValueCursor) peek() (t int64, v interface{}) { return tsdb.EOF, c.value }
func (c *literalValueCursor) next() (t int64, v interface{}) { return tsdb.EOF, c.value }
func (c *literalValueCursor) nextAt(seek int64) interface{} { return c.value }
// preallocate and cast to cursorAt to avoid allocations
var (
nilFloatLiteralValueCursor cursorAt = &literalValueCursor{value: (*float64)(nil)}
nilIntegerLiteralValueCursor cursorAt = &literalValueCursor{value: (*int64)(nil)}
nilUnsignedLiteralValueCursor cursorAt = &literalValueCursor{value: (*uint64)(nil)}
nilStringLiteralValueCursor cursorAt = &literalValueCursor{value: (*string)(nil)}
nilBooleanLiteralValueCursor cursorAt = &literalValueCursor{value: (*bool)(nil)}
)