[PATCH 1/6] Add ERROR_INJECT_YIELD and ERROR_INJECT_SLEEP helpers

Vladimir Davydov vdavydov.dev at gmail.com
Sun Jun 30 22:40:14 MSK 2019


ERROR_INJECT_YIELD yields the current fiber execution by calling
fiber_sleep(0) while the given error injection is set.

ERROR_INJECT_SLEEP suspends the current thread execution by calling
usleep(1000) while the given error injection is set.
---
 src/box/memtx_engine.c | 16 ++--------
 src/box/memtx_space.c  | 79 ++++++++++++++++++--------------------------------
 src/box/relay.cc       |  6 ++--
 src/box/vinyl.c        | 23 ++-------------
 src/box/vy_log.c       |  6 +---
 src/box/vy_run.c       |  6 +---
 src/box/vy_scheduler.c | 22 ++++----------
 src/box/wal.c          |  4 +--
 src/curl.c             |  7 +----
 src/lib/core/errinj.h  |  8 +++++
 10 files changed, 53 insertions(+), 124 deletions(-)

diff --git a/src/box/memtx_engine.c b/src/box/memtx_engine.c
index f371d147..c60f831c 100644
--- a/src/box/memtx_engine.c
+++ b/src/box/memtx_engine.c
@@ -774,14 +774,7 @@ memtx_engine_commit_checkpoint(struct engine *engine,
 		snprintf(to, sizeof(to), "%s",
 			 xdir_format_filename(dir, lsn, NONE));
 		const char *from = xdir_format_filename(dir, lsn, INPROGRESS);
-#ifndef NDEBUG
-		struct errinj *delay = errinj(ERRINJ_SNAP_COMMIT_DELAY,
-					       ERRINJ_BOOL);
-		if (delay != NULL && delay->bparam) {
-			while (delay->bparam)
-				fiber_sleep(0.001);
-		}
-#endif
+		ERROR_INJECT_YIELD(ERRINJ_SNAP_COMMIT_DELAY);
 		int rc = coio_rename(from, to);
 		if (rc != 0)
 			panic("can't rename .snap.inprogress");
@@ -990,12 +983,7 @@ memtx_engine_gc_f(va_list va)
 	struct memtx_engine *memtx = va_arg(va, struct memtx_engine *);
 	while (!fiber_is_cancelled()) {
 		bool stop;
-		struct errinj *delay = errinj(ERRINJ_MEMTX_DELAY_GC,
-					      ERRINJ_BOOL);
-		if (delay != NULL && delay->bparam) {
-			while (delay->bparam)
-				fiber_sleep(0.001);
-		}
+		ERROR_INJECT_YIELD(ERRINJ_MEMTX_DELAY_GC);
 		memtx_engine_run_gc(memtx, &stop);
 		if (stop) {
 			fiber_yield_timeout(TIMEOUT_INFINITY);
diff --git a/src/box/memtx_space.c b/src/box/memtx_space.c
index 77a8f7d5..f0e1cfd2 100644
--- a/src/box/memtx_space.c
+++ b/src/box/memtx_space.c
@@ -910,33 +910,21 @@ memtx_space_check_format(struct space *space, struct tuple_format *format)
 		rc = tuple_validate(format, tuple);
 		if (rc != 0)
 			break;
+
+		state.cursor = tuple;
+		tuple_ref(state.cursor);
+
 		if (++count % MEMTX_DDL_YIELD_LOOPS == 0 &&
-		    memtx->state == MEMTX_OK) {
-			state.cursor = tuple;
-			tuple_ref(state.cursor);
+		    memtx->state == MEMTX_OK)
 			fiber_sleep(0);
-			tuple_unref(state.cursor);
 
-			if (state.rc != 0) {
-				rc = -1;
-				diag_move(&state.diag, diag_get());
-				break;
-			}
-		}
+		ERROR_INJECT_YIELD(ERRINJ_CHECK_FORMAT_DELAY);
 
-		struct errinj *inj = errinj(ERRINJ_CHECK_FORMAT_DELAY, ERRINJ_BOOL);
-		if (inj != NULL && inj->bparam && count == 1) {
-			state.cursor = tuple;
-			tuple_ref(state.cursor);
-			do {
-				fiber_sleep(0);
-			} while (inj->bparam);
-			tuple_unref(state.cursor);
-			if (state.rc != 0) {
-				rc = -1;
-				diag_move(&state.diag, diag_get());
-				break;
-			}
+		tuple_unref(state.cursor);
+		if (state.rc != 0) {
+			rc = -1;
+			diag_move(&state.diag, diag_get());
+			break;
 		}
 	}
 	iterator_delete(it);
@@ -1086,39 +1074,30 @@ memtx_space_build_index(struct space *src_space, struct index *new_index,
 		 */
 		if (new_index->def->iid == 0)
 			tuple_ref(tuple);
+		/*
+		 * Remember the latest inserted tuple to
+		 * avoid processing yet to be added tuples
+		 * in on_replace triggers.
+		 */
+		state.cursor = tuple;
+		tuple_ref(state.cursor);
 		if (++count % MEMTX_DDL_YIELD_LOOPS == 0 &&
-		    memtx->state == MEMTX_OK) {
-			/*
-			 * Remember the latest inserted tuple to
-			 * avoid processing yet to be added tuples
-			 * in on_replace triggers.
-			 */
-			state.cursor = tuple;
-			tuple_ref(state.cursor);
+		    memtx->state == MEMTX_OK)
 			fiber_sleep(0);
-			tuple_unref(state.cursor);
-			/*
-			 * The on_replace trigger may have failed
-			 * during the yield.
-			 */
-			if (state.rc != 0) {
-				rc = -1;
-				diag_move(&state.diag, diag_get());
-				break;
-			}
-		}
 		/*
 		 * Sleep after at least one tuple is inserted to test
 		 * on_replace triggers for index build.
 		 */
-		struct errinj *inj = errinj(ERRINJ_BUILD_INDEX_DELAY, ERRINJ_BOOL);
-		if (inj != NULL && inj->bparam && count == 1) {
-			state.cursor = tuple;
-			tuple_ref(state.cursor);
-			do {
-				fiber_sleep(0);
-			} while (inj->bparam);
-			tuple_unref(state.cursor);
+		ERROR_INJECT_YIELD(ERRINJ_BUILD_INDEX_DELAY);
+		tuple_unref(state.cursor);
+		/*
+		 * The on_replace trigger may have failed
+		 * during the yield.
+		 */
+		if (state.rc != 0) {
+			rc = -1;
+			diag_move(&state.diag, diag_get());
+			break;
 		}
 	}
 	iterator_delete(it);
diff --git a/src/box/relay.cc b/src/box/relay.cc
index 906bf8ef..e9f5bdca 100644
--- a/src/box/relay.cc
+++ b/src/box/relay.cc
@@ -684,16 +684,14 @@ relay_subscribe(struct replica *replica, int fd, uint64_t sync,
 static void
 relay_send(struct relay *relay, struct xrow_header *packet)
 {
-	struct errinj *inj = errinj(ERRINJ_RELAY_SEND_DELAY, ERRINJ_BOOL);
-	while (inj != NULL && inj->bparam)
-		fiber_sleep(0.01);
+	ERROR_INJECT_YIELD(ERRINJ_RELAY_SEND_DELAY);
 
 	packet->sync = relay->sync;
 	relay->last_row_time = ev_monotonic_now(loop());
 	coio_write_xrow(&relay->io, packet);
 	fiber_gc();
 
-	inj = errinj(ERRINJ_RELAY_TIMEOUT, ERRINJ_DOUBLE);
+	struct errinj *inj = errinj(ERRINJ_RELAY_TIMEOUT, ERRINJ_DOUBLE);
 	if (inj != NULL && inj->dparam > 0)
 		fiber_sleep(inj->dparam);
 }
diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index 814325da..128b1199 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -1156,12 +1156,7 @@ vinyl_space_check_format(struct space *space, struct tuple_format *format)
 		 */
 		if (++loops % VY_YIELD_LOOPS == 0)
 			fiber_sleep(0);
-		struct errinj *inj = errinj(ERRINJ_CHECK_FORMAT_DELAY, ERRINJ_BOOL);
-		if (inj != NULL && inj->bparam && loops == 1) {
-			do {
-				fiber_sleep(0);
-			} while (inj->bparam);
-		}
+		ERROR_INJECT_YIELD(ERRINJ_CHECK_FORMAT_DELAY);
 		if (ctx.is_failed) {
 			diag_move(&ctx.diag, diag_get());
 			rc = -1;
@@ -3882,14 +3877,7 @@ next:
 		*ret = NULL;
 		return 0;
 	}
-#ifndef NDEBUG
-	struct errinj *delay = errinj(ERRINJ_VY_DELAY_PK_LOOKUP,
-				      ERRINJ_BOOL);
-	if (delay && delay->bparam) {
-		while (delay->bparam)
-			fiber_sleep(0.01);
-	}
-#endif
+	ERROR_INJECT_YIELD(ERRINJ_VY_DELAY_PK_LOOKUP);
 	/* Get the full tuple from the primary index. */
 	if (vy_get_by_secondary_tuple(it->lsm, it->tx,
 				      vy_tx_read_view(it->tx),
@@ -4422,12 +4410,7 @@ vinyl_space_build_index(struct space *src_space, struct index *new_index,
 		 * Sleep after one tuple is inserted to test
 		 * on_replace triggers for index build.
 		 */
-		inj = errinj(ERRINJ_BUILD_INDEX_DELAY, ERRINJ_BOOL);
-		if (inj != NULL && inj->bparam && loops == 1) {
-			do {
-				fiber_sleep(0);
-			} while (inj->bparam);
-		}
+		ERROR_INJECT_YIELD(ERRINJ_BUILD_INDEX_DELAY);
 	}
 	vy_read_iterator_close(&itr);
 
diff --git a/src/box/vy_log.c b/src/box/vy_log.c
index bf50f552..cb291f3c 100644
--- a/src/box/vy_log.c
+++ b/src/box/vy_log.c
@@ -807,11 +807,7 @@ vy_log_tx_flush(struct vy_log_tx *tx)
 		diag_set(ClientError, ER_INJECTION, "vinyl log flush");
 		return -1;
 	});
-	struct errinj *delay = errinj(ERRINJ_VY_LOG_FLUSH_DELAY, ERRINJ_BOOL);
-	if (delay != NULL && delay->bparam) {
-		while (delay->bparam)
-			fiber_sleep(0.001);
-	}
+	ERROR_INJECT_YIELD(ERRINJ_VY_LOG_FLUSH_DELAY);
 
 	int tx_size = 0;
 	struct vy_log_record *record;
diff --git a/src/box/vy_run.c b/src/box/vy_run.c
index dfd71f1f..c6c17aee 100644
--- a/src/box/vy_run.c
+++ b/src/box/vy_run.c
@@ -916,11 +916,7 @@ vy_page_read(struct vy_page *page, const struct vy_page_info *page_info,
 	if (inj != NULL && inj->dparam > 0)
 		usleep(inj->dparam * 1000000);
 
-	inj = errinj(ERRINJ_VY_READ_PAGE_DELAY, ERRINJ_BOOL);
-	if (inj != NULL) {
-		while (inj->bparam)
-			usleep(10000);
-	}
+	ERROR_INJECT_SLEEP(ERRINJ_VY_READ_PAGE_DELAY);
 
 	/* decode xlog tx */
 	const char *data_pos = data;
diff --git a/src/box/vy_scheduler.c b/src/box/vy_scheduler.c
index 0df55818..f3bded20 100644
--- a/src/box/vy_scheduler.c
+++ b/src/box/vy_scheduler.c
@@ -1040,12 +1040,7 @@ vy_task_write_run(struct vy_task *task, bool no_compression)
 	ERROR_INJECT(ERRINJ_VY_RUN_WRITE,
 		     {diag_set(ClientError, ER_INJECTION,
 			       "vinyl dump"); return -1;});
-
-	struct errinj *inj = errinj(ERRINJ_VY_RUN_WRITE_DELAY, ERRINJ_BOOL);
-	if (inj != NULL && inj->bparam) {
-		while (inj->bparam)
-			usleep(10000);
-	}
+	ERROR_INJECT_SLEEP(ERRINJ_VY_RUN_WRITE_DELAY);
 
 	struct vy_run_writer writer;
 	if (vy_run_writer_create(&writer, task->new_run, lsm->env->path,
@@ -1061,7 +1056,8 @@ vy_task_write_run(struct vy_task *task, bool no_compression)
 	int loops = 0;
 	struct vy_entry entry = vy_entry_none();
 	while ((rc = wi->iface->next(wi, &entry)) == 0 && entry.stmt != NULL) {
-		inj = errinj(ERRINJ_VY_RUN_WRITE_STMT_TIMEOUT, ERRINJ_DOUBLE);
+		struct errinj *inj = errinj(ERRINJ_VY_RUN_WRITE_STMT_TIMEOUT,
+					    ERRINJ_DOUBLE);
 		if (inj != NULL && inj->dparam > 0)
 			usleep(inj->dparam * 1000000);
 
@@ -1095,11 +1091,7 @@ fail:
 static int
 vy_task_dump_execute(struct vy_task *task)
 {
-	struct errinj *errinj = errinj(ERRINJ_VY_DUMP_DELAY, ERRINJ_BOOL);
-	if (errinj != NULL && errinj->bparam) {
-		while (errinj->bparam)
-			fiber_sleep(0.01);
-	}
+	ERROR_INJECT_SLEEP(ERRINJ_VY_DUMP_DELAY);
 	/*
 	 * Don't compress L1 runs as they are most frequently read
 	 * and smallest runs at the same time and so we would gain
@@ -1441,11 +1433,7 @@ err:
 static int
 vy_task_compaction_execute(struct vy_task *task)
 {
-	struct errinj *errinj = errinj(ERRINJ_VY_COMPACTION_DELAY, ERRINJ_BOOL);
-	if (errinj != NULL && errinj->bparam) {
-		while (errinj->bparam)
-			fiber_sleep(0.01);
-	}
+	ERROR_INJECT_SLEEP(ERRINJ_VY_COMPACTION_DELAY);
 	return vy_task_write_run(task, false);
 }
 
diff --git a/src/box/wal.c b/src/box/wal.c
index 6f5d0a58..58a58e5b 100644
--- a/src/box/wal.c
+++ b/src/box/wal.c
@@ -936,9 +936,7 @@ wal_write_to_disk(struct cmsg *msg)
 	struct vclock vclock_diff;
 	vclock_create(&vclock_diff);
 
-	struct errinj *inj = errinj(ERRINJ_WAL_DELAY, ERRINJ_BOOL);
-	while (inj != NULL && inj->bparam)
-		usleep(10);
+	ERROR_INJECT_SLEEP(ERRINJ_WAL_DELAY);
 
 	if (writer->in_rollback.route != NULL) {
 		/* We're rolling back a failed write. */
diff --git a/src/curl.c b/src/curl.c
index 3b48f907..a41c65e4 100644
--- a/src/curl.c
+++ b/src/curl.c
@@ -297,12 +297,7 @@ curl_execute(struct curl_request *curl_request, struct curl_env *env,
 	mcode = curl_multi_add_handle(env->multi, curl_request->easy);
 	if (mcode != CURLM_OK)
 		goto curl_merror;
-#ifndef NDEBUG
-	struct errinj *errinj = errinj(ERRINJ_HTTP_RESPONSE_ADD_WAIT,
-				       ERRINJ_BOOL);
-	while (errinj != NULL && errinj->bparam)
-		fiber_sleep(0.001);
-#endif
+	ERROR_INJECT_YIELD(ERRINJ_HTTP_RESPONSE_ADD_WAIT);
 	/* Don't wait on a cond if request has already failed or finished. */
 	if (curl_request->code == CURLE_OK && curl_request->in_progress) {
 		++env->stat.active_requests;
diff --git a/src/lib/core/errinj.h b/src/lib/core/errinj.h
index 78783651..a55f583c 100644
--- a/src/lib/core/errinj.h
+++ b/src/lib/core/errinj.h
@@ -153,6 +153,7 @@ errinj_foreach(errinj_cb cb, void *cb_ctx);
 
 #ifdef NDEBUG
 #  define ERROR_INJECT(ID, CODE)
+#  define ERROR_INJECT_WHILE(ID, CODE)
 #  define errinj(ID, TYPE) ((struct errinj *) NULL)
 #else
 #  /* Returns the error injection by id */
@@ -167,9 +168,16 @@ errinj_foreach(errinj_cb cb, void *cb_ctx);
 		if (errinj(ID, ERRINJ_BOOL)->bparam) \
 			CODE; \
 	} while (0)
+#  define ERROR_INJECT_WHILE(ID, CODE) \
+	do { \
+		while (errinj(ID, ERRINJ_BOOL)->bparam) \
+			CODE; \
+	} while (0)
 #endif
 
 #define ERROR_INJECT_RETURN(ID) ERROR_INJECT(ID, return -1)
+#define ERROR_INJECT_SLEEP(ID) ERROR_INJECT_WHILE(ID, usleep(1000))
+#define ERROR_INJECT_YIELD(ID) ERROR_INJECT_WHILE(ID, fiber_sleep(0))
 
 #if defined(__cplusplus)
 } /* extern "C" */
-- 
2.11.0




More information about the Tarantool-patches mailing list