-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
take pruning logic out of create_transaction logic #11845
Conversation
I see that you haven't updated any README files. Would it make sense to do so? |
Is it important that we always call |
yes, since we want to make sure that adding unstarted transactions to the unstarted transaction queue also keeps the queue a manageable size
The biggest reason is due to the in-memory work. The original The other reason to remove the prune step from the evm txstore create transaction method is since this prune step shouldnt be chain specific for |
Co-authored-by: amit-momin <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall this looks good, but I am confused about the queueSize math here.
common/txmgr/strategies.go
Outdated
var cancel context.CancelFunc | ||
ctx, cancel = context.WithTimeout(ctx, s.queryTimeout) | ||
defer cancel() | ||
|
||
n, err = pruneService.PruneUnstartedTxQueue(ctx, s.queueSize, s.subject) | ||
// NOTE: We prune one less than the queue size because we will be adding a new transaction to the queue right after this PruneQueue call |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comments helps! But I'm not yet sure why we can't just use the queueSize. The prune is occurring before the create call right? This means that the new transaction isn't in the queue yet, so it should be safe to use s.queueSize as opposed to queueSize - 1 right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The concern that prashant brought up was that if we didnt do a -1 we could end up with a queue size +1 above the max queue size. Here is an example
- Queue is full at 500 txns
- PruneQueue is run... it sees 500txns which matches the max so it moves on without pruning
- CreateTransaction puts a new txn in the queue making the new queue size 501 which is technically above the max limit of 500
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it would be only off by 1 if we chose to stick with queueSize, but let me know if i am not fully understanding your idea
@@ -682,3 +682,36 @@ func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Fin | |||
func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) CountTransactionsByState(ctx context.Context, state txmgrtypes.TxState) (count uint32, err error) { | |||
return count, errors.New(n.ErrMsg) | |||
} | |||
|
|||
func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) pruneQueueAndCreateTxn( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It occurred to me during our call that both PruneQueue and createTransaction touch the queue, but there's no locking on this function. As a result, its possible there could be a race condition that occurs when multiple pruneQueueAndCreateTxn calls are done at the same time. For example, if thread A calls pruneQueue and then gets pre-empted, then thread B could run pruneQueueAndCreate putting the queueSize to the max queue size, and then when thread A finishes, it could then call createTransaction when the queueSize is at maximum, thereby allowing the queue to grow beyond the max queue size.
My question here is: do we need a lock to guard the interactions with the queue within this function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that's a good point!
We do have a constraint in our other loops where only 1 thread is operating for each fromAddress. Thus no thread safety issues.
However the CreateTransaction method is called by the client, and can be called concurrently.
So the situation you described can potentially happen.
Note that the only harm in this case would be that our queue will momentarily grow to a larger size. As soon as there's yet another call from client, that prune will again cut down the queue size to right values.
So this isn't a big problem, except that theoretically we could have a larger queue.
I won't mind adding a new lock to prevent this situation, but even if we don't, it won't break/affect anything, according to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great catch patrick. Added the Lock
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Thanks for the changes
SonarQube Quality Gate |
This PR removes the pruning logic from the createTransaction logic
PruneQueue
andPruneUnstartedTxQueue
to returnids []int64, err error
instead ofn int64, err error
This change helps the in-memory work move forward #11625