diff --git a/models/points.go b/models/points.go index 99c57570aae..1e742772f21 100644 --- a/models/points.go +++ b/models/points.go @@ -273,8 +273,8 @@ func ParsePointsString(buf string) ([]Point, error) { // NOTE: to minimize heap allocations, the returned Tags will refer to subslices of buf. // This can have the unintended effect preventing buf from being garbage collected. func ParseKey(buf []byte) (string, Tags) { - meas, tags := ParseKeyBytes(buf) - return string(meas), tags + name, tags := ParseKeyBytes(buf) + return string(name), tags } func ParseKeyBytes(buf []byte) ([]byte, Tags) { @@ -282,27 +282,34 @@ func ParseKeyBytes(buf []byte) ([]byte, Tags) { // when just parsing a key state, i, _ := scanMeasurement(buf, 0) + var name []byte var tags Tags if state == tagKeyState { tags = parseTags(buf) // scanMeasurement returns the location of the comma if there are tags, strip that off - return buf[:i-1], tags + name = buf[:i-1] + } else { + name = buf[:i] } - return buf[:i], tags + return unescapeMeasurement(name), tags } func ParseTags(buf []byte) Tags { return parseTags(buf) } -func ParseName(buf []byte) ([]byte, error) { +func ParseName(buf []byte) []byte { // Ignore the error because scanMeasurement returns "missing fields" which we ignore // when just parsing a key state, i, _ := scanMeasurement(buf, 0) + var name []byte if state == tagKeyState { - return buf[:i-1], nil + name = buf[:i-1] + } else { + name = buf[:i] } - return buf[:i], nil + + return unescapeMeasurement(name) } // ParsePointsWithPrecision is similar to ParsePoints, but allows the diff --git a/models/points_test.go b/models/points_test.go index 94f8a614771..9e1e5422577 100644 --- a/models/points_test.go +++ b/models/points_test.go @@ -2388,6 +2388,50 @@ func TestEscapeStringField(t *testing.T) { } } +func TestParseKeyBytes(t *testing.T) { + testCases := []struct { + input string + expectedName string + expectedTags map[string]string + }{ + {input: "m,k=v", expectedName: "m", expectedTags: map[string]string{"k": "v"}}, + {input: "m\\ q,k=v", expectedName: "m q", expectedTags: map[string]string{"k": "v"}}, + {input: "m,k\\ q=v", expectedName: "m", expectedTags: map[string]string{"k q": "v"}}, + {input: "m\\ q,k\\ q=v", expectedName: "m q", expectedTags: map[string]string{"k q": "v"}}, + } + + for _, testCase := range testCases { + t.Run(testCase.input, func(t *testing.T) { + name, tags := models.ParseKeyBytes([]byte(testCase.input)) + if !bytes.Equal([]byte(testCase.expectedName), name) { + t.Errorf("%s produced measurement %s but expected %s", testCase.input, string(name), testCase.expectedName) + } + if !tags.Equal(models.NewTags(testCase.expectedTags)) { + t.Errorf("%s produced tags %s but expected %s", testCase.input, tags.String(), models.NewTags(testCase.expectedTags).String()) + } + }) + } +} + +func TestParseName(t *testing.T) { + testCases := []struct { + input string + expectedName string + }{ + {input: "m,k=v", expectedName: "m"}, + {input: "m\\ q,k=v", expectedName: "m q"}, + } + + for _, testCase := range testCases { + t.Run(testCase.input, func(t *testing.T) { + name := models.ParseName([]byte(testCase.input)) + if !bytes.Equal([]byte(testCase.expectedName), name) { + t.Errorf("%s produced measurement %s but expected %s", testCase.input, string(name), testCase.expectedName) + } + }) + } +} + func BenchmarkEscapeStringField_Plain(b *testing.B) { s := "nothing special" for i := 0; i < b.N; i++ { diff --git a/tsdb/engine/tsm1/engine.go b/tsdb/engine/tsm1/engine.go index 0f5e1571027..9412ee75f64 100644 --- a/tsdb/engine/tsm1/engine.go +++ b/tsdb/engine/tsm1/engine.go @@ -1203,7 +1203,7 @@ func (e *Engine) addToIndexFromKey(keys [][]byte, fieldTypes []influxql.DataType for i := 0; i < len(keys); i++ { // Replace tsm key format with index key format. keys[i], field = SeriesAndFieldFromCompositeKey(keys[i]) - name := tsdb.MeasurementFromSeriesKey(keys[i]) + name := models.ParseName(keys[i]) mf := e.fieldset.CreateFieldsIfNotExists(name) if err := mf.CreateFieldIfNotExists(field, fieldTypes[i]); err != nil { return err diff --git a/tsdb/meta.go b/tsdb/meta.go index 57fb9e72e5d..0a7d273090b 100644 --- a/tsdb/meta.go +++ b/tsdb/meta.go @@ -6,7 +6,6 @@ import ( "sort" "github.com/influxdata/influxdb/models" - "github.com/influxdata/influxdb/pkg/escape" ) // MarshalTags converts a tag set to bytes for use as a lookup key. @@ -97,11 +96,3 @@ func MakeTagsKey(keys []string, tags models.Tags) []byte { return b } - -// MeasurementFromSeriesKey returns the name of the measurement from a key that -// contains a measurement name. -func MeasurementFromSeriesKey(key []byte) []byte { - // Ignoring the error because the func returns "missing fields" - k, _ := models.ParseName(key) - return escape.Unescape(k) -}