Skip to content

Commit

Permalink
Ensure points with trailing whitespace are accepted
Browse files Browse the repository at this point in the history
  • Loading branch information
e-dard committed May 26, 2016
1 parent 5163e74 commit 39f3480
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 38 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
- [#6701](https://github.com/influxdata/influxdb/issues/6701): Filter out sources that do not match the shard database/retention policy.
- [#6683](https://github.com/influxdata/influxdb/issues/6683): Fix compaction planning re-compacting large TSM files
- [#6693](https://github.com/influxdata/influxdb/pull/6693): Truncate the shard group end time if it exceeds MaxNanoTime.
- [#6672](https://github.com/influxdata/influxdb/issues/6672): Accept points with trailing whitespace.

## v0.13.0 [2016-05-12]

Expand Down
43 changes: 27 additions & 16 deletions models/points.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var (

ErrPointMustHaveAField = errors.New("point without fields is unsupported")
ErrInvalidNumber = errors.New("invalid number")
ErrInvalidPoint = errors.New("point is invalid")
ErrMaxKeyLengthExceeded = errors.New("max key length exceeded")
)

Expand Down Expand Up @@ -234,7 +235,6 @@ func parsePoint(buf []byte, defaultTime time.Time, precision string) (Point, err

// scan the last block which is an optional integer timestamp
pos, ts, err := scanTime(buf, pos)

if err != nil {
return nil, err
}
Expand All @@ -257,6 +257,15 @@ func parsePoint(buf []byte, defaultTime time.Time, precision string) (Point, err
if err != nil {
return nil, err
}

// Determine if there are illegal non-whitespace characters after the
// timestamp block.
for pos < len(buf) {
if buf[pos] != ' ' {
return nil, ErrInvalidPoint
}
pos++
}
}
return pt, nil
}
Expand Down Expand Up @@ -634,32 +643,34 @@ func scanFields(buf []byte, i int) (int, []byte, error) {
return i, buf[start:i], nil
}

// scanTime scans buf, starting at i for the time section of a point. It returns
// the ending position and the byte slice of the fields within buf and error if the
// timestamp is not in the correct numeric format
// scanTime scans buf, starting at i for the time section of a point. It
// returns the ending position and the byte slice of the timestamp within buf
// and and error if the timestamp is not in the correct numeric format.
func scanTime(buf []byte, i int) (int, []byte, error) {
start := skipWhitespace(buf, i)
i = start

for {
// reached the end of buf?
if i >= len(buf) {
break
}

// Timestamps should be integers, make sure they are so we don't need to actually
// parse the timestamp until needed
if buf[i] < '0' || buf[i] > '9' {
// Handle negative timestamps
if i == start && buf[i] == '-' {
i++
continue
}
return i, buf[start:i], fmt.Errorf("bad timestamp")
// Reached end of block or trailing whitespace?
if buf[i] == '\n' || buf[i] == ' ' {
break
}

// reached end of block?
if buf[i] == '\n' {
break
// Handle negative timestamps
if i == start && buf[i] == '-' {
i++
continue
}

// Timestamps should be integers, make sure they are so we don't need
// to actually parse the timestamp until needed.
if buf[i] < '0' || buf[i] > '9' {
return i, buf[start:i], fmt.Errorf("bad timestamp")
}
i++
}
Expand Down
77 changes: 55 additions & 22 deletions models/points_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,47 @@ func TestParsePointScientificIntInvalid(t *testing.T) {
}
}

func TestParsePointWhitespace(t *testing.T) {
examples := []string{
`cpu value=1.0 1257894000000000000`,
`cpu value=1.0 1257894000000000000`,
`cpu value=1.0 1257894000000000000`,
`cpu value=1.0 1257894000000000000 `,
`cpu value=1.0 1257894000000000000
`,
`cpu value=1.0 1257894000000000000
`,
}

expPoint := NewTestPoint("cpu", models.Tags{}, models.Fields{"value": 1.0}, time.Unix(0, 1257894000000000000))
for i, example := range examples {
pts, err := models.ParsePoints([]byte(example))
if err != nil {
t.Fatalf(`[Example %d] ParsePoints("%s") error. got %v, exp nil`, i, example, err)
}

if got, exp := len(pts), 1; got != exp {
t.Fatalf("[Example %d] got %d points, expected %d", i, got, exp)
}

if got, exp := pts[0].Name(), expPoint.Name(); got != exp {
t.Fatalf("[Example %d] got %d measurement, expected %d", i, got, exp)
}

if got, exp := len(pts[0].Fields()), len(expPoint.Fields()); got != exp {
t.Fatalf("[Example %d] got %d fields, expected %d", i, got, exp)
}

if got, exp := pts[0].Fields()["value"], expPoint.Fields()["value"]; got != exp {
t.Fatalf(`[Example %d] got %v for field "value", expected %v`, i, got, exp)
}

if got, exp := pts[0].Time().UnixNano(), expPoint.Time().UnixNano(); got != exp {
t.Fatalf(`[Example %d] got %d time, expected %d`, i, got, exp)
}
}
}

func TestParsePointUnescape(t *testing.T) {
// commas in measurement name
test(t, `foo\,bar value=1i`,
Expand Down Expand Up @@ -1171,29 +1212,21 @@ func TestParsePointMinTimestamp(t *testing.T) {
}

func TestParsePointInvalidTimestamp(t *testing.T) {
_, err := models.ParsePointsString("cpu value=1 9223372036854775808")
if err == nil {
t.Fatalf("ParsePoints failed: %v", err)
}
_, err = models.ParsePointsString("cpu value=1 -92233720368547758078")
if err == nil {
t.Fatalf("ParsePoints failed: %v", err)
}
_, err = models.ParsePointsString("cpu value=1 -")
if err == nil {
t.Fatalf("ParsePoints failed: %v", err)
}
_, err = models.ParsePointsString("cpu value=1 -/")
if err == nil {
t.Fatalf("ParsePoints failed: %v", err)
}
_, err = models.ParsePointsString("cpu value=1 -1?")
if err == nil {
t.Fatalf("ParsePoints failed: %v", err)
examples := []string{
"cpu value=1 9223372036854775808",
"cpu value=1 -92233720368547758078",
"cpu value=1 -",
"cpu value=1 -/",
"cpu value=1 -1?",
"cpu value=1 1-",
"cpu value=1 9223372036854775807 12",
}
_, err = models.ParsePointsString("cpu value=1 1-")
if err == nil {
t.Fatalf("ParsePoints failed: %v", err)

for i, example := range examples {
_, err := models.ParsePointsString(example)
if err == nil {
t.Fatalf("[Example %d] ParsePoints failed: %v", i, err)
}
}
}

Expand Down

0 comments on commit 39f3480

Please sign in to comment.