From 8c088e73afc728068a0c0baccd4a5379a36059de Mon Sep 17 00:00:00 2001 From: Menno Finlay-Smits Date: Tue, 20 Mar 2018 14:22:07 +1300 Subject: [PATCH] Move filter.fastParseInt to convert.ToInt This has been extracted so that it can be used outside of the filter package. --- convert/convert.go | 46 ++++++++++++++++++++++++++++++ convert/convert_small_test.go | 51 ++++++++++++++++++++++++++++++++++ filter/timestamp_small_test.go | 26 ----------------- filter/worker.go | 33 ++-------------------- monitor/prometheus.go | 9 +++--- 5 files changed, 104 insertions(+), 61 deletions(-) create mode 100644 convert/convert.go create mode 100644 convert/convert_small_test.go diff --git a/convert/convert.go b/convert/convert.go new file mode 100644 index 0000000..2a8110f --- /dev/null +++ b/convert/convert.go @@ -0,0 +1,46 @@ +// Copyright 2018 Jump Trading +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package convert + +import "errors" + +const int64Max = (1 << 63) - 1 + +// ToInt is a simpler, faster version of strconv.ParseInt(). +// Differences to ParseInt: +// - input is []byte instead of a string (no type conversion required +// by caller) +// - only supports base 10 input +// - only handles positive values +func ToInt(s []byte) (int64, error) { + if len(s) == 0 { + return 0, errors.New("empty") + } + + var n uint64 + for _, c := range s { + if '0' <= c && c <= '9' { + c -= '0' + } else { + return 0, errors.New("invalid char") + } + n = n*10 + uint64(c) + } + + if n > int64Max { + return 0, errors.New("overflow") + } + return int64(n), nil +} diff --git a/convert/convert_small_test.go b/convert/convert_small_test.go new file mode 100644 index 0000000..d824a4b --- /dev/null +++ b/convert/convert_small_test.go @@ -0,0 +1,51 @@ +// Copyright 2018 Jump Trading +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build small + +package convert_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/jumptrading/influx-spout/convert" +) + +func TestToInt(t *testing.T) { + check := func(input string, expected int64) { + actual, err := convert.ToInt([]byte(input)) + require.NoError(t, err) + assert.Equal(t, expected, actual, "ToInt(%q)", input) + } + + shouldFail := func(input string) { + _, err := convert.ToInt([]byte(input)) + assert.Error(t, err) + } + + check("0", 0) + check("1", 1) + check("9", 9) + check("10", 10) + check("99", 99) + check("101", 101) + check("9223372036854775807", (1<<63)-1) // max int64 value + + shouldFail("9223372036854775808") // max int64 value + 1 + shouldFail("-1") // negatives not supported + shouldFail("x") +} diff --git a/filter/timestamp_small_test.go b/filter/timestamp_small_test.go index 3310a78..b64d32d 100644 --- a/filter/timestamp_small_test.go +++ b/filter/timestamp_small_test.go @@ -22,7 +22,6 @@ import ( "time" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestExtractTimestamp(t *testing.T) { @@ -56,28 +55,3 @@ func TestExtractTimestamp(t *testing.T) { check("weather temp=99 -"+tsStr, defaultTs) check(tsStr, defaultTs) } - -func TestFastParseInt(t *testing.T) { - check := func(input string, expected int64) { - actual, err := fastParseInt([]byte(input)) - require.NoError(t, err) - assert.Equal(t, expected, actual, "fastParseInt(%q)", input) - } - - shouldFail := func(input string) { - _, err := fastParseInt([]byte(input)) - assert.Error(t, err) - } - - check("0", 0) - check("1", 1) - check("9", 9) - check("10", 10) - check("99", 99) - check("101", 101) - check("9223372036854775807", (1<<63)-1) // max int64 value - - shouldFail("9223372036854775808") // max int64 value + 1 - shouldFail("-1") // negatives not supported - shouldFail("x") -} diff --git a/filter/worker.go b/filter/worker.go index 7bde60e..9dd836a 100644 --- a/filter/worker.go +++ b/filter/worker.go @@ -16,12 +16,12 @@ package filter import ( "bytes" - "errors" "fmt" "log" "sync" "time" + "github.com/jumptrading/influx-spout/convert" "github.com/jumptrading/influx-spout/stats" ) @@ -161,7 +161,7 @@ func extractTimestamp(line []byte, defaultTs int64) int64 { // Expect a space just before the timestamp. for i := length - maxTsLen - 1; i < length-minTsLen; i++ { if line[i] == ' ' { - out, err := fastParseInt(line[i+1:]) + out, err := convert.ToInt(line[i+1:]) if err != nil { return defaultTs } @@ -170,32 +170,3 @@ func extractTimestamp(line []byte, defaultTs int64) int64 { } return defaultTs } - -const int64Max = (1 << 63) - 1 - -// fastParseInt is a simpler, faster version of strconv.ParseInt(). -// Differences to ParseInt: -// - input is []byte instead of a string (no type conversion required -// by caller) -// - only supports base 10 input -// - only handles positive values -func fastParseInt(s []byte) (int64, error) { - if len(s) == 0 { - return 0, errors.New("empty") - } - - var n uint64 - for _, c := range s { - if '0' <= c && c <= '9' { - c -= '0' - } else { - return 0, errors.New("invalid char") - } - n = n*10 + uint64(c) - } - - if n > int64Max { - return 0, errors.New("overflow") - } - return int64(n), nil -} diff --git a/monitor/prometheus.go b/monitor/prometheus.go index 4272684..ffcbf5d 100644 --- a/monitor/prometheus.go +++ b/monitor/prometheus.go @@ -3,7 +3,8 @@ package monitor import ( "bytes" "errors" - "strconv" + + "github.com/jumptrading/influx-spout/convert" ) // Metric represents a single Prometheus metric line, including its @@ -11,7 +12,7 @@ import ( type Metric struct { Name []byte Labels LabelPairs - Value int + Value int64 Milliseconds int64 } @@ -60,14 +61,14 @@ func ParseMetric(s []byte) (*Metric, error) { if j == -1 { j = len(s[i:]) // No timestamp } - out.Value, err = strconv.Atoi(string(s[i : i+j])) + out.Value, err = convert.ToInt(s[i : i+j]) if err != nil { return nil, errors.New("invalid value") } i += j if i < len(s) { - out.Milliseconds, err = strconv.ParseInt(string(s[i+1:]), 10, 64) + out.Milliseconds, err = convert.ToInt(s[i+1:]) if err != nil { return nil, errors.New("invalid timestamp") }