From 6fe8217ce4ab9a161aeba0c375a26bc2102beed0 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sat, 21 Oct 2023 12:38:01 +0000 Subject: [PATCH 1/2] tsdb: shrink txRing with smaller integers 4 billion active transactions ought to be enough for anyone. Signed-off-by: Bryan Boreham --- tsdb/head_read.go | 2 +- tsdb/head_test.go | 2 +- tsdb/isolation.go | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tsdb/head_read.go b/tsdb/head_read.go index 6964d5472..6e74b74a6 100644 --- a/tsdb/head_read.go +++ b/tsdb/head_read.go @@ -724,7 +724,7 @@ func (s *memSeries) iterator(id chunks.HeadChunkID, c chunkenc.Chunk, isoState * // Removing the extra transactionIDs that are relevant for samples that // come after this chunk, from the total transactionIDs. - appendIDsToConsider := s.txs.txIDCount - (totalSamples - (previousSamples + numSamples)) + appendIDsToConsider := int(s.txs.txIDCount) - (totalSamples - (previousSamples + numSamples)) // Iterate over the appendIDs, find the first one that the isolation state says not // to return. diff --git a/tsdb/head_test.go b/tsdb/head_test.go index 54fd469a3..616270100 100644 --- a/tsdb/head_test.go +++ b/tsdb/head_test.go @@ -2550,7 +2550,7 @@ func TestIsolationAppendIDZeroIsNoop(t *testing.T) { ok, _ := s.append(0, 0, 0, cOpts) require.True(t, ok, "Series append failed.") - require.Equal(t, 0, s.txs.txIDCount, "Series should not have an appendID after append with appendID=0.") + require.Equal(t, 0, int(s.txs.txIDCount), "Series should not have an appendID after append with appendID=0.") } func TestHeadSeriesChunkRace(t *testing.T) { diff --git a/tsdb/isolation.go b/tsdb/isolation.go index e436884a8..19eba9340 100644 --- a/tsdb/isolation.go +++ b/tsdb/isolation.go @@ -240,8 +240,8 @@ func (i *isolation) closeAppend(appendID uint64) { // The transactionID ring buffer. type txRing struct { txIDs []uint64 - txIDFirst int // Position of the first id in the ring. - txIDCount int // How many ids in the ring. + txIDFirst uint32 // Position of the first id in the ring. + txIDCount uint32 // How many ids in the ring. } func newTxRing(capacity int) *txRing { @@ -251,7 +251,7 @@ func newTxRing(capacity int) *txRing { } func (txr *txRing) add(appendID uint64) { - if txr.txIDCount == len(txr.txIDs) { + if int(txr.txIDCount) == len(txr.txIDs) { // Ring buffer is full, expand by doubling. newRing := make([]uint64, txr.txIDCount*2) idx := copy(newRing, txr.txIDs[txr.txIDFirst:]) @@ -260,12 +260,12 @@ func (txr *txRing) add(appendID uint64) { txr.txIDFirst = 0 } - txr.txIDs[(txr.txIDFirst+txr.txIDCount)%len(txr.txIDs)] = appendID + txr.txIDs[int(txr.txIDFirst+txr.txIDCount)%len(txr.txIDs)] = appendID txr.txIDCount++ } func (txr *txRing) cleanupAppendIDsBelow(bound uint64) { - pos := txr.txIDFirst + pos := int(txr.txIDFirst) for txr.txIDCount > 0 { if txr.txIDs[pos] < bound { @@ -281,7 +281,7 @@ func (txr *txRing) cleanupAppendIDsBelow(bound uint64) { } } - txr.txIDFirst %= len(txr.txIDs) + txr.txIDFirst %= uint32(len(txr.txIDs)) } func (txr *txRing) iterator() *txRingIterator { @@ -296,7 +296,7 @@ func (txr *txRing) iterator() *txRingIterator { type txRingIterator struct { ids []uint64 - pos int + pos uint32 } func (it *txRingIterator) At() uint64 { @@ -305,7 +305,7 @@ func (it *txRingIterator) At() uint64 { func (it *txRingIterator) Next() { it.pos++ - if it.pos == len(it.ids) { + if int(it.pos) == len(it.ids) { it.pos = 0 } } From 90e98e0235522451bf35d054173702c8837f97b1 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sat, 21 Oct 2023 13:45:47 +0000 Subject: [PATCH 2/2] tsdb: create isolation transaction slice on demand When Prometheus restarts it creates every series read in from the WAL, but many of those series will be finished, and never receive any more samples. By defering allocation of the txRing slice to when it is first needed, we save 32 bytes per stale series. Signed-off-by: Bryan Boreham --- tsdb/head.go | 2 +- tsdb/isolation.go | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tsdb/head.go b/tsdb/head.go index 0ea2b8385..4a6e6ac73 100644 --- a/tsdb/head.go +++ b/tsdb/head.go @@ -2011,7 +2011,7 @@ func newMemSeries(lset labels.Labels, id chunks.HeadSeriesRef, isolationDisabled nextAt: math.MinInt64, } if !isolationDisabled { - s.txs = newTxRing(4) + s.txs = newTxRing(0) } return s } diff --git a/tsdb/isolation.go b/tsdb/isolation.go index 19eba9340..86330f36e 100644 --- a/tsdb/isolation.go +++ b/tsdb/isolation.go @@ -253,7 +253,11 @@ func newTxRing(capacity int) *txRing { func (txr *txRing) add(appendID uint64) { if int(txr.txIDCount) == len(txr.txIDs) { // Ring buffer is full, expand by doubling. - newRing := make([]uint64, txr.txIDCount*2) + newLen := txr.txIDCount * 2 + if newLen == 0 { + newLen = 4 + } + newRing := make([]uint64, newLen) idx := copy(newRing, txr.txIDs[txr.txIDFirst:]) copy(newRing[idx:], txr.txIDs[:txr.txIDFirst]) txr.txIDs = newRing @@ -265,6 +269,9 @@ func (txr *txRing) add(appendID uint64) { } func (txr *txRing) cleanupAppendIDsBelow(bound uint64) { + if len(txr.txIDs) == 0 { + return + } pos := int(txr.txIDFirst) for txr.txIDCount > 0 {