@@ -20,6 +20,7 @@ import (
20
20
"container/heap"
21
21
"math"
22
22
"math/big"
23
+ "slices"
23
24
"sort"
24
25
"sync"
25
26
"sync/atomic"
@@ -49,16 +50,18 @@ func (h *nonceHeap) Pop() interface{} {
49
50
old := * h
50
51
n := len (old )
51
52
x := old [n - 1 ]
53
+ old [n - 1 ] = 0
52
54
* h = old [0 : n - 1 ]
53
55
return x
54
56
}
55
57
56
58
// txSortedMap is a nonce->transaction hash map with a heap based index to allow
57
59
// iterating over the contents in a nonce-incrementing way.
58
60
type txSortedMap struct {
59
- items map [uint64 ]* types.Transaction // Hash map storing the transaction data
60
- index * nonceHeap // Heap of nonces of all the stored transactions (non-strict mode)
61
- cache types.Transactions // Cache of the transactions already sorted
61
+ items map [uint64 ]* types.Transaction // Hash map storing the transaction data
62
+ index * nonceHeap // Heap of nonces of all the stored transactions (non-strict mode)
63
+ cache types.Transactions // Cache of the transactions already sorted
64
+ cacheMu sync.Mutex // Mutex covering the cache
62
65
}
63
66
64
67
// newTxSortedMap creates a new nonce-sorted transaction map.
@@ -81,7 +84,9 @@ func (m *txSortedMap) Put(tx *types.Transaction) {
81
84
if m .items [nonce ] == nil {
82
85
heap .Push (m .index , nonce )
83
86
}
87
+ m .cacheMu .Lock ()
84
88
m .items [nonce ], m .cache = tx , nil
89
+ m .cacheMu .Unlock ()
85
90
}
86
91
87
92
// Forward removes all transactions from the map with a nonce lower than the
@@ -97,9 +102,11 @@ func (m *txSortedMap) Forward(threshold uint64) types.Transactions {
97
102
delete (m .items , nonce )
98
103
}
99
104
// If we had a cached order, shift the front
105
+ m .cacheMu .Lock ()
100
106
if m .cache != nil {
101
107
m .cache = m .cache [len (removed ):]
102
108
}
109
+ m .cacheMu .Unlock ()
103
110
return removed
104
111
}
105
112
@@ -123,7 +130,9 @@ func (m *txSortedMap) reheap() {
123
130
* m .index = append (* m .index , nonce )
124
131
}
125
132
heap .Init (m .index )
133
+ m .cacheMu .Lock ()
126
134
m .cache = nil
135
+ m .cacheMu .Unlock ()
127
136
}
128
137
129
138
// filter is identical to Filter, but **does not** regenerate the heap. This method
@@ -139,7 +148,9 @@ func (m *txSortedMap) filter(filter func(*types.Transaction) bool) types.Transac
139
148
}
140
149
}
141
150
if len (removed ) > 0 {
151
+ m .cacheMu .Lock ()
142
152
m .cache = nil
153
+ m .cacheMu .Unlock ()
143
154
}
144
155
return removed
145
156
}
@@ -153,19 +164,21 @@ func (m *txSortedMap) Cap(threshold int) types.Transactions {
153
164
}
154
165
// Otherwise gather and drop the highest nonce'd transactions
155
166
var drops types.Transactions
156
-
157
- sort .Sort (* m .index )
167
+ slices .Sort (* m .index )
158
168
for size := len (m .items ); size > threshold ; size -- {
159
169
drops = append (drops , m .items [(* m .index )[size - 1 ]])
160
170
delete (m .items , (* m .index )[size - 1 ])
161
171
}
162
172
* m .index = (* m .index )[:threshold ]
163
- heap .Init (m .index )
173
+ // The sorted m.index slice is still a valid heap, so there is no need to
174
+ // reheap after deleting tail items.
164
175
165
176
// If we had a cache, shift the back
177
+ m .cacheMu .Lock ()
166
178
if m .cache != nil {
167
179
m .cache = m .cache [:len (m .cache )- len (drops )]
168
180
}
181
+ m .cacheMu .Unlock ()
169
182
return drops
170
183
}
171
184
@@ -185,7 +198,9 @@ func (m *txSortedMap) Remove(nonce uint64) bool {
185
198
}
186
199
}
187
200
delete (m .items , nonce )
201
+ m .cacheMu .Lock ()
188
202
m .cache = nil
203
+ m .cacheMu .Unlock ()
189
204
190
205
return true
191
206
}
@@ -195,7 +210,7 @@ func (m *txSortedMap) Remove(nonce uint64) bool {
195
210
// removed from the list.
196
211
//
197
212
// Note, all transactions with nonces lower than start will also be returned to
198
- // prevent getting into and invalid state. This is not something that should ever
213
+ // prevent getting into an invalid state. This is not something that should ever
199
214
// happen but better to be self correcting than failing!
200
215
func (m * txSortedMap ) Ready (start uint64 ) types.Transactions {
201
216
// Short circuit if no transactions are available
@@ -209,7 +224,9 @@ func (m *txSortedMap) Ready(start uint64) types.Transactions {
209
224
delete (m .items , next )
210
225
heap .Pop (m .index )
211
226
}
227
+ m .cacheMu .Lock ()
212
228
m .cache = nil
229
+ m .cacheMu .Unlock ()
213
230
214
231
return ready
215
232
}
@@ -220,6 +237,8 @@ func (m *txSortedMap) Len() int {
220
237
}
221
238
222
239
func (m * txSortedMap ) flatten () types.Transactions {
240
+ m .cacheMu .Lock ()
241
+ defer m .cacheMu .Unlock ()
223
242
// If the sorting was not cached yet, create and cache it
224
243
if m .cache == nil {
225
244
m .cache = make (types.Transactions , 0 , len (m .items ))
@@ -604,6 +623,7 @@ func (l *txPricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool
604
623
605
624
// Discard finds a number of most underpriced transactions, removes them from the
606
625
// priced list and returns them for further removal from the entire pool.
626
+ // If noPending is set to true, we will only consider the floating list
607
627
//
608
628
// Note local transaction won't be considered for eviction.
609
629
func (l * txPricedList ) Discard (slots int , force bool ) (types.Transactions , bool ) {
0 commit comments