[tarantool-patches] [PATCH v3 4/6] box: extend box.error.new({}) API

Kirill Shcherbatov kshcherbatov at tarantool.org
Mon Sep 2 17:51:12 MSK 2019


We need to extend box.error.new({}) to define complex errors
with diagnostics area in NetBox module in following patches.

Needed for #1148

@TarantoolBot document
Title: Extend box.error.new API

Create an error object, but do not throw. This is useful when error
information should be saved for later retrieval.

Currently the box.error.new() endpoint supports two usages:
box.error.new(errcode, format_str, <params>)
and
box.error.new({code = errcode, reason = error_msg_str,
               <file = filename_str>, <line = linenumber>,
               <prev = reason_error_object>})
The second one allows to (optionally) specify an extra information:
filename - the name of the file where the error was produced,
line - the line number,
prev - the previous (reason) error object.

Being set, the reason object could be unpacked using
box.error.prev API.
---
 src/box/error.h           |  5 +--
 src/box/sql/vdbe.c        |  2 +-
 src/box/xrow.c            |  2 +-
 test/app-tap/module_api.c |  3 +-
 test/box/function1.c      | 29 ++++++++--------
 test/box/reload1.c        | 20 ++++++-----
 test/box/reload2.c        |  9 ++---
 test/box/tuple_bench.c    | 10 +++---
 src/box/error.cc          |  5 ++-
 src/box/lua/error.cc      | 15 +++++++--
 test/box/misc.result      | 70 +++++++++++++++++++++++++++++++++++++++
 test/box/misc.test.lua    | 22 ++++++++++++
 12 files changed, 152 insertions(+), 40 deletions(-)

diff --git a/src/box/error.h b/src/box/error.h
index b8c7cf73d..2d5fb6370 100644
--- a/src/box/error.h
+++ b/src/box/error.h
@@ -119,6 +119,7 @@ box_error_clear(void);
  * Set the last error.
  *
  * \param code IPROTO error code (enum \link box_error_code \endlink)
+ * \param prev - the reason error object
  * \param format (const char * ) - printf()-like format string
  * \param ... - format arguments
  * \returns -1 for convention use
@@ -127,13 +128,13 @@ box_error_clear(void);
  */
 int
 box_error_set(const char *file, unsigned line, uint32_t code,
-	      const char *format, ...);
+	      struct error *prev, const char *format, ...);
 
 /**
  * A backward-compatible API define.
  */
 #define box_error_raise(code, format, ...) \
-	box_error_set(__FILE__, __LINE__, code, format, ##__VA_ARGS__)
+	box_error_set(__FILE__, __LINE__, code, NULL, format, ##__VA_ARGS__)
 
 /** \endcond public */
 
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 02e16da19..627532265 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -939,7 +939,7 @@ case OP_Goto: {             /* jump */
  * text description of the error.
  */
 case OP_SetDiag: {             /* jump */
-	box_error_set(__FILE__, __LINE__, pOp->p1, pOp->p4.z);
+	box_error_set(__FILE__, __LINE__, pOp->p1, NULL, pOp->p4.z);
 	if (pOp->p2 != 0)
 		goto jump_to_p2;
 	break;
diff --git a/src/box/xrow.c b/src/box/xrow.c
index 0ae5271c1..78462469a 100644
--- a/src/box/xrow.c
+++ b/src/box/xrow.c
@@ -1063,7 +1063,7 @@ xrow_decode_error(struct xrow_header *row)
 	}
 
 error:
-	box_error_set(__FILE__, __LINE__, code, error);
+	box_error_set(__FILE__, __LINE__, code, NULL, error);
 }
 
 void
diff --git a/test/app-tap/module_api.c b/test/app-tap/module_api.c
index b81a98056..15078f953 100644
--- a/test/app-tap/module_api.c
+++ b/test/app-tap/module_api.c
@@ -202,7 +202,8 @@ int fiber_test_func(va_list va)
 		fiber_set_cancellable(true);
 		fiber_sleep(0.01);
 		if (fiber_is_cancelled()) {
-			box_error_set(__FILE__, __LINE__, 10, "test error");
+			box_error_set(__FILE__, __LINE__, 10, NULL,
+				      "test error");
 			return -1;
 		}
 		fiber_set_cancellable(false);
diff --git a/test/box/function1.c b/test/box/function1.c
index ee5a422b5..84ed1ea1d 100644
--- a/test/box/function1.c
+++ b/test/box/function1.c
@@ -17,13 +17,13 @@ args(box_function_ctx_t *ctx, const char *args, const char *args_end)
 {
 	uint32_t arg_count = mp_decode_array(&args);
 	if (arg_count < 1) {
-		return box_error_set(__FILE__, __LINE__, ER_PROC_C, "%s",
-			"invalid argument count");
+		return box_error_set(__FILE__, __LINE__, ER_PROC_C, NULL,
+				     "invalid argument count");
 	}
 
 	if (mp_typeof(*args) != MP_UINT) {
-		return box_error_set(__FILE__, __LINE__, ER_PROC_C, "%s",
-			"first tuple field must be uint");
+		return box_error_set(__FILE__, __LINE__, ER_PROC_C, NULL,
+				     "first tuple field must be uint");
 	}
 
 	uint32_t num = mp_decode_uint(&args);
@@ -70,7 +70,7 @@ divide(box_function_ctx_t *ctx, const char *args, const char *args_end)
 		return -1;
 	return box_return_tuple(ctx, tuple);
 error:
-	return box_error_set(__FILE__, __LINE__, ER_PROC_C, "%s",
+	return box_error_set(__FILE__, __LINE__, ER_PROC_C, NULL,
 			     "invalid argument");
 }
 
@@ -90,9 +90,9 @@ multi_inc(box_function_ctx_t *ctx, const char *args, const char *args_end)
 	uint32_t index_id = box_index_id_by_name(space_id, INDEX_NAME,
 		strlen(INDEX_NAME));
 	if (space_id == BOX_ID_NIL || index_id == BOX_ID_NIL) {
-		return box_error_set(__FILE__, __LINE__, ER_PROC_C,
-			"Can't find index %s in space %s",
-			INDEX_NAME, SPACE_NAME);
+		return box_error_set(__FILE__, __LINE__, ER_PROC_C, NULL,
+				     "Can't find index %s in space %s",
+				     INDEX_NAME, SPACE_NAME);
 	}
 	say_debug("space_id = %u, index_id = %u", space_id, index_id);
 
@@ -104,7 +104,8 @@ multi_inc(box_function_ctx_t *ctx, const char *args, const char *args_end)
 		/* Decode next argument */
 		if (mp_typeof(*args) != MP_UINT)
 			return box_error_set(__FILE__, __LINE__,
-					       ER_PROC_C, "Expected uint keys");
+					     ER_PROC_C, NULL,
+					     "Expected uint keys");
 		uint32_t key = mp_decode_uint(&args);
 		(void) key;
 
@@ -125,8 +126,8 @@ multi_inc(box_function_ctx_t *ctx, const char *args, const char *args_end)
 			const char *field = box_tuple_field(tuple, 1);
 			if (field == NULL || mp_typeof(*field) != MP_UINT)
 				return box_error_set(__FILE__, __LINE__,
-						       ER_PROC_LUA,
-						       "Invalid tuple");
+						     ER_PROC_LUA, NULL,
+						     "Invalid tuple");
 			counter = mp_decode_uint(&field) + 1;
 		}
 
@@ -149,7 +150,7 @@ multi_inc(box_function_ctx_t *ctx, const char *args, const char *args_end)
 int
 errors(box_function_ctx_t *ctx, const char *args, const char *args_end)
 {
-	box_error_set(__FILE__, __LINE__, ER_PROC_C, "%s", "Proc error");
+	box_error_set(__FILE__, __LINE__, ER_PROC_C, NULL, "Proc error");
 
 	const box_error_t *error = box_error_last();
 	assert(strcmp(box_error_type(error), "ClientError") == 0);
@@ -184,8 +185,8 @@ test_yield(box_function_ctx_t *ctx, const char *args, const char *args_end)
 
 	uint32_t space_id = box_space_id_by_name(SPACE_NAME, strlen(SPACE_NAME));
 	if (space_id == BOX_ID_NIL) {
-		return box_error_set(__FILE__, __LINE__, ER_PROC_C,
-			"Can't find space %s", SPACE_NAME);
+		return box_error_set(__FILE__, __LINE__, ER_PROC_C, NULL,
+				     "Can't find space %s", SPACE_NAME);
 	}
 
 	assert(!box_txn());
diff --git a/test/box/reload1.c b/test/box/reload1.c
index 83227851e..232f5e297 100644
--- a/test/box/reload1.c
+++ b/test/box/reload1.c
@@ -13,9 +13,9 @@ foo(box_function_ctx_t *ctx, const char *args, const char *args_end)
 	uint32_t index_id = box_index_id_by_name(space_test_id, INDEX_NAME,
 		strlen(INDEX_NAME));
 	if (space_test_id == BOX_ID_NIL || index_id == BOX_ID_NIL) {
-		return box_error_set(__FILE__, __LINE__, ER_PROC_C,
-			"Can't find index %s in space %s",
-			INDEX_NAME, SPACE_TEST_NAME);
+		return box_error_set(__FILE__, __LINE__, ER_PROC_C, NULL,
+				     "Can't find index %s in space %s",
+				     INDEX_NAME, SPACE_TEST_NAME);
 	}
 	mp_decode_array(&args);
 	uint32_t num = mp_decode_uint(&args);
@@ -25,8 +25,9 @@ foo(box_function_ctx_t *ctx, const char *args, const char *args_end)
 	end = mp_encode_array(end, 1);
 	end = mp_encode_uint(end, num);
 	if (box_insert(space_test_id, buf, end, NULL) < 0) {
-		return box_error_set(__FILE__, __LINE__, ER_PROC_C,
-			"Can't insert in space %s", SPACE_TEST_NAME);
+		return box_error_set(__FILE__, __LINE__, ER_PROC_C, NULL,
+				     "Can't insert in space %s",
+				     SPACE_TEST_NAME);
 	}
 	end = buf;
 	end = mp_encode_array(end, 1);
@@ -38,8 +39,9 @@ foo(box_function_ctx_t *ctx, const char *args, const char *args_end)
 	end = mp_encode_array(end, 1);
 	end = mp_encode_int(end, -((int)num));
 	if (box_insert(space_test_id, buf, end, NULL) < 0) {
-		return box_error_set(__FILE__, __LINE__, ER_PROC_C,
-			"Can't insert in space %s", SPACE_TEST_NAME);
+		return box_error_set(__FILE__, __LINE__, ER_PROC_C, NULL,
+				     "Can't insert in space %s",
+				     SPACE_TEST_NAME);
 	}
 	return 0;
 }
@@ -51,8 +53,8 @@ test_reload(box_function_ctx_t *ctx, const char *args, const char *args_end)
 
 	uint32_t space_id = box_space_id_by_name(SPACE_NAME, strlen(SPACE_NAME));
 	if (space_id == BOX_ID_NIL) {
-		return box_error_set(__FILE__, __LINE__, ER_PROC_C,
-			"Can't find space %s", SPACE_NAME);
+		return box_error_set(__FILE__, __LINE__, ER_PROC_C, NULL,
+				     "Can't find space %s", SPACE_NAME);
 	}
 
 	assert(!box_txn());
diff --git a/test/box/reload2.c b/test/box/reload2.c
index 30a359171..a3b99c8ae 100644
--- a/test/box/reload2.c
+++ b/test/box/reload2.c
@@ -10,16 +10,17 @@ foo(box_function_ctx_t *ctx, const char *args, const char *args_end)
 	uint32_t space_test_id = box_space_id_by_name(SPACE_TEST_NAME,
 			strlen(SPACE_TEST_NAME));
 	if (space_test_id == BOX_ID_NIL) {
-		return box_error_set(__FILE__, __LINE__, ER_PROC_C,
-			"Can't find space %s", SPACE_TEST_NAME);
+		return box_error_set(__FILE__, __LINE__, ER_PROC_C, NULL,
+				     "Can't find space %s", SPACE_TEST_NAME);
 	}
 	char buf[16];
 	char *end = buf;
 	end = mp_encode_array(end, 1);
 	end = mp_encode_uint(end, 0);
 	if (box_insert(space_test_id, buf, end, NULL) < 0) {
-		return box_error_set(__FILE__, __LINE__, ER_PROC_C,
-			"Can't insert in space %s", SPACE_TEST_NAME);
+		return box_error_set(__FILE__, __LINE__, ER_PROC_C, NULL,
+				     "Can't insert in space %s",
+				     SPACE_TEST_NAME);
 	}
 	return 0;
 }
diff --git a/test/box/tuple_bench.c b/test/box/tuple_bench.c
index ec92e6168..557b5d814 100644
--- a/test/box/tuple_bench.c
+++ b/test/box/tuple_bench.c
@@ -23,9 +23,9 @@ tuple_bench(box_function_ctx_t *ctx, const char *args, const char *args_end)
 		strlen(INDEX_NAME));
 
 	if (space_id == BOX_ID_NIL || index_id == BOX_ID_NIL) {
-		return box_error_set(__FILE__, __LINE__, ER_PROC_C,
-			"Can't find index %s in space %s",
-			INDEX_NAME, SPACE_NAME);
+		return box_error_set(__FILE__, __LINE__, ER_PROC_C, NULL,
+				     "Can't find index %s in space %s",
+				     INDEX_NAME, SPACE_NAME);
 	}
 	say_debug("space_id = %u, index_id = %u", space_id, index_id);
 
@@ -37,8 +37,8 @@ tuple_bench(box_function_ctx_t *ctx, const char *args, const char *args_end)
 	/* get key types from args, and build test tuples with according types*/
 	uint32_t arg_count = mp_decode_array(&args);
 	if (arg_count < 1) {
-		return box_error_set(__FILE__, __LINE__, ER_PROC_C, "%s",
-			"invalid argument count");
+		return box_error_set(__FILE__, __LINE__, ER_PROC_C, NULL,
+				     "invalid argument count");
 	}
 	uint32_t n = mp_decode_array(&args);
 	uint32_t knum = 0, kstr = 0;
diff --git a/src/box/error.cc b/src/box/error.cc
index 7dfe1b3ee..02ec9cafa 100644
--- a/src/box/error.cc
+++ b/src/box/error.cc
@@ -71,12 +71,15 @@ box_error_clear(void)
 
 int
 box_error_set(const char *file, unsigned line, uint32_t code,
-		const char *fmt, ...)
+	      struct error *prev, const char *fmt, ...)
 {
 	struct error *e = BuildClientError(file, line, ER_UNKNOWN);
 	ClientError *client_error = type_cast(ClientError, e);
 	if (client_error) {
 		client_error->m_errcode = code;
+		client_error->prev = prev;
+		if (prev != NULL)
+			error_ref(prev);
 		va_list ap;
 		va_start(ap, fmt);
 		error_vformat_msg(e, fmt, ap);
diff --git a/src/box/lua/error.cc b/src/box/lua/error.cc
index 5a2f5fc7d..a3ce27aa8 100644
--- a/src/box/lua/error.cc
+++ b/src/box/lua/error.cc
@@ -49,6 +49,7 @@ luaT_error_create(lua_State *L, int top_base)
 	const char *reason = NULL;
 	const char *file = "";
 	unsigned line = 0;
+	struct error *prev = NULL;
 	lua_Debug info;
 	int top = lua_gettop(L);
 	if (top >= top_base && lua_type(L, top_base) == LUA_TNUMBER) {
@@ -82,6 +83,15 @@ luaT_error_create(lua_State *L, int top_base)
 			if (reason == NULL)
 				reason = "";
 			lua_pop(L, 1);
+			lua_getfield(L, top_base, "file");
+			file = lua_tostring(L, -1);
+			lua_pop(L, 1);
+			lua_getfield(L, top_base, "line");
+			line = lua_tonumber(L, -1);
+			lua_pop(L, 1);
+			lua_getfield(L, top_base, "prev");
+			prev = luaL_iserror(L, -1);
+			lua_pop(L, 1);
 		} else if (luaL_iserror(L, top_base)) {
 			lua_error(L);
 			return;
@@ -91,7 +101,8 @@ luaT_error_create(lua_State *L, int top_base)
 	}
 
 raise:
-	if (lua_getstack(L, 1, &info) && lua_getinfo(L, "Sl", &info)) {
+	if ((line == 0 || file == NULL) &&
+	    lua_getstack(L, 1, &info) && lua_getinfo(L, "Sl", &info)) {
 		if (*info.short_src) {
 			file = info.short_src;
 		} else if (*info.source) {
@@ -102,7 +113,7 @@ raise:
 		line = info.currentline;
 	}
 	say_debug("box.error() at %s:%i", file, line);
-	box_error_set(file, line, code, "%s", reason);
+	box_error_set(file, line, code, prev, "%s", reason);
 }
 
 static int
diff --git a/test/box/misc.result b/test/box/misc.result
index 555075a6c..8429bf191 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -1328,3 +1328,73 @@ test_run:grep_log('default', 'test log')
 ---
 - test log
 ...
+--
+-- gh-1148: Stacked diagnostics area in fiber
+--
+e1 = box.error.new({code = 128, file = "hohoho.c", line = 123, reason = "#1"})
+---
+...
+e2 = box.error.new({code = 129, file = "hohoho.c", line = 124, reason = "#2", prev = e1})
+---
+...
+e2.refs == 2
+---
+- true
+...
+e1.refs == 2
+---
+- true
+...
+box.error.prev(e1) == nil
+---
+- true
+...
+box.error.prev(e2) == e1
+---
+- true
+...
+e2.prev == box.error.prev(e2)
+---
+- true
+...
+collectgarbage()
+---
+- 0
+...
+e1.refs == 2
+---
+- true
+...
+e1.refs == 2
+---
+- true
+...
+box.error.clear()
+---
+...
+e1.refs == 2
+---
+- true
+...
+e2.refs == 1
+---
+- true
+...
+e2 = nil
+---
+...
+collectgarbage()
+---
+- 0
+...
+e1.refs == 1
+---
+- true
+...
+e1 = nil
+---
+...
+collectgarbage()
+---
+- 0
+...
diff --git a/test/box/misc.test.lua b/test/box/misc.test.lua
index cc223b2ef..f4444b470 100644
--- a/test/box/misc.test.lua
+++ b/test/box/misc.test.lua
@@ -383,3 +383,25 @@ tuple_format = box.internal.new_tuple_format(format)
 box.cfg{}
 local ffi = require'ffi' ffi.C._say(ffi.C.S_WARN, nil, 0, nil, "%s", "test log")
 test_run:grep_log('default', 'test log')
+
+--
+-- gh-1148: Stacked diagnostics area in fiber
+--
+e1 = box.error.new({code = 128, file = "hohoho.c", line = 123, reason = "#1"})
+e2 = box.error.new({code = 129, file = "hohoho.c", line = 124, reason = "#2", prev = e1})
+e2.refs == 2
+e1.refs == 2
+box.error.prev(e1) == nil
+box.error.prev(e2) == e1
+e2.prev == box.error.prev(e2)
+collectgarbage()
+e1.refs == 2
+e1.refs == 2
+box.error.clear()
+e1.refs == 2
+e2.refs == 1
+e2 = nil
+collectgarbage()
+e1.refs == 1
+e1 = nil
+collectgarbage()
-- 
2.22.1





More information about the Tarantool-patches mailing list