Replace unbounded channels with bounded ones. (#1191)

* Replace unbounded channels with bounded ones.

To remove the unbounded channels used for communicating with node tasks
an API similar to `futures::Sink` is used, i.e. sending is split into a
start and complete phase. The start phase returns `StartSend` and first
attempts to complete any pending send operations. Completing the send
means polling until `Poll::Ready(())` is returned.

In addition this PR has split the `handled_node_tasks` module into
several smaller ones (cf. `nodes::tasks`) and renamed some types:

- `nodes::handled_node_tasks::NodeTask` -> `nodes::tasks::task::Task`
- `nodes::handled_node_tasks::NodeTaskInner` -> `nodes::tasks::task::State`
- `nodes::handled_node_tasks::NodeTasks` -> `nodes::tasks::Manager`
- `nodes::handled_node_tasks::TaskClosedEvent` -> `nodes::tasks::Error`
- `nodes::handled_node_tasks::HandledNodesEvent` -> `nodes::tasks::Event`
- `nodes::handled_node_tasks::Task` -> `nodes::tasks::TaskEntry`
- `nodes::handled_node_tasks::ExtToInMessage` -> `nodes::tasks::task::ToTaskMessage`
- `nodes::handled_node_tasks::InToExtMessage` -> `nodes::tasks::task::FromTaskMessage`

* `take_over_to_complete` can be an `Option`.

Since it is always holding just a single pending message.

* `send_event_to_complete` can be an `Option`.

* Update core/src/nodes/tasks/manager.rs

Co-Authored-By: Pierre Krieger <pierre.krieger1708@gmail.com>

* Update core/src/nodes/tasks/manager.rs

Co-Authored-By: Pierre Krieger <pierre.krieger1708@gmail.com>

* Add comments to explain the need to flush sends ...

of take-over and event messages delivered over Sinks.
This commit is contained in:
Toralf Wittner
2019-07-09 16:47:24 +02:00
committed by Pierre Krieger
parent a0d278a479
commit 6aba7961d1
14 changed files with 1287 additions and 806 deletions

View File

@ -154,20 +154,40 @@ fn events_in_a_node_reaches_the_collection_stream() {
Ok(Async::Ready(()))
})).expect("tokio works");
let cs2 = cs.clone();
rt.block_on(future::poll_fn(move || {
if cs2.lock().start_broadcast(&InEvent::NextState).is_not_ready() {
Ok::<_, ()>(Async::NotReady)
} else {
Ok(Async::Ready(()))
}
})).unwrap();
let cs_fut = cs.clone();
rt.block_on(future::poll_fn(move || -> Poll<_, ()> {
let mut cs = cs_fut.lock();
cs.broadcast_event(&InEvent::NextState);
if cs.complete_broadcast().is_not_ready() {
return Ok(Async::NotReady)
}
assert_matches!(cs.poll(), Async::Ready(CollectionEvent::NodeReached(reach_ev)) => {
reach_ev.accept(());
});
Ok(Async::Ready(()))
})).expect("tokio works");
let cs2 = cs.clone();
rt.block_on(future::poll_fn(move || {
if cs2.lock().start_broadcast(&InEvent::NextState).is_not_ready() {
Ok::<_, ()>(Async::NotReady)
} else {
Ok(Async::Ready(()))
}
})).unwrap();
let cs_fut = cs.clone();
rt.block_on(future::poll_fn(move || -> Poll<_, ()> {
let mut cs = cs_fut.lock();
cs.broadcast_event(&InEvent::NextState);
if cs.complete_broadcast().is_not_ready() {
return Ok(Async::NotReady)
}
assert_matches!(cs.poll(), Async::Ready(CollectionEvent::NodeEvent{peer: _, event}) => {
assert_matches!(event, OutEvent::Custom("init"));
});
@ -175,20 +195,40 @@ fn events_in_a_node_reaches_the_collection_stream() {
})).expect("tokio works");
let cs2 = cs.clone();
rt.block_on(future::poll_fn(move || {
if cs2.lock().start_broadcast(&InEvent::NextState).is_not_ready() {
Ok::<_, ()>(Async::NotReady)
} else {
Ok(Async::Ready(()))
}
})).unwrap();
let cs_fut = cs.clone();
rt.block_on(future::poll_fn(move || -> Poll<_, ()> {
let mut cs = cs_fut.lock();
cs.broadcast_event(&InEvent::NextState);
if cs.complete_broadcast().is_not_ready() {
return Ok(Async::NotReady)
}
assert_matches!(cs.poll(), Async::Ready(CollectionEvent::NodeEvent{peer: _, event}) => {
assert_matches!(event, OutEvent::Custom("from handler 1"));
});
Ok(Async::Ready(()))
})).expect("tokio works");
let cs2 = cs.clone();
rt.block_on(future::poll_fn(move || {
if cs2.lock().start_broadcast(&InEvent::NextState).is_not_ready() {
Ok::<_, ()>(Async::NotReady)
} else {
Ok(Async::Ready(()))
}
})).unwrap();
let cs_fut = cs.clone();
rt.block_on(future::poll_fn(move || -> Poll<_, ()> {
let mut cs = cs_fut.lock();
cs.broadcast_event(&InEvent::NextState);
if cs.complete_broadcast().is_not_ready() {
return Ok(Async::NotReady)
}
assert_matches!(cs.poll(), Async::Ready(CollectionEvent::NodeEvent{peer: _, event}) => {
assert_matches!(event, OutEvent::Custom("from handler 2"));
});
@ -238,13 +278,20 @@ fn task_closed_with_error_when_task_is_connected_yields_node_error() {
let mut rt = Builder::new().core_threads(1).build().unwrap();
// Kick it off
let cs2 = cs.clone();
rt.block_on(future::poll_fn(move || {
if cs2.lock().start_broadcast(&InEvent::NextState).is_not_ready() {
Ok::<_, ()>(Async::NotReady)
} else {
Ok(Async::Ready(()))
}
})).unwrap();
let cs_fut = cs.clone();
rt.block_on(future::poll_fn(move || -> Poll<_, ()> {
let mut cs = cs_fut.lock();
assert_matches!(cs.poll(), Async::NotReady);
// send an event so the Handler errors in two polls
cs.broadcast_event(&InEvent::NextState);
Ok(Async::Ready(()))
Ok(cs.complete_broadcast())
})).expect("tokio works");
// Accept the new node