Skip to content

Commit

Permalink
Reuse components slice when parsing chunk time range value. (grafana#…
Browse files Browse the repository at this point in the history
…3501)

This uses a buffer pool for when we parse the chunk time range value.

```
❯ benchcmp before.txt after.txt
benchmark                                      old ns/op     new ns/op     delta
BenchmarkParseIndexEntries500-16               265343        232446        -12.40%
BenchmarkParseIndexEntries2500-16              1393835       1232639       -11.56%
BenchmarkParseIndexEntries10000-16             5741372       5032199       -12.35%
BenchmarkParseIndexEntries50000-16             30158888      27272835      -9.57%
BenchmarkParseIndexEntriesRegexSet500-16       79101         50394         -36.29%
BenchmarkParseIndexEntriesRegexSet2500-16      386920        246015        -36.42%
BenchmarkParseIndexEntriesRegexSet10000-16     1570068       957154        -39.04%
BenchmarkParseIndexEntriesRegexSet50000-16     7445006       4757111       -36.10%

benchmark                                      old allocs     new allocs     delta
BenchmarkParseIndexEntries500-16               1504           1004           -33.24%
BenchmarkParseIndexEntries2500-16              7504           5004           -33.32%
BenchmarkParseIndexEntries10000-16             30006          20005          -33.33%
BenchmarkParseIndexEntries50000-16             150008         100007         -33.33%
BenchmarkParseIndexEntriesRegexSet500-16       1522           1022           -32.85%
BenchmarkParseIndexEntriesRegexSet2500-16      7522           5022           -33.24%
BenchmarkParseIndexEntriesRegexSet10000-16     30022          20022          -33.31%
BenchmarkParseIndexEntriesRegexSet50000-16     150022         100022         -33.33%

benchmark                                      old bytes     new bytes     delta
BenchmarkParseIndexEntries500-16               96397         32365         -66.43%
BenchmarkParseIndexEntries2500-16              482307        162164        -66.38%
BenchmarkParseIndexEntries10000-16             1928766       648454        -66.38%
BenchmarkParseIndexEntries50000-16             9608702       3207322       -66.62%
BenchmarkParseIndexEntriesRegexSet500-16       88665         24689         -72.15%
BenchmarkParseIndexEntriesRegexSet2500-16      441471        121573        -72.46%
BenchmarkParseIndexEntriesRegexSet10000-16     1764370       484644        -72.53%
BenchmarkParseIndexEntriesRegexSet50000-16     8803429       2404042       -72.69%
```

Signed-off-by: Cyril Tovena <cyril.tovena@gmail.com>
  • Loading branch information
cyriltovena authored Nov 18, 2020
1 parent 58b2268 commit 4245565
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 13 deletions.
4 changes: 2 additions & 2 deletions chunk_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ func (c *baseStore) LabelValuesForMetricName(ctx context.Context, userID string,

var result UniqueStrings
for _, entry := range entries {
_, labelValue, _, err := parseChunkTimeRangeValue(entry.RangeValue, entry.Value)
_, labelValue, err := parseChunkTimeRangeValue(entry.RangeValue, entry.Value)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -559,7 +559,7 @@ func (c *baseStore) parseIndexEntries(_ context.Context, entries []IndexEntry, m

result := make([]string, 0, len(entries))
for _, entry := range entries {
chunkKey, labelValue, _, err := parseChunkTimeRangeValue(entry.RangeValue, entry.Value)
chunkKey, labelValue, err := parseChunkTimeRangeValue(entry.RangeValue, entry.Value)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ const (

// parseRangeValueType returns the type of rangeValue
func parseRangeValueType(rangeValue []byte) (int, error) {
components := decodeRangeKey(rangeValue)
components := decodeRangeKey(rangeValue, make([][]byte, 0, 5))
switch {
case len(components) < 3:
return 0, fmt.Errorf("invalid range value: %x", rangeValue)
Expand Down Expand Up @@ -340,7 +340,7 @@ func TestSchemaRangeKey(t *testing.T) {
_, err := parseMetricNameRangeValue(entry.RangeValue, entry.Value)
require.NoError(t, err)
case ChunkTimeRangeValue:
_, _, _, err := parseChunkTimeRangeValue(entry.RangeValue, entry.Value)
_, _, err := parseChunkTimeRangeValue(entry.RangeValue, entry.Value)
require.NoError(t, err)
case SeriesRangeValue:
_, err := parseSeriesRangeValue(entry.RangeValue, entry.Value)
Expand Down
33 changes: 25 additions & 8 deletions schema_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"encoding/json"
"strconv"
"strings"
"sync"

"fmt"

Expand Down Expand Up @@ -82,8 +83,8 @@ func rangeValuePrefix(ss ...[]byte) []byte {
return buildRangeValue(0, ss...)
}

func decodeRangeKey(value []byte) [][]byte {
components := make([][]byte, 0, 5)
func decodeRangeKey(value []byte, components [][]byte) [][]byte {
components = components[:0]
i, j := 0, 0
for j < len(value) {
if value[j] != 0 {
Expand Down Expand Up @@ -134,7 +135,10 @@ func encodeTime(t uint32) []byte {
// range values. Currently checks range value key and returns the value as the
// metric name.
func parseMetricNameRangeValue(rangeValue []byte, value []byte) (model.LabelValue, error) {
components := decodeRangeKey(rangeValue)
componentRef := componentsPool.Get().(*componentRef)
defer componentsPool.Put(componentRef)
components := decodeRangeKey(rangeValue, componentRef.components)

switch {
case len(components) < 4:
return "", fmt.Errorf("invalid metric name range value: %x", rangeValue)
Expand All @@ -151,7 +155,10 @@ func parseMetricNameRangeValue(rangeValue []byte, value []byte) (model.LabelValu
// parseSeriesRangeValue returns the model.Metric stored in metric fingerprint
// range values.
func parseSeriesRangeValue(rangeValue []byte, value []byte) (model.Metric, error) {
components := decodeRangeKey(rangeValue)
componentRef := componentsPool.Get().(*componentRef)
defer componentsPool.Put(componentRef)
components := decodeRangeKey(rangeValue, componentRef.components)

switch {
case len(components) < 4:
return nil, fmt.Errorf("invalid metric range value: %x", rangeValue)
Expand All @@ -169,12 +176,24 @@ func parseSeriesRangeValue(rangeValue []byte, value []byte) (model.Metric, error
}
}

type componentRef struct {
components [][]byte
}

var componentsPool = sync.Pool{
New: func() interface{} {
return &componentRef{components: make([][]byte, 0, 5)}
},
}

// parseChunkTimeRangeValue returns the chunkID and labelValue for chunk time
// range values.
func parseChunkTimeRangeValue(rangeValue []byte, value []byte) (
chunkID string, labelValue model.LabelValue, isSeriesID bool, err error,
chunkID string, labelValue model.LabelValue, err error,
) {
components := decodeRangeKey(rangeValue)
componentRef := componentsPool.Get().(*componentRef)
defer componentsPool.Put(componentRef)
components := decodeRangeKey(rangeValue, componentRef.components)

switch {
case len(components) < 3:
Expand Down Expand Up @@ -225,13 +244,11 @@ func parseChunkTimeRangeValue(rangeValue []byte, value []byte) (
// v9 schema actually return series IDs
case seriesRangeKeyV1:
chunkID = string(components[0])
isSeriesID = true
return

case labelSeriesRangeKeyV1:
chunkID = string(components[1])
labelValue = model.LabelValue(value)
isSeriesID = true
return
}
}
Expand Down
2 changes: 1 addition & 1 deletion schema_util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func TestParseChunkTimeRangeValue(t *testing.T) {
{[]byte("a1b2c3d4\x00Y29kZQ\x002:1484661279394:1484664879394\x004\x00"),
"code", "2:1484661279394:1484664879394"},
} {
chunkID, labelValue, _, err := parseChunkTimeRangeValue(c.encoded, nil)
chunkID, labelValue, err := parseChunkTimeRangeValue(c.encoded, nil)
require.NoError(t, err)
assert.Equal(t, model.LabelValue(c.value), labelValue)
assert.Equal(t, c.chunkID, chunkID)
Expand Down

0 comments on commit 4245565

Please sign in to comment.