TSDB: Allocate series ID after seriesLifecycleCallback

This callback is not used by Prometheus, but in downstream projects it
is wasteful to allocate an ID only to abandon it.

Remove lengthy commment which I feel is distracting from the flow.

Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
This commit is contained in:
Bryan Boreham 2025-10-17 11:04:34 +01:00
parent 2852c9c431
commit 42b52ecc4b
3 changed files with 10 additions and 11 deletions

View File

@ -1738,24 +1738,23 @@ func (*Head) String() string {
}
func (h *Head) getOrCreate(hash uint64, lset labels.Labels, pendingCommit bool) (*memSeries, bool, error) {
// Just using `getOrCreateWithID` below would be semantically sufficient, but we'd create
// a new series on every sample inserted via Add(), which causes allocations
// and makes our series IDs rather random and harder to compress in postings.
s := h.series.getByHash(hash, lset)
if s != nil {
return s, false, nil
}
// Optimistically assume that we are the first one to create the series.
id := chunks.HeadSeriesRef(h.lastSeriesID.Inc())
return h.getOrCreateWithID(id, hash, lset, pendingCommit)
return h.getOrCreateWithOptionalID(0, hash, lset, pendingCommit)
}
func (h *Head) getOrCreateWithID(id chunks.HeadSeriesRef, hash uint64, lset labels.Labels, pendingCommit bool) (*memSeries, bool, error) {
// If id is zero, one will be allocated.
func (h *Head) getOrCreateWithOptionalID(id chunks.HeadSeriesRef, hash uint64, lset labels.Labels, pendingCommit bool) (*memSeries, bool, error) {
if preCreationErr := h.series.seriesLifecycleCallback.PreCreation(lset); preCreationErr != nil {
return nil, false, preCreationErr
}
if id == 0 {
// Note this id is wasted in the case where a concurrent operation creates the same series first.
id = chunks.HeadSeriesRef(h.lastSeriesID.Inc())
}
shardHash := uint64(0)
if h.opts.EnableSharding {

View File

@ -1152,7 +1152,7 @@ func TestHead_KeepSeriesInWALCheckpoint(t *testing.T) {
{
name: "keep series still in the head",
prepare: func(t *testing.T, h *Head) {
_, _, err := h.getOrCreateWithID(chunks.HeadSeriesRef(existingRef), existingLbls.Hash(), existingLbls, false)
_, _, err := h.getOrCreateWithOptionalID(chunks.HeadSeriesRef(existingRef), existingLbls.Hash(), existingLbls, false)
require.NoError(t, err)
},
expected: true,

View File

@ -255,7 +255,7 @@ Outer:
switch v := d.(type) {
case []record.RefSeries:
for _, walSeries := range v {
mSeries, created, err := h.getOrCreateWithID(walSeries.Ref, walSeries.Labels.Hash(), walSeries.Labels, false)
mSeries, created, err := h.getOrCreateWithOptionalID(walSeries.Ref, walSeries.Labels.Hash(), walSeries.Labels, false)
if err != nil {
seriesCreationErr = err
break Outer
@ -1590,7 +1590,7 @@ func (h *Head) loadChunkSnapshot() (int, int, map[chunks.HeadSeriesRef]*memSerie
localRefSeries := shardedRefSeries[idx]
for csr := range rc {
series, _, err := h.getOrCreateWithID(csr.ref, csr.lset.Hash(), csr.lset, false)
series, _, err := h.getOrCreateWithOptionalID(csr.ref, csr.lset.Hash(), csr.lset, false)
if err != nil {
errChan <- err
return