-
Notifications
You must be signed in to change notification settings - Fork 548
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
Fix libp2p helper concurrent writes #14467
Conversation
Some remaining data races when running the node with
|
btw, here is a patch that adds some wrapper methods for accessing/modifying shared data structures, so far with this extra changes I am not getting any race conditions. Solution is not ideal because it would be better to not have to use so many mutexes and instead have a single thread handling the state, but that would require a bigger change (EDIT: PR targetting this branch here) |
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.
Nits
src/app/libp2p_helper/src/codanet.go
Outdated
prevOnConnect(net, c) | ||
f(net, c) | ||
} | ||
cm.onConnectMutex.Unlock() |
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.
Use defer
idiom
src/app/libp2p_helper/src/codanet.go
Outdated
prevOnDisconnect(net, c) | ||
f(net, c) | ||
} | ||
cm.onDisconnectMutex.Unlock() |
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.
Use defer
idiom
src/app/libp2p_helper/src/codanet.go
Outdated
h.gatingState.TrustedAddrFilters = ma.NewFilters() | ||
h.gatingState.trustedAddrFiltersMutex.Lock() | ||
h.gatingState.trustedAddrFilters = ma.NewFilters() | ||
h.gatingState.trustedAddrFiltersMutex.Unlock() |
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.
Use defer
idiom
src/app/libp2p_helper/src/codanet.go
Outdated
cm.OnConnect(net, c) | ||
cm.onConnectMutex.Lock() | ||
cm.onConnect(net, c) | ||
cm.onConnectMutex.Unlock() |
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.
Use defer
idiom
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.
Use RLock
src/app/libp2p_helper/src/codanet.go
Outdated
cm.OnDisconnect(net, c) | ||
cm.onDisconnectMutex.Lock() | ||
cm.onDisconnect(net, c) | ||
cm.onDisconnectMutex.Unlock() |
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.
Use defer
idiom
src/app/libp2p_helper/src/codanet.go
Outdated
func (gs *CodaGatingState) TrustPeer(p peer.ID) { | ||
gs.trustedPeersMutex.Lock() | ||
gs.trustedPeers[p] = struct{}{} | ||
gs.trustedPeersMutex.Unlock() |
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.
Use defer
idiom
src/app/libp2p_helper/src/codanet.go
Outdated
_, isTrusted := gs.TrustedPeers[p] | ||
gs.trustedPeersMutex.Lock() | ||
_, isTrusted := gs.trustedPeers[p] | ||
gs.trustedPeersMutex.Unlock() |
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.
Use defer
idiom
src/app/libp2p_helper/src/codanet.go
Outdated
_, isBanned := gs.BannedPeers[p] | ||
gs.bannedPeersMutex.Lock() | ||
_, isBanned := gs.bannedPeers[p] | ||
gs.bannedPeersMutex.Unlock() |
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.
Use defer
idiom
gs.TrustedPeers[testInfo.ID] = struct{}{} | ||
gs.trustedPeersMutex.Lock() | ||
gs.trustedPeers[testInfo.ID] = struct{}{} | ||
gs.trustedPeersMutex.Unlock() |
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.
Use defer
idiom
handleStreamReads(appB, stream, streamIdx) | ||
streamIdx++ | ||
streamMutex.Unlock() |
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.
move handleStreamReads
out
e64d3d5
to
5ec0334
Compare
Problem: RPC protocol requires response to stream open RPC to arrive before any message from the stream. This was implemented with use of an ugly hack. Solution: remove hack, introduce notion of after-write handler in to be executed after the rpc response is written to output.
Problem: writing to a stream pauses all other stream writes. This might be troublesome e.g. in case of a peer disconnecting: until connection timeout is not propagated, we may get stuck trying to send it bytes, while writing to streams of other peers is blocked. Solution: use fine-grained locking on stream level. P.S. previous commit introduces a potential concurrency issue in stream reset/write not being synchronized. This commit fixes this issue.
!ci-build-me |
!ci-build-me |
1 similar comment
!ci-build-me |
827ecf2
to
7543edf
Compare
7543edf
to
8548686
Compare
!ci-build-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.
LGTM!
ValidatorMutex: &sync.Mutex{}, | ||
Validators: make(map[uint64]*validationStatus), | ||
Streams: make(map[uint64]net.Stream), | ||
_subs: make(map[uint64]subscription), |
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.
Why the underscore prefixes? We don't do this in other parts of the code.
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 is @tizoc's decision, I guess to visually discourage usage of these fields.
We may roll back the prefixes, I agree they look a bit alien to the rest of the codebase.
Though I liked the idea of making use of these fields visually uncomfortable, so thought why not
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.
I guess to visually discourage usage of these fields.
That was exactly it. I am not terribly familiar with Go, so I guess that naming convention is not idiomatic at all. From what I found, the proper way would be to separate this into a separate package to make those fields truly private.
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.
👍 on moving to a different package later
!approved-for-mainnet |
This PR:
Fixes race conditions mentioned on #14345