[tarantool-patches] [PATCH 1/5] swim: do not use ev_timer_start

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Wed May 1 01:31:23 MSK 2019


Appeared that libev changes 'ev_timer.at' field to a remaining
time value, and it can't be used as a storage for a timeout. By
the same reason ev_timer_start() can't be used to reuse a timer.

On the contrary, 'ev_timer.repeat' is not touched by libev, and
ev_timer_again() allows to reuse a timer.

This patch replaces 'at' with 'repeat' and ev_timer_start() with
ev_timer_again().

The bug was not detected by unit tests, because they implement
their own event loop and do not change ev_timer.at. Now they do
to prevent a regression.

Part of #3234
---
 src/lib/swim/swim.c      | 28 +++++++++++-----------------
 src/lib/swim/swim.h      |  4 ----
 src/lib/swim/swim_ev.c   |  6 ++++++
 src/lib/swim/swim_ev.h   |  3 +++
 test/unit/swim_test_ev.c | 11 +++++++++++
 5 files changed, 31 insertions(+), 21 deletions(-)

diff --git a/src/lib/swim/swim.c b/src/lib/swim/swim.c
index 68b87b120..dfee16493 100644
--- a/src/lib/swim/swim.c
+++ b/src/lib/swim/swim.c
@@ -496,7 +496,7 @@ swim_wait_ack(struct swim *swim, struct swim_member *member,
 	      bool was_ping_indirect)
 {
 	if (heap_node_is_stray(&member->in_wait_ack_heap)) {
-		double timeout = swim->wait_ack_tick.at;
+		double timeout = swim->wait_ack_tick.repeat;
 		/*
 		 * Direct ping is two trips: PING + ACK.
 		 * Indirect ping is four trips: PING,
@@ -507,7 +507,7 @@ swim_wait_ack(struct swim *swim, struct swim_member *member,
 			timeout *= 2;
 		member->ping_deadline = swim_time() + timeout;
 		wait_ack_heap_insert(&swim->wait_ack_heap, member);
-		swim_ev_timer_start(loop(), &swim->wait_ack_tick);
+		swim_ev_timer_again(loop(), &swim->wait_ack_tick);
 	}
 }
 
@@ -767,7 +767,7 @@ swim_new_member(struct swim *swim, const struct sockaddr_in *addr,
 		return NULL;
 	}
 	if (mh_size(swim->members) > 1)
-		swim_ev_timer_start(loop(), &swim->round_tick);
+		swim_ev_timer_again(loop(), &swim->round_tick);
 
 	/* Dissemination component. */
 	swim_on_member_update(swim, member);
@@ -1072,7 +1072,7 @@ swim_complete_step(struct swim_task *task,
 	(void) rc;
 	(void) task;
 	struct swim *swim = swim_by_scheduler(scheduler);
-	swim_ev_timer_start(loop(), &swim->round_tick);
+	swim_ev_timer_again(loop(), &swim->round_tick);
 	/*
 	 * It is possible that the original member was deleted
 	 * manually during the task execution.
@@ -1239,7 +1239,7 @@ swim_check_acks(struct ev_loop *loop, struct ev_timer *t, int events)
 	struct swim_member *m;
 	while ((m = wait_ack_heap_top(&swim->wait_ack_heap)) != NULL) {
 		if (current_time < m->ping_deadline) {
-			swim_ev_timer_start(loop, t);
+			swim_ev_timer_again(loop, t);
 			return;
 		}
 		wait_ack_heap_pop(&swim->wait_ack_heap);
@@ -1635,7 +1635,7 @@ swim_new(void)
 	}
 	rlist_create(&swim->round_queue);
 	swim_ev_timer_init(&swim->round_tick, swim_begin_step,
-			   HEARTBEAT_RATE_DEFAULT, 0);
+			   0, HEARTBEAT_RATE_DEFAULT);
 	swim->round_tick.data = (void *) swim;
 	swim_task_create(&swim->round_step_task, swim_complete_step, NULL,
 			 "round packet");
@@ -1644,7 +1644,7 @@ swim_new(void)
 	/* Failure detection component. */
 	wait_ack_heap_create(&swim->wait_ack_heap);
 	swim_ev_timer_init(&swim->wait_ack_tick, swim_check_acks,
-			   ACK_TIMEOUT_DEFAULT, 0);
+			   0, ACK_TIMEOUT_DEFAULT);
 	swim->wait_ack_tick.data = (void *) swim;
 	swim->gc_mode = SWIM_GC_ON;
 
@@ -1737,11 +1737,11 @@ swim_cfg(struct swim *swim, const char *uri, double heartbeat_rate,
 	} else {
 		addr = swim->self->addr;
 	}
-	if (swim->round_tick.at != heartbeat_rate && heartbeat_rate > 0)
-		swim_ev_timer_set(&swim->round_tick, heartbeat_rate, 0);
+	if (swim->round_tick.repeat != heartbeat_rate && heartbeat_rate > 0)
+		swim_ev_timer_set(&swim->round_tick, 0, heartbeat_rate);
 
-	if (swim->wait_ack_tick.at != ack_timeout && ack_timeout > 0)
-		swim_ev_timer_set(&swim->wait_ack_tick, ack_timeout, 0);
+	if (swim->wait_ack_tick.repeat != ack_timeout && ack_timeout > 0)
+		swim_ev_timer_set(&swim->wait_ack_tick, 0, ack_timeout);
 
 	if (new_self != NULL) {
 		swim->self->status = MEMBER_LEFT;
@@ -1763,12 +1763,6 @@ swim_set_codec(struct swim *swim, enum crypto_algo algo, const char *key)
 	return swim_scheduler_set_codec(&swim->scheduler, algo, key);
 }
 
-double
-swim_ack_timeout(const struct swim *swim)
-{
-	return swim->wait_ack_tick.at;
-}
-
 bool
 swim_is_configured(const struct swim *swim)
 {
diff --git a/src/lib/swim/swim.h b/src/lib/swim/swim.h
index 5abbe8c33..653e45be7 100644
--- a/src/lib/swim/swim.h
+++ b/src/lib/swim/swim.h
@@ -101,10 +101,6 @@ swim_cfg(struct swim *swim, const char *uri, double heartbeat_rate,
 	 double ack_timeout, enum swim_gc_mode gc_mode,
 	 const struct tt_uuid *uuid);
 
-/** SWIM's ACK timeout, previously set via @sa swim_cfg. */
-double
-swim_ack_timeout(const struct swim *swim);
-
 /** Set payload to disseminate over the cluster. */
 int
 swim_set_payload(struct swim *swim, const char *payload, uint16_t payload_size);
diff --git a/src/lib/swim/swim_ev.c b/src/lib/swim/swim_ev.c
index f7c464426..49c8c273b 100644
--- a/src/lib/swim/swim_ev.c
+++ b/src/lib/swim/swim_ev.c
@@ -44,6 +44,12 @@ swim_ev_timer_start(struct ev_loop *loop, struct ev_timer *watcher)
 	ev_timer_start(loop, watcher);
 }
 
+void
+swim_ev_timer_again(struct ev_loop *loop, struct ev_timer *watcher)
+{
+	ev_timer_again(loop, watcher);
+}
+
 void
 swim_ev_timer_stop(struct ev_loop *loop, struct ev_timer *watcher)
 {
diff --git a/src/lib/swim/swim_ev.h b/src/lib/swim/swim_ev.h
index 34394ef47..0fe550523 100644
--- a/src/lib/swim/swim_ev.h
+++ b/src/lib/swim/swim_ev.h
@@ -46,6 +46,9 @@ swim_time(void);
 void
 swim_ev_timer_start(struct ev_loop *loop, struct ev_timer *watcher);
 
+void
+swim_ev_timer_again(struct ev_loop *loop, struct ev_timer *watcher);
+
 void
 swim_ev_timer_stop(struct ev_loop *loop, struct ev_timer *watcher);
 
diff --git a/test/unit/swim_test_ev.c b/test/unit/swim_test_ev.c
index 135f20107..16fd87c78 100644
--- a/test/unit/swim_test_ev.c
+++ b/test/unit/swim_test_ev.c
@@ -184,6 +184,7 @@ swim_timer_event_process(struct swim_event *e, struct ev_loop *loop)
 	assert(e->type == SWIM_EVENT_TIMER);
 	struct ev_watcher *w = ((struct swim_timer_event *) e)->watcher;
 	swim_timer_event_delete(e);
+	((struct ev_timer *) w)->at = 0;
 	ev_invoke(loop, w, EV_TIMER);
 }
 
@@ -265,6 +266,16 @@ swim_ev_timer_start(struct ev_loop *loop, struct ev_timer *base)
 	swim_timer_event_new((struct ev_watcher *) base, base->at);
 }
 
+void
+swim_ev_timer_again(struct ev_loop *loop, struct ev_timer *base)
+{
+	(void) loop;
+	if (swim_event_by_ev((struct ev_watcher *) base) != NULL)
+		return;
+	/* Create the periodic watcher and one event. */
+	swim_timer_event_new((struct ev_watcher *) base, base->repeat);
+}
+
 /** Time stop cancels the event if the timer is active. */
 void
 swim_ev_timer_stop(struct ev_loop *loop, struct ev_timer *base)
-- 
2.20.1 (Apple Git-117)





More information about the Tarantool-patches mailing list