[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