From 0703dae7cc4fcb1e051ab5fec89c47530e78c75a Mon Sep 17 00:00:00 2001 From: Marco Pracucci Date: Fri, 24 Jan 2020 08:44:52 +0100 Subject: [PATCH] Compact TSDB head chunks after being cut, to reduce inuse memory Signed-off-by: Marco Pracucci --- tsdb/chunkenc/chunk.go | 1 + tsdb/chunkenc/xor.go | 12 ++++++++++++ tsdb/head.go | 5 +++++ 3 files changed, 18 insertions(+) diff --git a/tsdb/chunkenc/chunk.go b/tsdb/chunkenc/chunk.go index 5f9349f05..2bc1bf33f 100644 --- a/tsdb/chunkenc/chunk.go +++ b/tsdb/chunkenc/chunk.go @@ -49,6 +49,7 @@ type Chunk interface { // be re-used or a new iterator can be allocated. Iterator(Iterator) Iterator NumSamples() int + Compact() } // Appender adds sample pairs to a chunk. diff --git a/tsdb/chunkenc/xor.go b/tsdb/chunkenc/xor.go index ce6e0a951..5401261d9 100644 --- a/tsdb/chunkenc/xor.go +++ b/tsdb/chunkenc/xor.go @@ -49,6 +49,10 @@ import ( "math/bits" ) +const ( + chunkCompactCapacityThreshold = 32 +) + // XORChunk holds XOR encoded sample data. type XORChunk struct { b bstream @@ -75,6 +79,14 @@ func (c *XORChunk) NumSamples() int { return int(binary.BigEndian.Uint16(c.Bytes())) } +func (c *XORChunk) Compact() { + if l := len(c.b.stream); cap(c.b.stream) > l+chunkCompactCapacityThreshold { + buf := make([]byte, l) + copy(buf, c.b.stream) + c.b.stream = buf + } +} + // Appender implements the Chunk interface. func (c *XORChunk) Appender() (Appender, error) { it := c.iterator(nil) diff --git a/tsdb/head.go b/tsdb/head.go index ce4a36719..5769c770a 100644 --- a/tsdb/head.go +++ b/tsdb/head.go @@ -1691,6 +1691,11 @@ func (s *memSeries) cut(mint int64) *memChunk { s.chunks = append(s.chunks, c) s.headChunk = c + // Remove exceeding capacity from the previous chunk byte slice to save memory. + if l := len(s.chunks); l > 1 { + s.chunks[l-2].chunk.Compact() + } + // Set upper bound on when the next chunk must be started. An earlier timestamp // may be chosen dynamically at a later point. s.nextAt = rangeForTimestamp(mint, s.chunkRange) -- GitLab