Remove symbols map from TSDB head (#9301)

This saves memory, effort and locking.

Since every symbol is also added to postings, `Symbols()` can be
implemented there instead. This now has to build a map for
deduplication, but `Symbols()` is only called for compaction, and `gc()`
used to rebuild the symbols map after every compaction so not an
additional cost.

Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
This commit is contained in:
Bryan Boreham 2021-09-08 10:18:48 +01:00 committed by GitHub
parent 92a3eeac55
commit 87d909df4a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 50 deletions

View file

@ -79,9 +79,6 @@ type Head struct {
// All series addressable by their ID or hash.
series *stripeSeries
symMtx sync.RWMutex
symbols map[string]struct{}
deletedMtx sync.Mutex
deleted map[uint64]int // Deleted series, and what WAL segment they must be kept until.
@ -223,7 +220,6 @@ func (h *Head) resetInMemoryState() error {
h.exemplarMetrics = em
h.exemplars = es
h.series = newStripeSeries(h.opts.StripeSize, h.opts.SeriesCallback)
h.symbols = map[string]struct{}{}
h.postings = index.NewUnorderedMemPostings()
h.tombstones = tombstones.NewMemTombstones()
h.iso = newIsolation()
@ -1120,22 +1116,6 @@ func (h *Head) gc() int64 {
h.deletedMtx.Unlock()
}
// Rebuild symbols and label value indices from what is left in the postings terms.
// symMtx ensures that append of symbols and postings is disabled for rebuild time.
h.symMtx.Lock()
defer h.symMtx.Unlock()
symbols := make(map[string]struct{}, len(h.symbols))
if err := h.postings.Iter(func(l labels.Label, _ index.Postings) error {
symbols[l.Name] = struct{}{}
symbols[l.Value] = struct{}{}
return nil
}); err != nil {
// This should never happen, as the iteration function only returns nil.
panic(err)
}
h.symbols = symbols
return actualMint
}
@ -1234,14 +1214,6 @@ func (h *Head) getOrCreateWithID(id, hash uint64, lset labels.Labels) (*memSerie
h.metrics.seriesCreated.Inc()
h.numSeries.Inc()
h.symMtx.Lock()
defer h.symMtx.Unlock()
for _, l := range lset {
h.symbols[l.Name] = struct{}{}
h.symbols[l.Value] = struct{}{}
}
h.postings.Add(id, lset)
return s, true, nil
}

View file

@ -54,16 +54,7 @@ func (h *headIndexReader) Close() error {
}
func (h *headIndexReader) Symbols() index.StringIter {
h.head.symMtx.RLock()
res := make([]string, 0, len(h.head.symbols))
for s := range h.head.symbols {
res = append(res, s)
}
h.head.symMtx.RUnlock()
sort.Strings(res)
return index.NewStringListIter(res)
return h.head.postings.Symbols()
}
// SortedLabelValues returns label values present in the head for the
@ -88,8 +79,6 @@ func (h *headIndexReader) LabelValues(name string, matchers ...*labels.Matcher)
}
if len(matchers) == 0 {
h.head.symMtx.RLock()
defer h.head.symMtx.RUnlock()
return h.head.postings.LabelValues(name), nil
}
@ -104,10 +93,7 @@ func (h *headIndexReader) LabelNames(matchers ...*labels.Matcher) ([]string, err
}
if len(matchers) == 0 {
h.head.symMtx.RLock()
labelNames := h.head.postings.LabelNames()
h.head.symMtx.RUnlock()
sort.Strings(labelNames)
return labelNames, nil
}

View file

@ -469,13 +469,14 @@ func TestHead_Truncate(t *testing.T) {
require.Nil(t, postingsB2)
require.Nil(t, postingsC1)
require.Equal(t, map[string]struct{}{
"": {}, // from 'all' postings list
"a": {},
"b": {},
"1": {},
"2": {},
}, h.symbols)
iter := h.postings.Symbols()
symbols := []string{}
for iter.Next() {
symbols = append(symbols, iter.At())
}
require.Equal(t,
[]string{"" /* from 'all' postings list */, "1", "2", "a", "b"},
symbols)
values := map[string]map[string]struct{}{}
for _, name := range h.postings.LabelNames() {

View file

@ -58,6 +58,29 @@ func NewUnorderedMemPostings() *MemPostings {
}
}
// Symbols returns an iterator over all unique name and value strings, in order.
func (p *MemPostings) Symbols() StringIter {
p.mtx.RLock()
// Add all the strings to a map to de-duplicate.
symbols := make(map[string]struct{}, 512)
for n, e := range p.m {
symbols[n] = struct{}{}
for v := range e {
symbols[v] = struct{}{}
}
}
p.mtx.RUnlock()
res := make([]string, 0, len(symbols))
for k := range symbols {
res = append(res, k)
}
sort.Strings(res)
return NewStringListIter(res)
}
// SortedKeys returns a list of sorted label keys of the postings.
func (p *MemPostings) SortedKeys() []labels.Label {
p.mtx.RLock()