From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 537FE2B3CA for ; Tue, 9 Apr 2019 14:12:16 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id T6tPg9sLmKQA for ; Tue, 9 Apr 2019 14:12:16 -0400 (EDT) Received: from smtpng3.m.smailru.net (smtpng3.m.smailru.net [94.100.177.149]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id BB99D2A6CE for ; Tue, 9 Apr 2019 14:12:15 -0400 (EDT) From: Vladislav Shpilevoy Subject: [tarantool-patches] [PATCH 3/5] test: process IO swim test events before protocol's ones Date: Tue, 9 Apr 2019 21:12:10 +0300 Message-Id: <79b08bc60bcebefba3333dc2874359769e6586c2.1554833062.git.v.shpilevoy@tarantool.org> In-Reply-To: References: In-Reply-To: References: Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-Help: List-Unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-Subscribe: List-Owner: List-post: List-Archive: To: tarantool-patches@freelists.org Cc: kostja@tarantool.org Before that patch the swim test event loop worked like this: pop a new event, set the global watch to its deadline, process the event, repeat until the deadlines are the same. These events usually generate IO events, which are processed next. But after swim_quit() will be introduced, it is possible to insert new IO events before protocol's events like round steps and ack checks. Because of that it would be impossible to process new IO events only, with timeout = 0, or with timeout > 0, but without changing the global clock. For example, a typical test would try to call swim_quit() on a swim instance, and expect that it has sent all the quit messages without delays immediately. But before this patch it would be necessary to run at least one swim round to get to the IO processing. The patch splits protocol's events and IO events processing logic into two functions and calls them explicitly in swim_wait_timeout() - the main function to check something in the swim tests. Part of #3234 --- test/unit/swim_test_ev.c | 27 +-------------------------- test/unit/swim_test_ev.h | 2 +- test/unit/swim_test_transport.c | 32 ++++++++++++++++++++++++++++++-- test/unit/swim_test_transport.h | 9 +++++---- test/unit/swim_test_utils.c | 16 +++++++++++++++- 5 files changed, 52 insertions(+), 34 deletions(-) diff --git a/test/unit/swim_test_ev.c b/test/unit/swim_test_ev.c index 1c4ba8612..135f20107 100644 --- a/test/unit/swim_test_ev.c +++ b/test/unit/swim_test_ev.c @@ -281,7 +281,7 @@ swim_ev_timer_stop(struct ev_loop *loop, struct ev_timer *base) /** Process all the events with the next nearest deadline. */ void -swim_do_loop_step(struct ev_loop *loop) +swim_test_ev_do_loop_step(struct ev_loop *loop) { struct swim_event *next_e, *e = event_heap_top(&event_heap); if (e != NULL) { @@ -296,31 +296,6 @@ swim_do_loop_step(struct ev_loop *loop) e = next_e; } while (e != NULL && e->deadline == watch); } - /* - * After events are processed, it is possible that some of - * them generated IO events. Process them too. - */ - do { - swim_transport_do_loop_step(loop); - /* - * Just a single loop + invoke is not enough. At - * least two are necessary. - * - * First loop does nothing since send queues are - * empty. First invoke fills send queues. - * - * Second loop moves messages from send to recv - * queues. Second invoke processes messages in - * recv queues. - * - * With indirect messages even 2 cycles is not - * enough - processing of one received message can - * add a new message into another send queue. - */ - if (ev_pending_count(loop) == 0) - break; - ev_invoke_pending(loop); - } while (true); } void diff --git a/test/unit/swim_test_ev.h b/test/unit/swim_test_ev.h index 6a0002c2f..bc925a859 100644 --- a/test/unit/swim_test_ev.h +++ b/test/unit/swim_test_ev.h @@ -98,7 +98,7 @@ swim_ev_set_brk(double delay); /** Play one step of event loop, process generated events. */ void -swim_do_loop_step(struct ev_loop *loop); +swim_test_ev_do_loop_step(struct ev_loop *loop); /** Destroy pending events, reset global watch. */ void diff --git a/test/unit/swim_test_transport.c b/test/unit/swim_test_transport.c index f30000135..78fda587a 100644 --- a/test/unit/swim_test_transport.c +++ b/test/unit/swim_test_transport.c @@ -304,8 +304,12 @@ swim_fd_send_packet(struct swim_fd *fd) swim_test_packet_delete(p); } -void -swim_transport_do_loop_step(struct ev_loop *loop) +/** + * Feed EV_WRITE/READ events to the descriptors having something + * to send/recv. + */ +static inline void +swim_test_transport_feed_events(struct ev_loop *loop) { struct swim_fd *fd; /* @@ -322,3 +326,27 @@ swim_transport_do_loop_step(struct ev_loop *loop) ev_feed_fd_event(loop, fd->evfd, EV_READ); } } + +void +swim_test_transport_do_loop_step(struct ev_loop *loop) +{ + do { + ev_invoke_pending(loop); + swim_test_transport_feed_events(loop); + /* + * Just a single loop + invoke is not enough. At + * least two are necessary. + * + * First loop does nothing since send queues are + * empty. First invoke fills send queues. + * + * Second loop moves messages from send to recv + * queues. Second invoke processes messages in + * recv queues. + * + * With indirect messages even 2 cycles is not + * enough - processing of one received message can + * add a new message into another send queue. + */ + } while (ev_pending_count(loop) > 0); +} diff --git a/test/unit/swim_test_transport.h b/test/unit/swim_test_transport.h index d291abe91..9248f0e98 100644 --- a/test/unit/swim_test_transport.h +++ b/test/unit/swim_test_transport.h @@ -41,12 +41,13 @@ struct ev_loop; */ /** - * Feed EV_WRITE event to all opened descriptors, and EV_READ to - * ones, who have not empty recv queue. Move packets from send to - * recv queues. No callbacks is invoked. Only events are fed. + * Until there are no new IO events, feed EV_WRITE event to all + * opened descriptors; EV_READ to ones, who have not empty recv + * queue; invoke callbacks to process the events. Move packets + * from send to recv queues. */ void -swim_transport_do_loop_step(struct ev_loop *loop); +swim_test_transport_do_loop_step(struct ev_loop *loop); /** * Block a file descriptor so as it can not receive nor send any diff --git a/test/unit/swim_test_utils.c b/test/unit/swim_test_utils.c index a42e50cae..8964e345c 100644 --- a/test/unit/swim_test_utils.c +++ b/test/unit/swim_test_utils.c @@ -293,10 +293,24 @@ swim_wait_timeout(double timeout, struct swim_cluster *cluster, { swim_ev_set_brk(timeout); double deadline = swim_time() + timeout; + struct ev_loop *loop = loop(); + /* + * There can be pending out of bound IO events, affecting + * the result. For example, 'quit' messages, which are + * send immediately without preliminary timeouts or + * whatsoever. + */ + swim_test_transport_do_loop_step(loop); while (! check(cluster, data)) { if (swim_time() >= deadline) return -1; - swim_do_loop_step(loop()); + swim_test_ev_do_loop_step(loop); + /* + * After events are processed, it is possible that + * some of them generated IO events. Process them + * too. + */ + swim_test_transport_do_loop_step(loop); } return 0; } -- 2.17.2 (Apple Git-113)