@ -18,11 +18,13 @@ import (
"context"
"context"
"encoding/binary"
"encoding/binary"
"fmt"
"fmt"
"math"
"runtime"
"runtime"
"sort"
"sort"
"strings"
"strings"
"sync"
"sync"
"github.com/bboreham/go-loser"
"golang.org/x/exp/slices"
"golang.org/x/exp/slices"
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/model/labels"
@ -525,7 +527,7 @@ func (it *intersectPostings) Err() error {
}
}
// Merge returns a new iterator over the union of the input iterators.
// Merge returns a new iterator over the union of the input iterators.
func Merge ( ctx context . Context , its ... Postings ) Postings {
func Merge ( _ context . Context , its ... Postings ) Postings {
if len ( its ) == 0 {
if len ( its ) == 0 {
return EmptyPostings ( )
return EmptyPostings ( )
}
}
@ -533,122 +535,48 @@ func Merge(ctx context.Context, its ...Postings) Postings {
return its [ 0 ]
return its [ 0 ]
}
}
p , ok := newMergedPostings ( ctx, its)
p , ok := newMergedPostings ( its)
if ! ok {
if ! ok {
return EmptyPostings ( )
return EmptyPostings ( )
}
}
return p
return p
}
}
type postingsHeap [ ] Postings
func ( h postingsHeap ) Len ( ) int { return len ( h ) }
func ( h postingsHeap ) Less ( i , j int ) bool { return h [ i ] . At ( ) < h [ j ] . At ( ) }
func ( h * postingsHeap ) Swap ( i , j int ) { ( * h ) [ i ] , ( * h ) [ j ] = ( * h ) [ j ] , ( * h ) [ i ] }
func ( h * postingsHeap ) Push ( x interface { } ) {
* h = append ( * h , x . ( Postings ) )
}
func ( h * postingsHeap ) Pop ( ) interface { } {
old := * h
n := len ( old )
x := old [ n - 1 ]
* h = old [ 0 : n - 1 ]
return x
}
type mergedPostings struct {
type mergedPostings struct {
h postingsHeap
p [ ] Postings
initialized bool
h * loser . Tree [ storage . SeriesRef , Postings ]
cur storage . SeriesRef
cur storage . SeriesRef
err error
}
}
func newMergedPostings ( ctx context . Context , p [ ] Postings ) ( m * mergedPostings , nonEmpty bool ) {
func newMergedPostings ( p [ ] Postings ) ( m * mergedPostings , nonEmpty bool ) {
ph := make ( postingsHeap , 0 , len ( p ) )
const maxVal = storage . SeriesRef ( math . MaxUint64 ) // This value must be higher than all real values used in the tree.
lt := loser . New ( p , maxVal )
for _ , it := range p {
return & mergedPostings { p : p , h : lt } , true
// NOTE: mergedPostings struct requires the user to issue an initial Next.
switch {
case ctx . Err ( ) != nil :
return & mergedPostings { err : ctx . Err ( ) } , true
case it . Next ( ) :
ph = append ( ph , it )
case it . Err ( ) != nil :
return & mergedPostings { err : it . Err ( ) } , true
}
}
if len ( ph ) == 0 {
return nil , false
}
return & mergedPostings { h : ph } , true
}
}
func ( it * mergedPostings ) Next ( ) bool {
func ( it * mergedPostings ) Next ( ) bool {
if it . h . Len ( ) == 0 || it . err != nil {
return false
}
// The user must issue an initial Next.
if ! it . initialized {
heap . Init ( & it . h )
it . cur = it . h [ 0 ] . At ( )
it . initialized = true
return true
}
for {
for {
cur := it . h [ 0 ]
if ! it . h . Next ( ) {
if ! cur . Next ( ) {
heap . Pop ( & it . h )
if cur . Err ( ) != nil {
it . err = cur . Err ( )
return false
}
if it . h . Len ( ) == 0 {
return false
return false
}
}
} else {
// Remove duplicate entries.
// Value of top of heap has changed, re-heapify.
newItem := it . h . At ( )
heap . Fix ( & it . h , 0 )
if newItem != it . cur {
}
it . cur = newItem
if it . h [ 0 ] . At ( ) != it . cur {
it . cur = it . h [ 0 ] . At ( )
return true
return true
}
}
}
}
}
}
func ( it * mergedPostings ) Seek ( id storage . SeriesRef ) bool {
func ( it * mergedPostings ) Seek ( id storage . SeriesRef ) bool {
if it . h . Len ( ) == 0 || it . err != nil {
for ! it . h . IsEmpty ( ) && it . h . At ( ) < id {
return false
finished := ! it . h . Winner ( ) . Seek ( id )
it . h . Fix ( finished )
}
}
if ! it . initialized {
if it . h . IsEmpty ( ) {
if ! it . Next ( ) {
return false
return false
}
}
}
it . cur = it . h . At ( )
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 ( )
}
return true
return true
}
}
@ -657,7 +585,12 @@ func (it mergedPostings) At() storage.SeriesRef {
}
}
func ( it mergedPostings ) Err ( ) error {
func ( it mergedPostings ) Err ( ) error {
return it . err
for _ , p := range it . p {
if err := p . Err ( ) ; err != nil {
return err
}
}
return nil
}
}
// Without returns a new postings list that contains all elements from the full list that
// Without returns a new postings list that contains all elements from the full list that