[tarantool-patches] [PATCH 3/5] test: process IO swim test events before protocol's ones

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Tue Apr 9 21:12:10 MSK 2019


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)





More information about the Tarantool-patches mailing list