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 }