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

eth: fix potential deadlock of pub/sub module #22132

Closed
wants to merge 1 commit into from

Conversation

unclezoro
Copy link

@unclezoro unclezoro commented Jan 7, 2021

Description

Fix the potential deadlock of pub/sub module which may cause the chain halt.

More detail in #22131

Rationale

The deadlock dependency is:

Routine A: NewPendingTransactionFilter want to lock filtersMu to consume hashes;
Routine B: eventLoop is waiting Routine A to consume hashes so that it can push new hash to channel.
Routine C: Unsubscribe is holding lock filtersMu, but it is waiting for Routine B to consume uninstall channel.

Changes

There is no need to fetch lock on NewPendingTransactionFilter routine, so just loose the logic.

And fix the potential risk that Unsubscribe routine does not drain all the hash, header and log.

@unclezoro unclezoro changed the title [R4R]fix potential deadlock of pub/sub module eth: fix potential deadlock of pub/sub module Jan 7, 2021
Copy link

@DGKSK8LIFE DGKSK8LIFE left a comment

Choose a reason for hiding this comment

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

Not sure about drainLoop. Seems like infinitely iterating will cause problems in the future; or rather, it's not the most elegant solution.

@rjl493456442
Copy link
Member

Thanks for your detail issue explanation and the fix!
However the fix is not complete, because some other filter APIs may also lock up the loop(e.g. NewBlockFilter). Please also fix them.

@@ -174,6 +174,17 @@ func (sub *Subscription) Unsubscribe() {
// this ensures that the manager won't use the event channel which
// will probably be closed by the client asap after this method returns.
<-sub.Err()

drainLoop:
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure it's needed. After the uninstall request gets processed, no more following events will be sent to this filter. All accumulated events will be consumed by the filter handler itself.

But anwway I agree it's ugly to prevent the deadlock in the Unsubscribe by such approach.

Copy link
Author

@unclezoro unclezoro Jan 7, 2021

Choose a reason for hiding this comment

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

The uninstall request is processed in eventLoop, while eventLoop maybe busy pushing hash into sub.f.hashes, however if sub.f.hashes have unread hash, then deadlock happens.

f.hashes = append(f.hashes, ph...)
}
api.filtersMu.Unlock()
f.hashes = append(f.hashes, ph...)
Copy link
Member

Choose a reason for hiding this comment

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

It may introduces some data race.

In the GetFilterChanges API will be reset the f.hashes to nil. So the lock is kind of necessary here.

Copy link
Author

Choose a reason for hiding this comment

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

You are right, I missed this.

Copy link
Author

@unclezoro unclezoro Jan 7, 2021

Choose a reason for hiding this comment

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

I suggest adding a fine-grained lock in filter rather than using a global lock. What do you think?

@fjl fjl self-assigned this Jan 7, 2021
@fjl
Copy link
Contributor

fjl commented Jan 19, 2021

@s1na made a better fix in this PR, and also added a test to reproduce #22178
Closing this in favor of #22178

@fjl fjl closed this Jan 19, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants