Skip to content
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

network/p2p/gossip: refactor Set.Add to accept multiple elements #2986

Closed
wants to merge 7 commits into from

Conversation

lebdron
Copy link
Contributor

@lebdron lebdron commented May 3, 2024

Allows potential optimized implementations for adding multiple elements to sets of Gossipables.

Why this should be merged

Coreth currently has to pass every received transaction to the mempool in a separate Add call, requiring exclusive mutex acquire and release on every call.

https://github.com/ava-labs/coreth/blob/8d22112c7033658eb83b64e8b31d2f9c69676e28/plugin/evm/gossip.go#L192-L194

https://github.com/ava-labs/coreth/blob/8d22112c7033658eb83b64e8b31d2f9c69676e28/core/txpool/legacypool/legacypool.go#L1108-L1110

This interface will allow an optimized implementation to avoid individual Add calls for Coreth.

How this works

How this was tested

@@ -29,3 +29,20 @@ type Set[T Gossipable] interface {
// corresponding salt.
GetFilter() (bloom []byte, salt []byte)
}

type AddManySet[T Gossipable] interface {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this would increase the scope of this change (especially because changing interfaces that are depended on by Coreth creates annoy circular dependencies)... But should we just be updating the Set interface to require this rather than adding this optional interface?

It seems like the X-chain and the P-chain could also try and avoid grabbing their locks multiple times.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, that was exactly my concern, trying to add this feature in a way without modifying the existing interface. But if it's OK, then I can just refactor Add to take a slice instead of a single element.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should probably push for just having one Add. Let me know if you have any questions on how to handle this weird circular import.

Copy link
Contributor

@joshua-kim joshua-kim May 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. Having an interface that has both Add and the AddMany signature is going to be an awkward API IMO. I would recommend an function signature that uses a variadic parameter like so on the Set interface.

Add(gossipables ...Gossipable) []error

Allows potential optimized implementations for adding multiple elements to sets of Gossipables.
@lebdron lebdron changed the title network/p2p/gossip: add AddManySet interface network/p2p/gossip: refactor Set.Add to accept multiple elements May 4, 2024
Comment on lines 120 to 121
g.lock.Lock()
defer g.lock.Unlock()
Copy link
Contributor

@StephenButtolph StephenButtolph May 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is going to work as expected if multiple transactions are provided. The defer will be executed on function return - not when the loop iterates.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, overlooked that, thanks! Regarding X/P-Chain mempools, I'd rather put all the checks and tx verification inside the mempool not to acquire RLock for every lookup. Plus, GetDropReason acquires RW lock on mutex inside LRU cache, which would also be possible to rearrange if we do the verification inside Add. It's possible to pass txVerifier as a dependency to mempool I think.

reset, errs[i] = gossip.ResetBloomFilterIfNeeded(g.bloom, g.Mempool.Len()*bloomChurnMultiplier)
if errs[i] != nil {
hasErr = true
continue
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add tests for multiple txs - I think this can continue to the next iteration with the lock held.

Would it make sense to keep the single tx addition as a method so that we can keep using defer g.lock.Unlock()?

@joshua-kim
Copy link
Contributor

joshua-kim commented May 14, 2024

Do you happen to have any benchmarks/profile that indicate that this is giving us any measurable change in performance? I think unless there is some non-trivial benchmark that shows that this is an improvement we should close this because returning []error introduces unnecessary complexity in the upstream code (ref: diff upstream of p2p) + I think it's a somewhat non-idiomatic way of handling errors in Go.

@joshua-kim
Copy link
Contributor

Closing for the above reason, feel free to re-open.

@joshua-kim joshua-kim closed this May 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
networking This involves networking sdk This involves SDK tooling or frameworks
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

3 participants