mirror of
https://github.com/tendermint/tendermint.git
synced 2026-02-04 02:52:07 +00:00
The primary effect of this change is to simplify the implementation of the priority mempool to eliminate an unbounded heap growth observed by Vega team when it was enabled in their testnet. It updates and fixes #8775. The main body of this change is to remove the auxiliary indexing structures, and use only the concurrent list structure (the same as the legacy mempool) to maintain both gossip order and priority. This means that operations that require priority information, such as block updates and insert-time evictions, require a linear scan over the mempool. This tradeoff greatly simplifies the code and eliminates the long-term heap load, at the cost of some extra CPU and short-lived working memory during CheckTx and Update calls. Rough benchmark results: - This PR: BenchmarkTxMempool_CheckTx-10 486373 2271 ns/op - Original priority mempool implementation: BenchmarkTxMempool_CheckTx-10 500302 2113 ns/op - Legacy (v0) mempool: BenchmarkCheckTx-10 364591 3571 ns/op These benchmarks are not a good proxy for production load, but at least suggest that the overhead of the implementation changes are not cause for concern. In addition: - Rework synchronization so that access to shared data structures is safe. Previously shared locks were used to exclude block updates during calls that update mempool state. Now access is properly exclusive where necessary. - Fix a bug in the recheck flow, where priority updates from the application were not correctly reflected in the index structures. - Eliminate the need for separate recheck cursors during block update. This avoids the need to explicitly invalidate elements of the concurrent list, which averts the dependency cycle that led to objects being pinned. - Clean up, clarify, and fix inaccuracies in documentation comments throughout the package. Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com>
88 lines
2.2 KiB
Go
88 lines
2.2 KiB
Go
package v1
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/tendermint/tendermint/types"
|
|
)
|
|
|
|
// WrappedTx defines a wrapper around a raw transaction with additional metadata
|
|
// that is used for indexing.
|
|
type WrappedTx struct {
|
|
tx types.Tx // the original transaction data
|
|
hash types.TxKey // the transaction hash
|
|
height int64 // height when this transaction was initially checked (for expiry)
|
|
timestamp time.Time // time when transaction was entered (for TTL)
|
|
|
|
mtx sync.Mutex
|
|
gasWanted int64 // app: gas required to execute this transaction
|
|
priority int64 // app: priority value for this transaction
|
|
sender string // app: assigned sender label
|
|
peers map[uint16]bool // peer IDs who have sent us this transaction
|
|
}
|
|
|
|
// Size reports the size of the raw transaction in bytes.
|
|
func (w *WrappedTx) Size() int64 { return int64(len(w.tx)) }
|
|
|
|
// SetPeer adds the specified peer ID as a sender of w.
|
|
func (w *WrappedTx) SetPeer(id uint16) {
|
|
w.mtx.Lock()
|
|
defer w.mtx.Unlock()
|
|
if w.peers == nil {
|
|
w.peers = map[uint16]bool{id: true}
|
|
} else {
|
|
w.peers[id] = true
|
|
}
|
|
}
|
|
|
|
// HasPeer reports whether the specified peer ID is a sender of w.
|
|
func (w *WrappedTx) HasPeer(id uint16) bool {
|
|
w.mtx.Lock()
|
|
defer w.mtx.Unlock()
|
|
_, ok := w.peers[id]
|
|
return ok
|
|
}
|
|
|
|
// SetGasWanted sets the application-assigned gas requirement of w.
|
|
func (w *WrappedTx) SetGasWanted(gas int64) {
|
|
w.mtx.Lock()
|
|
defer w.mtx.Unlock()
|
|
w.gasWanted = gas
|
|
}
|
|
|
|
// GasWanted reports the application-assigned gas requirement of w.
|
|
func (w *WrappedTx) GasWanted() int64 {
|
|
w.mtx.Lock()
|
|
defer w.mtx.Unlock()
|
|
return w.gasWanted
|
|
}
|
|
|
|
// SetSender sets the application-assigned sender of w.
|
|
func (w *WrappedTx) SetSender(sender string) {
|
|
w.mtx.Lock()
|
|
defer w.mtx.Unlock()
|
|
w.sender = sender
|
|
}
|
|
|
|
// Sender reports the application-assigned sender of w.
|
|
func (w *WrappedTx) Sender() string {
|
|
w.mtx.Lock()
|
|
defer w.mtx.Unlock()
|
|
return w.sender
|
|
}
|
|
|
|
// SetPriority sets the application-assigned priority of w.
|
|
func (w *WrappedTx) SetPriority(p int64) {
|
|
w.mtx.Lock()
|
|
defer w.mtx.Unlock()
|
|
w.priority = p
|
|
}
|
|
|
|
// Priority reports the application-assigned priority of w.
|
|
func (w *WrappedTx) Priority() int64 {
|
|
w.mtx.Lock()
|
|
defer w.mtx.Unlock()
|
|
return w.priority
|
|
}
|