-
Notifications
You must be signed in to change notification settings - Fork 21.4k
core/txpool: change lock in Pending method of legacy pool to read lock #32924
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
will-2012
commented
Oct 17, 2025
#31523. I tried this before, but it seems to have some issues. FYI.
will-2012
commented
Oct 17, 2025
#31523. I tried this before, but it seems to have some issues. FYI.
SortedMap seems to have complex concurrent semantics. It seems that it is dangerous in concurrent situations.
Pls check and pay more attenttion :D.
@will-2012 Thanks for pointing it out, you are right.
func TestSortedMapConcurrency(t *testing.T) { m := NewSortedMap() // Generate a list of transactions to insert key, _ := crypto.GenerateKey() txs := make(types.Transactions, 1000) for i := 0; i < len(txs); i++ { txs[i] = transaction(uint64(i), 0, key) } for i := 0; i < len(txs)/2; i++ { m.Put(txs[i]) } var wg sync.WaitGroup wg.Add(8) for i := 0; i < 8; i++ { go func() { defer wg.Done() m.Flatten() }() } wg.Add(1) go func() { defer wg.Done() for i := len(txs) / 2; i < len(txs); i++ { m.Put(txs[i]) } }() wg.Add(1) go func() { defer wg.Done() for i := 0; i < len(txs)/2; i++ { m.Forward(uint64(i)) } }() wg.Wait() }
I can reproduce the concurrent map read/write panic with this script.
@will-2012 Thanks for pointing it out, you are right.
func TestSortedMapConcurrency(t *testing.T) { m := NewSortedMap() // Generate a list of transactions to insert key, _ := crypto.GenerateKey() txs := make(types.Transactions, 1000) for i := 0; i < len(txs); i++ { txs[i] = transaction(uint64(i), 0, key) } for i := 0; i < len(txs)/2; i++ { m.Put(txs[i]) } var wg sync.WaitGroup wg.Add(8) for i := 0; i < 8; i++ { go func() { defer wg.Done() m.Flatten() }() } wg.Add(1) go func() { defer wg.Done() for i := len(txs) / 2; i < len(txs); i++ { m.Put(txs[i]) } }() wg.Add(1) go func() { defer wg.Done() for i := 0; i < len(txs)/2; i++ { m.Forward(uint64(i)) } }() wg.Wait() }I can reproduce the concurrent map read/write panic with this script.
Cool. I see.
I checked the code — both Content and Pending can safely use RLock.
The Put and Forward methods of SortedMap are already protected by Lock in their actual usage scenarios,
and Flatten is also guarded by RLock.
Therefore, the test case mentioned in the reply wouldn’t occur in practice.
will-2012
commented
Oct 17, 2025
I checked the code — both Content and Pending can safely use RLock. The Put and Forward methods of SortedMap are already protected by Lock in their actual usage scenarios, and Flatten is also guarded by RLock. Therefore, the test case mentioned in the reply wouldn’t occur in practice.
Got it, SortedMap is not thread-safe, and the upper caller is responsible for concurrent access.
This PR makes a small update to the
Pending()method in the legacy pool. By changing the lock from exclusive to read-only, it aims to improve concurrency performance.