Skip to content

Commit

Permalink
Merge pull request #3610 from influxdb/jw-derivative
Browse files Browse the repository at this point in the history
Fix panic when running derivative on non-numeric values
  • Loading branch information
jwilder committed Aug 10, 2015
2 parents 41733f6 + 03dfec3 commit 2b33302
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
- [#3580](https://github.com/influxdb/influxdb/issues/3580): Do not allow wildcards with fields in select statements
- [#3530](https://github.com/influxdb/influxdb/pull/3530): Aliasing a column no longer works
- [#3436](https://github.com/influxdb/influxdb/issues/3436): Fix panic in hinted handoff queue processor
- [#3401](https://github.com/influxdb/influxdb/issues/3401): Derivative on non-numeric fields panics db

## v0.9.2 [2015-07-24]

Expand Down
39 changes: 36 additions & 3 deletions tsdb/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -757,14 +757,31 @@ type RawQueryDerivativeProcessor struct {
DerivativeInterval time.Duration
}

func (rqdp *RawQueryDerivativeProcessor) canProcess(input []*MapperValue) bool {
// If we only have 1 value, then the value did not change, so return
// a single row with 0.0
if len(input) == 1 {
return false
}

// See if the field value is numeric, if it's not, we can't process the derivative
validType := false
switch input[0].Value.(type) {
case int64:
validType = true
case float64:
validType = true
}

return validType
}

func (rqdp *RawQueryDerivativeProcessor) Process(input []*MapperValue) []*MapperValue {
if len(input) == 0 {
return input
}

// If we only have 1 value, then the value did not change, so return
// a single row with 0.0
if len(input) == 1 {
if !rqdp.canProcess(input) {
return []*MapperValue{
&MapperValue{
Time: input[0].Time,
Expand Down Expand Up @@ -858,6 +875,22 @@ func ProcessAggregateDerivative(results [][]interface{}, isNonNegative bool, int
}
}

// Check the value's type to ensure it's an numeric, if not, return a 0 result. We only check the first value
// because derivatives cannot be combined with other aggregates currently.
validType := false
switch results[0][1].(type) {
case int64:
validType = true
case float64:
validType = true
}

if !validType {
return [][]interface{}{
[]interface{}{results[0][0], 0.0},
}
}

// Otherwise calculate the derivatives as the difference between consecutive
// points divided by the elapsed time. Then normalize to the requested
// interval.
Expand Down
92 changes: 91 additions & 1 deletion tsdb/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ func TestProcessAggregateDerivative(t *testing.T) {
},
},
{
name: "float derivatives",
name: "integer derivatives",
fn: "derivative",
interval: 24 * time.Hour,
in: [][]interface{}{
Expand Down Expand Up @@ -608,6 +608,30 @@ func TestProcessAggregateDerivative(t *testing.T) {
},
},
},
{
name: "string derivatives",
fn: "derivative",
interval: 24 * time.Hour,
in: [][]interface{}{
[]interface{}{
time.Unix(0, 0), "1.0",
},
[]interface{}{
time.Unix(0, 0).Add(24 * time.Hour), "2.0",
},
[]interface{}{
time.Unix(0, 0).Add(48 * time.Hour), "3.0",
},
[]interface{}{
time.Unix(0, 0).Add(72 * time.Hour), "4.0",
},
},
exp: [][]interface{}{
[]interface{}{
time.Unix(0, 0), 0.0,
},
},
},
}

for _, test := range tests {
Expand Down Expand Up @@ -697,6 +721,43 @@ func TestProcessRawQueryDerivative(t *testing.T) {
},
},
},
{
name: "integer derivative",
fn: "derivative",
interval: 24 * time.Hour,
in: []*tsdb.MapperValue{
{
Time: time.Unix(0, 0).Unix(),
Value: int64(0),
},
{
Time: time.Unix(0, 0).Add(24 * time.Hour).UnixNano(),
Value: int64(3),
},
{
Time: time.Unix(0, 0).Add(48 * time.Hour).UnixNano(),
Value: int64(5),
},
{
Time: time.Unix(0, 0).Add(72 * time.Hour).UnixNano(),
Value: int64(9),
},
},
exp: []*tsdb.MapperValue{
{
Time: time.Unix(0, 0).Add(24 * time.Hour).UnixNano(),
Value: 3.0,
},
{
Time: time.Unix(0, 0).Add(48 * time.Hour).UnixNano(),
Value: 2.0,
},
{
Time: time.Unix(0, 0).Add(72 * time.Hour).UnixNano(),
Value: 4.0,
},
},
},
{
name: "12h interval",
fn: "derivative",
Expand Down Expand Up @@ -806,6 +867,35 @@ func TestProcessRawQueryDerivative(t *testing.T) {
},
},
},
{
name: "string derivatives",
fn: "derivative",
interval: 24 * time.Hour,
in: []*tsdb.MapperValue{
{
Time: time.Unix(0, 0).Unix(),
Value: "1.0",
},
{
Time: time.Unix(0, 0).Add(24 * time.Hour).UnixNano(),
Value: "2.0",
},
{
Time: time.Unix(0, 0).Add(48 * time.Hour).UnixNano(),
Value: "3.0",
},
{
Time: time.Unix(0, 0).Add(72 * time.Hour).UnixNano(),
Value: "4.0",
},
},
exp: []*tsdb.MapperValue{
{
Time: time.Unix(0, 0).Unix(),
Value: 0.0,
},
},
},
}

for _, test := range tests {
Expand Down

0 comments on commit 2b33302

Please sign in to comment.