reuse ValuerEval objects

Scanner objects and iterators often need a ValuerEval. This
object is created, often with a function call, and has at
least one interface in it, so it allocates storage. Then it's
dropped again right away. The only part of it that might be
subject to change is usually a map. While the map's contents
change over time, the actual map doesn't change for the
lifetime of the object.

So, in both iterators and scanners, stash the ValuerEval
and continue reusing it. On a query returning a fair number
of data points, this produces a small (<5% in practice)
improvement in observed performance, visible as a significant
reduction in time spent in runtime (mallocgc, newobject,
etcetera).

The performance improvement isn't big, but it's reasonably
easy to evaluate it and establish that it's a safe change
to make.

Signed-off-by: seebs <seebs@seebs.net>
pull/10414/head
Seebs 2018-10-25 11:28:40 -05:00
parent 59e4d86cbf
commit 5525240de3
3 changed files with 71 additions and 57 deletions

View File

@ -144,7 +144,8 @@ type scannerCursorBase struct {
columns []influxql.VarRef
loc *time.Location
scan scannerFunc
scan scannerFunc
valuer influxql.ValuerEval
}
func newScannerCursorBase(scan scannerFunc, fields []*influxql.Field, loc *time.Location) scannerCursorBase {
@ -162,12 +163,20 @@ func newScannerCursorBase(scan scannerFunc, fields []*influxql.Field, loc *time.
loc = time.UTC
}
m := make(map[string]interface{})
return scannerCursorBase{
fields: exprs,
m: make(map[string]interface{}),
m: m,
columns: columns,
loc: loc,
scan: scan,
valuer: influxql.ValuerEval{
Valuer: influxql.MultiValuer(
MathValuer{},
influxql.MapValuer(m),
),
IntegerFloatDivision: true,
},
}
}
@ -189,20 +198,13 @@ func (cur *scannerCursorBase) Scan(row *Row) bool {
row.Values = make([]interface{}, len(cur.columns))
}
valuer := influxql.ValuerEval{
Valuer: influxql.MultiValuer(
MathValuer{},
influxql.MapValuer(cur.m),
),
IntegerFloatDivision: true,
}
for i, expr := range cur.fields {
// A special case if the field is time to reduce memory allocations.
if ref, ok := expr.(*influxql.VarRef); ok && ref.Val == "time" {
row.Values[i] = time.Unix(0, row.Time).In(cur.loc)
continue
}
v := valuer.Eval(expr)
v := cur.valuer.Eval(expr)
if fv, ok := v.(float64); ok && math.IsNaN(fv) {
// If the float value is NaN, convert it to a null float
// so this can be serialized correctly, but not mistaken for
@ -339,6 +341,7 @@ type filterCursor struct {
fields map[string]IteratorMap
filter influxql.Expr
m map[string]interface{}
valuer influxql.ValuerEval
}
func newFilterCursor(cur Cursor, filter influxql.Expr) *filterCursor {
@ -362,11 +365,13 @@ func newFilterCursor(cur Cursor, filter influxql.Expr) *filterCursor {
fields[name.Val] = TagMap(name.Val)
}
}
m := make(map[string]interface{})
return &filterCursor{
Cursor: cur,
fields: fields,
filter: filter,
m: make(map[string]interface{}),
m: m,
valuer: influxql.ValuerEval{Valuer: influxql.MapValuer(m)},
}
}
@ -377,10 +382,7 @@ func (cur *filterCursor) Scan(row *Row) bool {
cur.m[name] = f.Value(row)
}
valuer := influxql.ValuerEval{
Valuer: influxql.MapValuer(cur.m),
}
if valuer.EvalBool(cur.filter) {
if cur.valuer.EvalBool(cur.filter) {
// Passes the filter! Return true. We no longer need to
// search for a suitable value.
return true

View File

@ -196,6 +196,7 @@ type floatIterator struct {
statsLock sync.Mutex
stats query.IteratorStats
statsBuf query.IteratorStats
valuer influxql.ValuerEval
}
func newFloatIterator(name string, tags query.Tags, opt query.IteratorOptions, cur floatCursor, aux []cursorAt, conds []cursorAt, condNames []string) *floatIterator {
@ -223,6 +224,13 @@ func newFloatIterator(name string, tags query.Tags, opt query.IteratorOptions, c
itr.conds.names = condNames
itr.conds.curs = conds
itr.valuer = influxql.ValuerEval{
Valuer: influxql.MultiValuer(
query.MathValuer{},
influxql.MapValuer(itr.m),
),
}
return itr
}
@ -270,13 +278,7 @@ func (itr *floatIterator) Next() (*query.FloatPoint, error) {
}
// Evaluate condition, if one exists. Retry if it fails.
valuer := influxql.ValuerEval{
Valuer: influxql.MultiValuer(
query.MathValuer{},
influxql.MapValuer(itr.m),
),
}
if itr.opt.Condition != nil && !valuer.EvalBool(itr.opt.Condition) {
if itr.opt.Condition != nil && !itr.valuer.EvalBool(itr.opt.Condition) {
continue
}
@ -674,6 +676,7 @@ type integerIterator struct {
statsLock sync.Mutex
stats query.IteratorStats
statsBuf query.IteratorStats
valuer influxql.ValuerEval
}
func newIntegerIterator(name string, tags query.Tags, opt query.IteratorOptions, cur integerCursor, aux []cursorAt, conds []cursorAt, condNames []string) *integerIterator {
@ -701,6 +704,13 @@ func newIntegerIterator(name string, tags query.Tags, opt query.IteratorOptions,
itr.conds.names = condNames
itr.conds.curs = conds
itr.valuer = influxql.ValuerEval{
Valuer: influxql.MultiValuer(
query.MathValuer{},
influxql.MapValuer(itr.m),
),
}
return itr
}
@ -748,13 +758,7 @@ func (itr *integerIterator) Next() (*query.IntegerPoint, error) {
}
// Evaluate condition, if one exists. Retry if it fails.
valuer := influxql.ValuerEval{
Valuer: influxql.MultiValuer(
query.MathValuer{},
influxql.MapValuer(itr.m),
),
}
if itr.opt.Condition != nil && !valuer.EvalBool(itr.opt.Condition) {
if itr.opt.Condition != nil && !itr.valuer.EvalBool(itr.opt.Condition) {
continue
}
@ -1152,6 +1156,7 @@ type unsignedIterator struct {
statsLock sync.Mutex
stats query.IteratorStats
statsBuf query.IteratorStats
valuer influxql.ValuerEval
}
func newUnsignedIterator(name string, tags query.Tags, opt query.IteratorOptions, cur unsignedCursor, aux []cursorAt, conds []cursorAt, condNames []string) *unsignedIterator {
@ -1179,6 +1184,13 @@ func newUnsignedIterator(name string, tags query.Tags, opt query.IteratorOptions
itr.conds.names = condNames
itr.conds.curs = conds
itr.valuer = influxql.ValuerEval{
Valuer: influxql.MultiValuer(
query.MathValuer{},
influxql.MapValuer(itr.m),
),
}
return itr
}
@ -1226,13 +1238,7 @@ func (itr *unsignedIterator) Next() (*query.UnsignedPoint, error) {
}
// Evaluate condition, if one exists. Retry if it fails.
valuer := influxql.ValuerEval{
Valuer: influxql.MultiValuer(
query.MathValuer{},
influxql.MapValuer(itr.m),
),
}
if itr.opt.Condition != nil && !valuer.EvalBool(itr.opt.Condition) {
if itr.opt.Condition != nil && !itr.valuer.EvalBool(itr.opt.Condition) {
continue
}
@ -1630,6 +1636,7 @@ type stringIterator struct {
statsLock sync.Mutex
stats query.IteratorStats
statsBuf query.IteratorStats
valuer influxql.ValuerEval
}
func newStringIterator(name string, tags query.Tags, opt query.IteratorOptions, cur stringCursor, aux []cursorAt, conds []cursorAt, condNames []string) *stringIterator {
@ -1657,6 +1664,13 @@ func newStringIterator(name string, tags query.Tags, opt query.IteratorOptions,
itr.conds.names = condNames
itr.conds.curs = conds
itr.valuer = influxql.ValuerEval{
Valuer: influxql.MultiValuer(
query.MathValuer{},
influxql.MapValuer(itr.m),
),
}
return itr
}
@ -1704,13 +1718,7 @@ func (itr *stringIterator) Next() (*query.StringPoint, error) {
}
// Evaluate condition, if one exists. Retry if it fails.
valuer := influxql.ValuerEval{
Valuer: influxql.MultiValuer(
query.MathValuer{},
influxql.MapValuer(itr.m),
),
}
if itr.opt.Condition != nil && !valuer.EvalBool(itr.opt.Condition) {
if itr.opt.Condition != nil && !itr.valuer.EvalBool(itr.opt.Condition) {
continue
}
@ -2108,6 +2116,7 @@ type booleanIterator struct {
statsLock sync.Mutex
stats query.IteratorStats
statsBuf query.IteratorStats
valuer influxql.ValuerEval
}
func newBooleanIterator(name string, tags query.Tags, opt query.IteratorOptions, cur booleanCursor, aux []cursorAt, conds []cursorAt, condNames []string) *booleanIterator {
@ -2135,6 +2144,13 @@ func newBooleanIterator(name string, tags query.Tags, opt query.IteratorOptions,
itr.conds.names = condNames
itr.conds.curs = conds
itr.valuer = influxql.ValuerEval{
Valuer: influxql.MultiValuer(
query.MathValuer{},
influxql.MapValuer(itr.m),
),
}
return itr
}
@ -2182,13 +2198,7 @@ func (itr *booleanIterator) Next() (*query.BooleanPoint, error) {
}
// Evaluate condition, if one exists. Retry if it fails.
valuer := influxql.ValuerEval{
Valuer: influxql.MultiValuer(
query.MathValuer{},
influxql.MapValuer(itr.m),
),
}
if itr.opt.Condition != nil && !valuer.EvalBool(itr.opt.Condition) {
if itr.opt.Condition != nil && !itr.valuer.EvalBool(itr.opt.Condition) {
continue
}

View File

@ -194,6 +194,7 @@ type {{.name}}Iterator struct {
statsLock sync.Mutex
stats query.IteratorStats
statsBuf query.IteratorStats
valuer influxql.ValuerEval
}
func new{{.Name}}Iterator(name string, tags query.Tags, opt query.IteratorOptions, cur {{.name}}Cursor, aux []cursorAt, conds []cursorAt, condNames []string) *{{.name}}Iterator {
@ -221,6 +222,13 @@ func new{{.Name}}Iterator(name string, tags query.Tags, opt query.IteratorOption
itr.conds.names = condNames
itr.conds.curs = conds
itr.valuer = influxql.ValuerEval{
Valuer: influxql.MultiValuer(
query.MathValuer{},
influxql.MapValuer(itr.m),
),
}
return itr
}
@ -268,13 +276,7 @@ func (itr *{{.name}}Iterator) Next() (*query.{{.Name}}Point, error) {
}
// Evaluate condition, if one exists. Retry if it fails.
valuer := influxql.ValuerEval{
Valuer: influxql.MultiValuer(
query.MathValuer{},
influxql.MapValuer(itr.m),
),
}
if itr.opt.Condition != nil && !valuer.EvalBool(itr.opt.Condition) {
if itr.opt.Condition != nil && !itr.valuer.EvalBool(itr.opt.Condition) {
continue
}