Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

client/network-gossip: Integrate GossipEngine tasks into Future impl #4767

Merged
merged 2 commits into from
Feb 12, 2020

Conversation

mxinden
Copy link
Contributor

@mxinden mxinden commented Jan 29, 2020

GossipEngine spawns two tasks, one for a periodic tick, one to forward
messages from the network to subscribers. These tasks hold an Arc to a
GossipEngineInner.

To reduce the amount of shared ownership (locking) this patch integrates
the two tasks into a Future implementation on the GossipEngine
struct. This Future implementation can now be called from a single
owner, e.g. the finality-grandpa NetworkBridge.

As a side effect this removes the requirement on the network-gossip
crate to spawn tasks and thereby removes the requirement on the
finality-grandpa crate to spawn any tasks.

This is part of a greater effort to reduce the number of owners of
components within finality-grandpa, network and network-gossip as
well as to reduce the amount of unbounded channels. For details see
d4fbb89, f0c1852 and 5afc777.

Once this simplification lands we can get rid of the construct of a
GossipEngine holding an Arc<Mutex<GossipEngineInner>>,
given that GossipEngine only has a single owner.

`GossipEngine` spawns two tasks, one for a periodic tick, one to forward
messages from the network to subscribers. These tasks hold an `Arc` to a
`GossipEngineInner`.

To reduce the amount of shared ownership (locking) this patch integrates
the two tasks into a `Future` implementation on the `GossipEngine`
struct. This `Future` implementation can now be called from a single
owner, e.g. the `finality-grandpa` `NetworkBridge`.

As a side effect this removes the requirement on the `network-gossip`
crate to spawn tasks and thereby removes the requirement on the
`finality-grandpa` crate to spawn any tasks.

This is part of a greater effort to reduce the number of owners of
components within `finality-grandpa`, `network` and `network-gossip` as
well as to reduce the amount of unbounded channels. For details see
d4fbb89, f0c1852 and 5afc777.
@mxinden mxinden requested a review from Demi-Marie as a code owner January 29, 2020 14:37
@mxinden mxinden added the A0-please_review Pull request needs code review. label Jan 29, 2020
@@ -160,7 +160,6 @@ pub fn new_full<C: Send + Default + 'static>(config: Configuration<C, GenesisCon
grandpa_link,
service.network(),
service.on_exit(),
service.spawn_task_handle(),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

None of finality-grandpa nor network-gossip need an executor to spawn tasks after this patch. Thus the logic passing said executor to those crates is removed in bin/node, bin/node-template, client/service and a lot of tests.

@@ -444,6 +442,12 @@ impl<B: BlockT, N: Network<B>> Future for NetworkBridge<B, N> {
}
}

match self.gossip_engine.poll_unpin(cx) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The GossipEngine needs to be polled by the NetworkBridge.

cx.waker().wake_by_ref();
}
}

Poll::Pending
Future::poll(Pin::new(&mut self.network), cx)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Bug originally fixed in #4766.

@@ -36,101 +37,42 @@ pub struct GossipEngine<B: BlockT> {
struct GossipEngineInner<B: BlockT> {
state_machine: ConsensusGossip<B>,
network: Box<dyn Network<B> + Send>,
periodic_maintenance_interval: futures_timer::Delay,
network_event_stream: Compat01As03<Box<dyn Stream01<Error = (), Item = Event> + Send>>,
engine_id: ConsensusEngineId,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Once this lands there is no need for GossipEngineInner anymore, thus the engine_id does not need to be duplicated either.

}));

let gossip_engine = GossipEngine {
inner: inner.clone(),
engine_id,
};

let res = executor.spawn({
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are the two tasks previously being spawned. You can find the new Future implementation further below.

fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = &mut *self;

while let Poll::Ready(Some(Ok(event))) = this.network_event_stream.poll_next_unpin(cx) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is copy and pasted from the previously spawned logic. In the long run I think we should at least log errors on this channel.

@mxinden
Copy link
Contributor Author

mxinden commented Jan 29, 2020

🛑 I have not yet created the corresponding Polkadot pull-request. But in the meantime I think this is worth taking a look. 🛑

(Polkadot will also need to poll the GossipEngine from now on.)

@mxinden mxinden added the B0-silent Changes should not be mentioned in any release notes label Feb 3, 2020
@tomaka
Copy link
Contributor

tomaka commented Feb 4, 2020

Sorry for the delay.
What about adding a GossipEngineInner::next_event() async function instead of manually implementing Future?

Something like:

impl<B: BlockT> Future for GossipEngine<B> {
	type Output = ();

	fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
		let inner = self.inner.lock();
		let fut = inner.run();
		futures::pin_mut!(fut);
		fut.poll(cx)
	}
}

impl<B: BlockT> GossipEngineInner<B> {
    async fn run(&mut self) { ... }
}

The async function should then however not use any local variable and only operate on the fields of self.

Copy link
Contributor

@andresilva andresilva left a comment

Choose a reason for hiding this comment

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

changes lgtm, needs a merge with master. I also like what @tomaka proposed.

mxinden added a commit to mxinden/polkadot that referenced this pull request Feb 11, 2020
With paritytech/substrate#4767 a `GossipEngine`
does not spawn its own tasks, but relies on its owner to poll it. This
patch removes the unneeded executor argument and spawns the gossip
engine as an orphaned task onto the executor instead.
mxinden added a commit to mxinden/polkadot that referenced this pull request Feb 11, 2020
With paritytech/substrate#4767 a `GossipEngine`
does not spawn its own tasks, but relies on its owner to poll it. This
patch removes the unneeded executor argument and spawns the gossip
engine as an orphaned task onto the executor instead.
@mxinden
Copy link
Contributor Author

mxinden commented Feb 11, 2020

I talked with @tomaka in regards to the suggestion above:

Using an async function without local variables would on the one hand

  • Reduce boiler plate code (impl Future for [...])
  • Not involve any pinning

on the other hand it would make the following two constraints previously enforced by the compiler only enforced by code comments.

  • Not being allowed to use local variables within the async function.
  • Not being allowed to depend on the fact that the generated Generator continues where it last stopped.

I would prefer to stick with the poll function style.

@gavofyork gavofyork merged commit e1668c2 into paritytech:master Feb 12, 2020
bkchr pushed a commit to paritytech/polkadot that referenced this pull request Feb 15, 2020
With paritytech/substrate#4767 a `GossipEngine`
does not spawn its own tasks, but relies on its owner to poll it. This
patch removes the unneeded executor argument and spawns the gossip
engine as an orphaned task onto the executor instead.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A0-please_review Pull request needs code review. B0-silent Changes should not be mentioned in any release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants