diff --git a/head_bench_test.go b/head_bench_test.go index 68505ea2c..0b0391e0a 100644 --- a/head_bench_test.go +++ b/head_bench_test.go @@ -56,20 +56,21 @@ func BenchmarkHeadPostingForMatchers(b *testing.B) { testutil.Ok(b, h.Close()) }() - var hash uint64 + var ref uint64 + + addSeries := func(l labels.Labels) { + ref++ + h.getOrCreateWithID(ref, l.Hash(), l) + } + for n := 0; n < 10; n++ { for i := 0; i < 100000; i++ { - h.getOrCreate(hash, labels.FromStrings("i", strconv.Itoa(i), "n", strconv.Itoa(i), "j", "foo")) - hash++ + addSeries(labels.FromStrings("i", strconv.Itoa(i), "n", strconv.Itoa(n), "j", "foo")) // Have some series that won't be matched, to properly test inverted matches. - h.getOrCreate(hash, labels.FromStrings("i", strconv.Itoa(i), "n", strconv.Itoa(i), "j", "bar")) - hash++ - h.getOrCreate(hash, labels.FromStrings("i", strconv.Itoa(i), "n", "0_"+strconv.Itoa(i), "j", "bar")) - hash++ - h.getOrCreate(hash, labels.FromStrings("i", strconv.Itoa(i), "n", "1_"+strconv.Itoa(i), "j", "bar")) - hash++ - h.getOrCreate(hash, labels.FromStrings("i", strconv.Itoa(i), "n", "2_"+strconv.Itoa(i), "j", "bar")) - hash++ + addSeries(labels.FromStrings("i", strconv.Itoa(i), "n", strconv.Itoa(n), "j", "bar")) + addSeries(labels.FromStrings("i", strconv.Itoa(i), "n", "0_"+strconv.Itoa(n), "j", "bar")) + addSeries(labels.FromStrings("i", strconv.Itoa(i), "n", "1_"+strconv.Itoa(n), "j", "bar")) + addSeries(labels.FromStrings("i", strconv.Itoa(i), "n", "2_"+strconv.Itoa(n), "j", "foo")) } } @@ -100,6 +101,7 @@ func BenchmarkHeadPostingForMatchers(b *testing.B) { {`i!=""`, []labels.Matcher{iNotEmpty}}, {`n="1",i=~".*",j="foo"`, []labels.Matcher{n1, iStar, jFoo}}, {`n="1",i=~".*",i!="2",j="foo"`, []labels.Matcher{n1, iStar, iNot2, jFoo}}, + {`n="1",i!=""`, []labels.Matcher{n1, iNotEmpty}}, {`n="1",i!="",j="foo"`, []labels.Matcher{n1, iNotEmpty, jFoo}}, {`n="1",i=~".+",j="foo"`, []labels.Matcher{n1, iPlus, jFoo}}, {`n="1",i=~"1.+",j="foo"`, []labels.Matcher{n1, i1Plus, jFoo}}, diff --git a/index/postings.go b/index/postings.go index cdad93953..bb7b5837a 100644 --- a/index/postings.go +++ b/index/postings.go @@ -404,7 +404,6 @@ func (h *postingsHeap) Pop() interface{} { type mergedPostings struct { h postingsHeap initilized bool - heaped bool cur uint64 err error } @@ -434,12 +433,9 @@ func (it *mergedPostings) Next() bool { return false } - if !it.heaped { - heap.Init(&it.h) - it.heaped = true - } // The user must issue an initial Next. if !it.initilized { + heap.Init(&it.h) it.cur = it.h[0].At() it.initilized = true return true @@ -477,33 +473,24 @@ func (it *mergedPostings) Seek(id uint64) bool { return false } } - if it.cur >= id { - return true - } - // Heapifying when there is lots of Seeks is inefficient, - // mark to be re-heapified on the Next() call. - it.heaped = false - lowest := ^uint64(0) - n := 0 - for _, i := range it.h { - if i.Seek(id) { - it.h[n] = i - n++ - if i.At() < lowest { - lowest = i.At() - } - } else { - if i.Err() != nil { - it.err = i.Err() + for it.cur < id { + cur := it.h[0] + if !cur.Seek(id) { + heap.Pop(&it.h) + if cur.Err() != nil { + it.err = cur.Err() return false } + if it.h.Len() == 0 { + return false + } + } else { + // Value of top of heap has changed, re-heapify. + heap.Fix(&it.h, 0) } + + it.cur = it.h[0].At() } - it.h = it.h[:n] - if len(it.h) == 0 { - return false - } - it.cur = lowest return true } diff --git a/querier.go b/querier.go index b7116c27e..9d99de083 100644 --- a/querier.go +++ b/querier.go @@ -332,15 +332,6 @@ func PostingsForMatchers(ix IndexReader, ms ...labels.Matcher) (index.Postings, it := index.Intersect(its...) for _, n := range notIts { - if _, ok := n.(*index.ListPostings); !ok { - // Best to pre-calculate the merged lists via next rather than have a ton - // of seeks in Without. - pl, err := index.ExpandPostings(n) - if err != nil { - return nil, err - } - n = index.NewListPostings(pl) - } it = index.Without(it, n) }