bitbucket.org/number571/tendermint@v0.8.14/internal/mempool/v1/priority_queue.go (about)

     1  package v1
     2  
     3  import (
     4  	"container/heap"
     5  	"sort"
     6  
     7  	tmsync "bitbucket.org/number571/tendermint/internal/libs/sync"
     8  )
     9  
    10  var _ heap.Interface = (*TxPriorityQueue)(nil)
    11  
    12  // TxPriorityQueue defines a thread-safe priority queue for valid transactions.
    13  type TxPriorityQueue struct {
    14  	mtx tmsync.RWMutex
    15  	txs []*WrappedTx
    16  }
    17  
    18  func NewTxPriorityQueue() *TxPriorityQueue {
    19  	pq := &TxPriorityQueue{
    20  		txs: make([]*WrappedTx, 0),
    21  	}
    22  
    23  	heap.Init(pq)
    24  
    25  	return pq
    26  }
    27  
    28  // GetEvictableTxs attempts to find and return a list of *WrappedTx than can be
    29  // evicted to make room for another *WrappedTx with higher priority. If no such
    30  // list of *WrappedTx exists, nil will be returned. The returned list of *WrappedTx
    31  // indicate that these transactions can be removed due to them being of lower
    32  // priority and that their total sum in size allows room for the incoming
    33  // transaction according to the mempool's configured limits.
    34  func (pq *TxPriorityQueue) GetEvictableTxs(priority, txSize, totalSize, cap int64) []*WrappedTx {
    35  	pq.mtx.RLock()
    36  	defer pq.mtx.RUnlock()
    37  
    38  	txs := make([]*WrappedTx, len(pq.txs))
    39  	copy(txs, pq.txs)
    40  
    41  	sort.Slice(txs, func(i, j int) bool {
    42  		return txs[i].priority < txs[j].priority
    43  	})
    44  
    45  	var (
    46  		toEvict []*WrappedTx
    47  		i       int
    48  	)
    49  
    50  	currSize := totalSize
    51  
    52  	// Loop over all transactions in ascending priority order evaluating those
    53  	// that are only of less priority than the provided argument. We continue
    54  	// evaluating transactions until there is sufficient capacity for the new
    55  	// transaction (size) as defined by txSize.
    56  	for i < len(txs) && txs[i].priority < priority {
    57  		toEvict = append(toEvict, txs[i])
    58  		currSize -= int64(txs[i].Size())
    59  
    60  		if currSize+txSize <= cap {
    61  			return toEvict
    62  		}
    63  
    64  		i++
    65  	}
    66  
    67  	return nil
    68  }
    69  
    70  // NumTxs returns the number of transactions in the priority queue. It is
    71  // thread safe.
    72  func (pq *TxPriorityQueue) NumTxs() int {
    73  	pq.mtx.RLock()
    74  	defer pq.mtx.RUnlock()
    75  
    76  	return len(pq.txs)
    77  }
    78  
    79  // RemoveTx removes a specific transaction from the priority queue.
    80  func (pq *TxPriorityQueue) RemoveTx(tx *WrappedTx) {
    81  	pq.mtx.Lock()
    82  	defer pq.mtx.Unlock()
    83  
    84  	if tx.heapIndex < len(pq.txs) {
    85  		heap.Remove(pq, tx.heapIndex)
    86  	}
    87  }
    88  
    89  // PushTx adds a valid transaction to the priority queue. It is thread safe.
    90  func (pq *TxPriorityQueue) PushTx(tx *WrappedTx) {
    91  	pq.mtx.Lock()
    92  	defer pq.mtx.Unlock()
    93  
    94  	heap.Push(pq, tx)
    95  }
    96  
    97  // PopTx removes the top priority transaction from the queue. It is thread safe.
    98  func (pq *TxPriorityQueue) PopTx() *WrappedTx {
    99  	pq.mtx.Lock()
   100  	defer pq.mtx.Unlock()
   101  
   102  	x := heap.Pop(pq)
   103  	if x != nil {
   104  		return x.(*WrappedTx)
   105  	}
   106  
   107  	return nil
   108  }
   109  
   110  // Push implements the Heap interface.
   111  //
   112  // NOTE: A caller should never call Push. Use PushTx instead.
   113  func (pq *TxPriorityQueue) Push(x interface{}) {
   114  	n := len(pq.txs)
   115  	item := x.(*WrappedTx)
   116  	item.heapIndex = n
   117  	pq.txs = append(pq.txs, item)
   118  }
   119  
   120  // Pop implements the Heap interface.
   121  //
   122  // NOTE: A caller should never call Pop. Use PopTx instead.
   123  func (pq *TxPriorityQueue) Pop() interface{} {
   124  	old := pq.txs
   125  	n := len(old)
   126  	item := old[n-1]
   127  	old[n-1] = nil      // avoid memory leak
   128  	item.heapIndex = -1 // for safety
   129  	pq.txs = old[0 : n-1]
   130  	return item
   131  }
   132  
   133  // Len implements the Heap interface.
   134  //
   135  // NOTE: A caller should never call Len. Use NumTxs instead.
   136  func (pq *TxPriorityQueue) Len() int {
   137  	return len(pq.txs)
   138  }
   139  
   140  // Less implements the Heap interface. It returns true if the transaction at
   141  // position i in the queue is of less priority than the transaction at position j.
   142  func (pq *TxPriorityQueue) Less(i, j int) bool {
   143  	// If there exists two transactions with the same priority, consider the one
   144  	// that we saw the earliest as the higher priority transaction.
   145  	if pq.txs[i].priority == pq.txs[j].priority {
   146  		return pq.txs[i].timestamp.Before(pq.txs[j].timestamp)
   147  	}
   148  
   149  	// We want Pop to give us the highest, not lowest, priority so we use greater
   150  	// than here.
   151  	return pq.txs[i].priority > pq.txs[j].priority
   152  }
   153  
   154  // Swap implements the Heap interface. It swaps two transactions in the queue.
   155  func (pq *TxPriorityQueue) Swap(i, j int) {
   156  	pq.txs[i], pq.txs[j] = pq.txs[j], pq.txs[i]
   157  	pq.txs[i].heapIndex = i
   158  	pq.txs[j].heapIndex = j
   159  }