github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/querier/queryrange/ordering.go (about)

     1  package queryrange
     2  
     3  import (
     4  	"sort"
     5  
     6  	"github.com/grafana/loki/pkg/logproto"
     7  )
     8  
     9  /*
    10  Utils for manipulating ordering
    11  */
    12  
    13  type entries []logproto.Entry
    14  
    15  func (m entries) start() int64 {
    16  	if len(m) == 0 {
    17  		return 0
    18  	}
    19  	return m[0].Timestamp.UnixNano()
    20  }
    21  
    22  type byDir struct {
    23  	markers   []entries
    24  	direction logproto.Direction
    25  	labels    string
    26  }
    27  
    28  func (a byDir) Len() int      { return len(a.markers) }
    29  func (a byDir) Swap(i, j int) { a.markers[i], a.markers[j] = a.markers[j], a.markers[i] }
    30  func (a byDir) Less(i, j int) bool {
    31  	x, y := a.markers[i].start(), a.markers[j].start()
    32  
    33  	if a.direction == logproto.BACKWARD {
    34  		return x > y
    35  	}
    36  	return y > x
    37  }
    38  func (a byDir) EntriesCount() (n int) {
    39  	for _, m := range a.markers {
    40  		n += len(m)
    41  	}
    42  	return n
    43  }
    44  
    45  func (a byDir) merge() []logproto.Entry {
    46  	result := make([]logproto.Entry, 0, a.EntriesCount())
    47  
    48  	sort.Sort(a)
    49  	for _, m := range a.markers {
    50  		result = append(result, m...)
    51  	}
    52  	return result
    53  }
    54  
    55  // priorityqueue is used for extracting a limited # of entries from a set of sorted streams
    56  type priorityqueue struct {
    57  	streams   []*logproto.Stream
    58  	direction logproto.Direction
    59  }
    60  
    61  func (pq *priorityqueue) Len() int { return len(pq.streams) }
    62  
    63  func (pq *priorityqueue) Less(i, j int) bool {
    64  	if pq.direction == logproto.FORWARD {
    65  		return pq.streams[i].Entries[0].Timestamp.UnixNano() < pq.streams[j].Entries[0].Timestamp.UnixNano()
    66  	}
    67  	return pq.streams[i].Entries[0].Timestamp.UnixNano() > pq.streams[j].Entries[0].Timestamp.UnixNano()
    68  
    69  }
    70  
    71  func (pq *priorityqueue) Swap(i, j int) {
    72  	pq.streams[i], pq.streams[j] = pq.streams[j], pq.streams[i]
    73  }
    74  
    75  func (pq *priorityqueue) Push(x interface{}) {
    76  	stream := x.(*logproto.Stream)
    77  	pq.streams = append(pq.streams, stream)
    78  }
    79  
    80  // Pop returns a stream with one entry. It pops the first entry of the first stream
    81  // then re-pushes the remainder of that stream if non-empty back into the queue
    82  func (pq *priorityqueue) Pop() interface{} {
    83  	n := pq.Len()
    84  	stream := pq.streams[n-1]
    85  	pq.streams[n-1] = nil // avoid memory leak
    86  	pq.streams = pq.streams[:n-1]
    87  
    88  	// put the rest of the stream back into the priorityqueue if more entries exist
    89  	if len(stream.Entries) > 1 {
    90  		remaining := *stream
    91  		remaining.Entries = remaining.Entries[1:]
    92  		pq.Push(&remaining)
    93  	}
    94  
    95  	stream.Entries = stream.Entries[:1]
    96  	return stream
    97  }