Clarify postings index semantics, handle staleness

The postings list index may point to series that no longer
exist during garbage collection. This clarifies that this is valid
behavior.
It would be possible, though more complex, to always keep them in sync.
However, series existance means nothing in itself as the queried time
range defines whether there's actual data. Thus our definition is sane
overall as long as drift is kept small.
This commit is contained in:
Fabian Reinartz 2017-10-11 09:33:35 +02:00
parent 6e94145515
commit 665955da48
4 changed files with 12 additions and 14 deletions

View File

@ -833,24 +833,17 @@ func (h *headIndexReader) SortedPostings(p Postings) Postings {
if err := p.Err(); err != nil {
return errPostings{err: errors.Wrap(err, "expand postings")}
}
var err error
sort.Slice(ep, func(i, j int) bool {
if err != nil {
return false
}
a := h.head.series.getByID(ep[i])
b := h.head.series.getByID(ep[j])
if a == nil || b == nil {
err = errors.Errorf("series not found")
level.Debug(h.head.logger).Log("msg", "looked up series not found")
return false
}
return labels.Compare(a.lset, b.lset) < 0
})
if err != nil {
return errPostings{err: err}
}
return newListPostings(ep)
}

View File

@ -525,6 +525,8 @@ type IndexReader interface {
// Postings returns the postings list iterator for the label pair.
// The Postings here contain the offsets to the series inside the index.
// Found IDs are not strictly required to point to a valid Series, e.g. during
// background garbage collections.
Postings(name, value string) (Postings, error)
// SortedPostings returns a postings list that is reordered to be sorted
@ -533,6 +535,7 @@ type IndexReader interface {
// Series populates the given labels and chunk metas for the series identified
// by the reference.
// Returns ErrNotFound if the ref does not resolve to a known series.
Series(ref uint64, lset *labels.Labels, chks *[]ChunkMeta) error
// LabelIndices returns the label pairs for which indices exist.

View File

@ -450,6 +450,10 @@ Outer:
for s.p.Next() {
ref := s.p.At()
if err := s.index.Series(ref, &lset, &chunks); err != nil {
// Postings may be stale. Skip if no underlying series exists.
if errors.Cause(err) == ErrNotFound {
continue
}
s.err = err
return false
}

View File

@ -702,9 +702,8 @@ func TestBaseChunkSeries(t *testing.T) {
ref: 108,
},
},
postings: []uint64{12, 10, 108},
expIdxs: []int{0, 1, 3},
postings: []uint64{12, 13, 10, 108}, // 13 doesn't exist and should just be skipped over.
expIdxs: []int{0, 1, 3},
},
{
series: []refdSeries{
@ -718,12 +717,11 @@ func TestBaseChunkSeries(t *testing.T) {
{
lset: labels.New([]labels.Label{{"b", "c"}}...),
chunks: []ChunkMeta{{Ref: 8282}},
ref: 1,
ref: 3,
},
},
postings: []uint64{},
expIdxs: []int{},
expIdxs: []int{},
},
}