mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Reduce memSeries memory usage by decoupling metadata (#11152)
Metadata was added recently but doesn't seem to be used much, at least as far as I could identify. Yet it's part of memSeries struct and so even when empty takes 48 bytes, which is a lot given that without it memSeries requires 224 bytes. This change turns it into a pointer on the struct, that get set only when metadata is actually set of given series. Signed-off-by: Łukasz Mierzwa <l.mierzwa@gmail.com> Signed-off-by: Łukasz Mierzwa <l.mierzwa@gmail.com>
This commit is contained in:
parent
af79dce8ea
commit
3196c98bc2
|
@ -1821,10 +1821,10 @@ func TestQuerierWithBoundaryChunks(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestInitializeHeadTimestamp ensures that the h.minTime is set properly.
|
// TestInitializeHeadTimestamp ensures that the h.minTime is set properly.
|
||||||
// - no blocks no WAL: set to the time of the first appended sample
|
// - no blocks no WAL: set to the time of the first appended sample
|
||||||
// - no blocks with WAL: set to the smallest sample from the WAL
|
// - no blocks with WAL: set to the smallest sample from the WAL
|
||||||
// - with blocks no WAL: set to the last block maxT
|
// - with blocks no WAL: set to the last block maxT
|
||||||
// - with blocks with WAL: same as above
|
// - with blocks with WAL: same as above
|
||||||
func TestInitializeHeadTimestamp(t *testing.T) {
|
func TestInitializeHeadTimestamp(t *testing.T) {
|
||||||
t.Run("clean", func(t *testing.T) {
|
t.Run("clean", func(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
|
@ -2166,10 +2166,12 @@ func TestCorrectNumTombstones(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestBlockRanges checks the following use cases:
|
// TestBlockRanges checks the following use cases:
|
||||||
// - No samples can be added with timestamps lower than the last block maxt.
|
// - No samples can be added with timestamps lower than the last block maxt.
|
||||||
// - The compactor doesn't create overlapping blocks
|
// - The compactor doesn't create overlapping blocks
|
||||||
|
//
|
||||||
// even when the last blocks is not within the default boundaries.
|
// even when the last blocks is not within the default boundaries.
|
||||||
// - Lower boundary is based on the smallest sample in the head and
|
// - Lower boundary is based on the smallest sample in the head and
|
||||||
|
//
|
||||||
// upper boundary is rounded to the configured block range.
|
// upper boundary is rounded to the configured block range.
|
||||||
//
|
//
|
||||||
// This ensures that a snapshot that includes the head and creates a block with a custom time range
|
// This ensures that a snapshot that includes the head and creates a block with a custom time range
|
||||||
|
@ -3697,10 +3699,10 @@ func TestMetadataAssertInMemoryData(t *testing.T) {
|
||||||
series2 := db.head.series.getByHash(s2.Hash(), s2)
|
series2 := db.head.series.getByHash(s2.Hash(), s2)
|
||||||
series3 := db.head.series.getByHash(s3.Hash(), s3)
|
series3 := db.head.series.getByHash(s3.Hash(), s3)
|
||||||
series4 := db.head.series.getByHash(s4.Hash(), s4)
|
series4 := db.head.series.getByHash(s4.Hash(), s4)
|
||||||
require.Equal(t, series1.meta, m1)
|
require.Equal(t, *series1.meta, m1)
|
||||||
require.Equal(t, series2.meta, m2)
|
require.Equal(t, *series2.meta, m2)
|
||||||
require.Equal(t, series3.meta, m3)
|
require.Equal(t, *series3.meta, m3)
|
||||||
require.Equal(t, series4.meta, metadata.Metadata{})
|
require.Nil(t, series4.meta)
|
||||||
|
|
||||||
// Add a replicated metadata entry to the first series,
|
// Add a replicated metadata entry to the first series,
|
||||||
// a changed metadata entry to the second series,
|
// a changed metadata entry to the second series,
|
||||||
|
@ -3718,10 +3720,10 @@ func TestMetadataAssertInMemoryData(t *testing.T) {
|
||||||
series2 = db.head.series.getByHash(s2.Hash(), s2)
|
series2 = db.head.series.getByHash(s2.Hash(), s2)
|
||||||
series3 = db.head.series.getByHash(s3.Hash(), s3)
|
series3 = db.head.series.getByHash(s3.Hash(), s3)
|
||||||
series4 = db.head.series.getByHash(s4.Hash(), s4)
|
series4 = db.head.series.getByHash(s4.Hash(), s4)
|
||||||
require.Equal(t, series1.meta, m1)
|
require.Equal(t, *series1.meta, m1)
|
||||||
require.Equal(t, series2.meta, m5)
|
require.Equal(t, *series2.meta, m5)
|
||||||
require.Equal(t, series3.meta, m3)
|
require.Equal(t, *series3.meta, m3)
|
||||||
require.Equal(t, series4.meta, m4)
|
require.Equal(t, *series4.meta, m4)
|
||||||
|
|
||||||
require.NoError(t, db.Close())
|
require.NoError(t, db.Close())
|
||||||
|
|
||||||
|
@ -3736,8 +3738,8 @@ func TestMetadataAssertInMemoryData(t *testing.T) {
|
||||||
_, err = reopenDB.head.wal.Size()
|
_, err = reopenDB.head.wal.Size()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, reopenDB.head.series.getByHash(s1.Hash(), s1).meta, m1)
|
require.Equal(t, *reopenDB.head.series.getByHash(s1.Hash(), s1).meta, m1)
|
||||||
require.Equal(t, reopenDB.head.series.getByHash(s2.Hash(), s2).meta, m5)
|
require.Equal(t, *reopenDB.head.series.getByHash(s2.Hash(), s2).meta, m5)
|
||||||
require.Equal(t, reopenDB.head.series.getByHash(s3.Hash(), s3).meta, m3)
|
require.Equal(t, *reopenDB.head.series.getByHash(s3.Hash(), s3).meta, m3)
|
||||||
require.Equal(t, reopenDB.head.series.getByHash(s4.Hash(), s4).meta, m4)
|
require.Equal(t, *reopenDB.head.series.getByHash(s4.Hash(), s4).meta, m4)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1516,7 +1516,7 @@ type memSeries struct {
|
||||||
|
|
||||||
ref chunks.HeadSeriesRef
|
ref chunks.HeadSeriesRef
|
||||||
lset labels.Labels
|
lset labels.Labels
|
||||||
meta metadata.Metadata
|
meta *metadata.Metadata
|
||||||
|
|
||||||
// Immutable chunks on disk that have not yet gone into a block, in order of ascending time stamps.
|
// Immutable chunks on disk that have not yet gone into a block, in order of ascending time stamps.
|
||||||
// When compaction runs, chunks get moved into a block and all pointers are shifted like so:
|
// When compaction runs, chunks get moved into a block and all pointers are shifted like so:
|
||||||
|
@ -1540,8 +1540,6 @@ type memSeries struct {
|
||||||
// Even the most compact encoding of a sample takes 2 bits, so the last byte is not contended.
|
// Even the most compact encoding of a sample takes 2 bits, so the last byte is not contended.
|
||||||
sampleBuf [4]sample
|
sampleBuf [4]sample
|
||||||
|
|
||||||
pendingCommit bool // Whether there are samples waiting to be committed to this series.
|
|
||||||
|
|
||||||
// Current appender for the head chunk. Set when a new head chunk is cut.
|
// Current appender for the head chunk. Set when a new head chunk is cut.
|
||||||
// It is nil only if headChunk is nil. E.g. if there was an appender that created a new series, but rolled back the commit
|
// It is nil only if headChunk is nil. E.g. if there was an appender that created a new series, but rolled back the commit
|
||||||
// (the first sample would create a headChunk, hence appender, but rollback skipped it while the Append() call would create a series).
|
// (the first sample would create a headChunk, hence appender, but rollback skipped it while the Append() call would create a series).
|
||||||
|
@ -1551,6 +1549,8 @@ type memSeries struct {
|
||||||
|
|
||||||
// txs is nil if isolation is disabled.
|
// txs is nil if isolation is disabled.
|
||||||
txs *txRing
|
txs *txRing
|
||||||
|
|
||||||
|
pendingCommit bool // Whether there are samples waiting to be committed to this series.
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMemSeries(lset labels.Labels, id chunks.HeadSeriesRef, chunkRange int64, memChunkPool *sync.Pool, isolationDisabled bool) *memSeries {
|
func newMemSeries(lset labels.Labels, id chunks.HeadSeriesRef, chunkRange int64, memChunkPool *sync.Pool, isolationDisabled bool) *memSeries {
|
||||||
|
|
|
@ -399,7 +399,7 @@ func (a *headAppender) UpdateMetadata(ref storage.SeriesRef, lset labels.Labels,
|
||||||
}
|
}
|
||||||
|
|
||||||
s.RLock()
|
s.RLock()
|
||||||
hasNewMetadata := s.meta != meta
|
hasNewMetadata := s.meta == nil || *s.meta != meta
|
||||||
s.RUnlock()
|
s.RUnlock()
|
||||||
|
|
||||||
if hasNewMetadata {
|
if hasNewMetadata {
|
||||||
|
@ -540,7 +540,7 @@ func (a *headAppender) Commit() (err error) {
|
||||||
for i, m := range a.metadata {
|
for i, m := range a.metadata {
|
||||||
series = a.metadataSeries[i]
|
series = a.metadataSeries[i]
|
||||||
series.Lock()
|
series.Lock()
|
||||||
series.meta = metadata.Metadata{Type: record.ToTextparseMetricType(m.Type), Unit: m.Unit, Help: m.Help}
|
series.meta = &metadata.Metadata{Type: record.ToTextparseMetricType(m.Type), Unit: m.Unit, Help: m.Help}
|
||||||
series.Unlock()
|
series.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -333,7 +333,7 @@ Outer:
|
||||||
unknownMetadataRefs.Inc()
|
unknownMetadataRefs.Inc()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
s.meta = metadata.Metadata{
|
s.meta = &metadata.Metadata{
|
||||||
Type: record.ToTextparseMetricType(m.Type),
|
Type: record.ToTextparseMetricType(m.Type),
|
||||||
Unit: m.Unit,
|
Unit: m.Unit,
|
||||||
Help: m.Help,
|
Help: m.Help,
|
||||||
|
|
Loading…
Reference in a new issue