From 7345567c293a54274b9900c0c3c19007dc22f265 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Mon, 22 Jan 2024 22:15:08 +0200 Subject: [PATCH] app/vmselect/netstorage: substitute pointer to blockRefs by brssPool index at the metricName->blockRefs map This should reduce the pressure on Go GC, since it will see lower number of pointers. This change has been extracted from https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5527 --- app/vmselect/netstorage/netstorage.go | 32 +++++++++++++++++---------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/app/vmselect/netstorage/netstorage.go b/app/vmselect/netstorage/netstorage.go index 34dc4c4956..da4468f5ad 100644 --- a/app/vmselect/netstorage/netstorage.go +++ b/app/vmselect/netstorage/netstorage.go @@ -1172,8 +1172,7 @@ func ProcessSearchQuery(qt *querytracer.Tracer, sq *storage.SearchQuery, deadlin brsPrealloc [4]blockRef brs []blockRef } - m := make(map[string]*blockRefs, maxSeriesCount) - orderedMetricNames := make([]string, 0, maxSeriesCount) + blocksRead := 0 samples := 0 tbf := getTmpBlocksFile() @@ -1184,9 +1183,16 @@ func ProcessSearchQuery(qt *querytracer.Tracer, sq *storage.SearchQuery, deadlin // when constructing metricName string from byte slice. var metricNamesBuf []byte - // brssBuf is used for holding all the blockRefs objects across all the loaded time series. + // brssPool is used for holding all the blockRefs objects across all the loaded time series. // It should reduce pressure on Go GC by reducing the number of blockRefs allocations. - var brssBuf []blockRefs + brssPool := make([]blockRefs, 0, maxSeriesCount) + + // m maps from metricName to the index of blockRefs inside brssPool + m := make(map[string]int, maxSeriesCount) + + // orderedMetricNames contains the list of loaded unique metric names + // in the load order. This order is important for triggering sequential data reading. + orderedMetricNames := make([]string, 0, maxSeriesCount) for sr.NextMetricBlock() { blocksRead++ @@ -1210,16 +1216,18 @@ func ProcessSearchQuery(qt *querytracer.Tracer, sq *storage.SearchQuery, deadlin return nil, fmt.Errorf("cannot write %d bytes to temporary file: %w", len(buf), err) } metricName := sr.MetricBlockRef.MetricName - brs := m[string(metricName)] - if brs == nil { - if cap(brssBuf) > len(brssBuf) { - brssBuf = brssBuf[:len(brssBuf)+1] + brsIdx, ok := m[string(metricName)] + if !ok { + if cap(brssPool) > len(brssPool) { + brssPool = brssPool[:len(brssPool)+1] } else { - brssBuf = append(brssBuf, blockRefs{}) + brssPool = append(brssPool, blockRefs{}) } - brs = &brssBuf[len(brssBuf)-1] + brsIdx = len(brssPool) - 1 + brs := &brssPool[brsIdx] brs.brs = brs.brsPrealloc[:0] } + brs := &brssPool[brsIdx] brs.brs = append(brs.brs, blockRef{ partRef: br.PartRef(), addr: addr, @@ -1230,7 +1238,7 @@ func ProcessSearchQuery(qt *querytracer.Tracer, sq *storage.SearchQuery, deadlin metricNameStr := bytesutil.ToUnsafeString(metricNamesBuf[metricNamesBufLen:]) orderedMetricNames = append(orderedMetricNames, metricNameStr) - m[metricNameStr] = brs + m[metricNameStr] = brsIdx } } if err := sr.Error(); err != nil { @@ -1255,7 +1263,7 @@ func ProcessSearchQuery(qt *querytracer.Tracer, sq *storage.SearchQuery, deadlin for i, metricName := range orderedMetricNames { pts[i] = packedTimeseries{ metricName: metricName, - brs: m[metricName].brs, + brs: brssPool[m[metricName]].brs, } } rss.packedTimeseries = pts