github.com/pachyderm/pachyderm@v1.13.4/src/server/pkg/storage/fileset/priority_queue.go (about)

     1  package fileset
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/pachyderm/pachyderm/src/client/pkg/errors"
     7  )
     8  
     9  // TODO: Change the code that depends on this to use the stream package priority queue.
    10  type stream interface {
    11  	next() error
    12  	key() string
    13  	streamPriority() int
    14  }
    15  
    16  type priorityQueue struct {
    17  	queue []stream
    18  	size  int
    19  	ss    []stream
    20  }
    21  
    22  func newPriorityQueue(ss []stream) *priorityQueue {
    23  	return &priorityQueue{
    24  		queue: make([]stream, len(ss)+1),
    25  		ss:    ss,
    26  	}
    27  }
    28  
    29  func (pq *priorityQueue) iterate(f func([]stream, ...string) error) error {
    30  	for {
    31  		ss, err := pq.next()
    32  		if err != nil {
    33  			if errors.Is(err, io.EOF) {
    34  				return nil
    35  			}
    36  			return err
    37  		}
    38  		if err := f(ss, pq.peek()...); err != nil {
    39  			return err
    40  		}
    41  	}
    42  }
    43  
    44  func (pq *priorityQueue) isHigherPriority(i, j int) bool {
    45  	si := pq.queue[i]
    46  	sj := pq.queue[j]
    47  	return si.key() < sj.key() || (si.key() == sj.key() && si.streamPriority() > sj.streamPriority())
    48  }
    49  
    50  func (pq *priorityQueue) empty() bool {
    51  	return len(pq.queue) == 1 || pq.queue[1] == nil
    52  }
    53  
    54  func (pq *priorityQueue) insert(s stream) error {
    55  	// Get next in stream and insert it.
    56  	if err := s.next(); err != nil {
    57  		if errors.Is(err, io.EOF) {
    58  			return nil
    59  		}
    60  		return err
    61  	}
    62  	pq.queue[pq.size+1] = s
    63  	pq.size++
    64  	// Propagate insert up the queue
    65  	i := pq.size
    66  	for i > 1 {
    67  		if pq.isHigherPriority(i/2, i) {
    68  			break
    69  		}
    70  		pq.swap(i/2, i)
    71  		i /= 2
    72  	}
    73  	return nil
    74  }
    75  
    76  func (pq *priorityQueue) next() ([]stream, error) {
    77  	// Re-insert streams
    78  	if pq.ss != nil {
    79  		for _, s := range pq.ss {
    80  			if err := pq.insert(s); err != nil {
    81  				return nil, err
    82  			}
    83  		}
    84  	}
    85  	if pq.empty() {
    86  		return nil, io.EOF
    87  	}
    88  	ss := []stream{pq.queue[1]}
    89  	pq.fill()
    90  	// Keep popping streams off the queue if they have the same key.
    91  	for pq.queue[1] != nil && pq.queue[1].key() == ss[0].key() {
    92  		ss = append(ss, pq.queue[1])
    93  		pq.fill()
    94  	}
    95  	pq.ss = ss
    96  	return ss, nil
    97  }
    98  
    99  func (pq *priorityQueue) peek() []string {
   100  	if pq.empty() {
   101  		return nil
   102  	}
   103  	return []string{pq.queue[1].key()}
   104  }
   105  
   106  func (pq *priorityQueue) fill() {
   107  	// Replace first stream with last
   108  	pq.queue[1] = pq.queue[pq.size]
   109  	pq.queue[pq.size] = nil
   110  	pq.size--
   111  	// Propagate last stream down the queue
   112  	i := 1
   113  	var next int
   114  	for {
   115  		left, right := i*2, i*2+1
   116  		if left > pq.size {
   117  			break
   118  		} else if right > pq.size || pq.isHigherPriority(left, right) {
   119  			next = left
   120  		} else {
   121  			next = right
   122  		}
   123  		if pq.isHigherPriority(i, next) {
   124  			break
   125  		}
   126  		pq.swap(i, next)
   127  		i = next
   128  	}
   129  }
   130  
   131  func (pq *priorityQueue) swap(i, j int) {
   132  	pq.queue[i], pq.queue[j] = pq.queue[j], pq.queue[i]
   133  }