[Tarantool-patches] [PATCH 6/9] error: use error_payload in Lua

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Sat Nov 6 02:56:37 MSK 2021


In Lua struct error used RTTI to return members of the error
depending on its type. If a field was added to error's payload, it
wasn't visible. The patch makes Lua use error_payload instead of
RTTI. Now if the payload gets a new field, it becomes
automatically visible in Lua without need to introduce a new
method for it.

Part of #5568
---
 extra/exports             |  3 +-
 src/box/error.cc          | 24 ++------------
 src/lib/core/diag.c       |  6 ++++
 src/lib/core/diag.h       |  3 ++
 src/lib/core/exception.cc |  8 +----
 src/lua/error.lua         | 69 +++++++++------------------------------
 src/lua/init.lua          | 24 --------------
 7 files changed, 29 insertions(+), 108 deletions(-)

diff --git a/extra/exports b/extra/exports
index 19e23f5db..4e9cea2eb 100644
--- a/extra/exports
+++ b/extra/exports
@@ -151,12 +151,11 @@ csv_next
 csv_setopt
 decimal_from_string
 decimal_unpack
+error_field_find
 error_ref
 error_set_prev
 error_unpack_unsafe
 error_unref
-exception_get_int
-exception_get_string
 fiber_attr_delete
 fiber_attr_getstacksize
 fiber_attr_new
diff --git a/src/box/error.cc b/src/box/error.cc
index be3b3b6f5..e0a1894e1 100644
--- a/src/box/error.cc
+++ b/src/box/error.cc
@@ -158,13 +158,8 @@ const char *rmean_error_strings[RMEAN_ERROR_LAST] = {
 	"ERROR"
 };
 
-static struct method_info clienterror_methods[] = {
-	make_method(&type_ClientError, "code", &ClientError::errcode),
-	METHODS_SENTINEL
-};
-
 const struct type_info type_ClientError =
-	make_type("ClientError", &type_Exception, clienterror_methods);
+	make_type("ClientError", &type_Exception);
 
 ClientError::ClientError(const type_info *type, const char *file, unsigned line,
 			 uint32_t errcode)
@@ -269,16 +264,8 @@ BuildXlogGapError(const char *file, unsigned line,
 
 struct rlist on_access_denied = RLIST_HEAD_INITIALIZER(on_access_denied);
 
-static struct method_info accessdeniederror_methods[] = {
-	make_method(&type_AccessDeniedError, "access_type", &AccessDeniedError::access_type),
-	make_method(&type_AccessDeniedError, "object_type", &AccessDeniedError::object_type),
-	make_method(&type_AccessDeniedError, "object_name", &AccessDeniedError::object_name),
-	METHODS_SENTINEL
-};
-
 const struct type_info type_AccessDeniedError =
-	make_type("AccessDeniedError", &type_ClientError,
-		  accessdeniederror_methods);
+	make_type("AccessDeniedError", &type_ClientError);
 
 AccessDeniedError::AccessDeniedError(const char *file, unsigned int line,
 				     const char *access_type,
@@ -318,13 +305,8 @@ BuildAccessDeniedError(const char *file, unsigned int line,
 	}
 }
 
-static struct method_info customerror_methods[] = {
-	make_method(&type_CustomError, "custom_type", &CustomError::custom_type),
-	METHODS_SENTINEL
-};
-
 const struct type_info type_CustomError =
-	make_type("CustomError", &type_ClientError, customerror_methods);
+	make_type("CustomError", &type_ClientError);
 
 CustomError::CustomError(const char *file, unsigned int line,
 			 const char *custom_type, uint32_t errcode)
diff --git a/src/lib/core/diag.c b/src/lib/core/diag.c
index b6fa1f5bb..f48ea231f 100644
--- a/src/lib/core/diag.c
+++ b/src/lib/core/diag.c
@@ -61,6 +61,12 @@ error_unref(struct error *e)
 	}
 }
 
+const struct error_field *
+error_field_find(const struct error *e, const char *name)
+{
+	return error_payload_find(&e->payload, name);
+}
+
 int
 error_set_prev(struct error *e, struct error *prev)
 {
diff --git a/src/lib/core/diag.h b/src/lib/core/diag.h
index 40d934c19..c754fc737 100644
--- a/src/lib/core/diag.h
+++ b/src/lib/core/diag.h
@@ -196,6 +196,9 @@ error_move_payload(struct error *e, struct error_payload *src)
 	error_payload_move(&e->payload, src);
 }
 
+const struct error_field *
+error_field_find(const struct error *e, const char *name);
+
 /**
  * Unlink error from its effect. For instance:
  * e1 -> e2 -> e3 -> e4 (e1:set_prev(e2); e2:set_prev(e3) ...)
diff --git a/src/lib/core/exception.cc b/src/lib/core/exception.cc
index 395baff6f..1895c50b8 100644
--- a/src/lib/core/exception.cc
+++ b/src/lib/core/exception.cc
@@ -85,13 +85,7 @@ exception_get_int(struct error *e, const struct method_info *method)
 static OutOfMemory out_of_memory(__FILE__, __LINE__,
 				 sizeof(OutOfMemory), "malloc", "exception");
 
-static const struct method_info exception_methods[] = {
-	make_method(&type_Exception, "message", &Exception::get_errmsg),
-	make_method(&type_Exception, "log", &Exception::log),
-	METHODS_SENTINEL
-};
-const struct type_info type_Exception = make_type("Exception", NULL,
-	exception_methods);
+const struct type_info type_Exception = make_type("Exception", NULL);
 
 void *
 Exception::operator new(size_t size)
diff --git a/src/lua/error.lua b/src/lua/error.lua
index a5d1d2a43..c339de7d4 100644
--- a/src/lua/error.lua
+++ b/src/lua/error.lua
@@ -1,6 +1,10 @@
 -- error.lua (internal file)
 
 local ffi = require('ffi')
+local msgpack = require('msgpack')
+
+local mp_decode = msgpack.decode_unchecked
+
 ffi.cdef[[
 struct type_info;
 
@@ -41,11 +45,6 @@ struct error {
     struct error *_effect;
 };
 
-char *
-exception_get_string(struct error *e, const struct method_info *method);
-int
-exception_get_int(struct error *e, const struct method_info *method);
-
 int
 error_set_prev(struct error *e, struct error *prev);
 
@@ -57,45 +56,10 @@ error_ref(struct error *e);
 
 void
 error_unref(struct error *e);
-]]
-
-local REFLECTION_CACHE = {}
 
-local function reflection_enumerate(err)
-    local key = tostring(err._type)
-    local result = REFLECTION_CACHE[key]
-    if result ~= nil then
-        return result
-    end
-    result = {}
-    -- See type_foreach_method() in reflection.h
-    local t = err._type
-    while t ~= nil do
-        local m = t.methods
-        while m.name ~= nil do
-            result[ffi.string(m.name)] = m
-            m = m + 1
-        end
-        t = t.parent
-    end
-    REFLECTION_CACHE[key] = result
-    return result
-end
-
-local function reflection_get(err, method)
-    if method.nargs ~= 0 then
-        return nil -- NYI
-    end
-    if method.rtype == ffi.C.CTYPE_INT then
-        return tonumber(ffi.C.exception_get_int(err, method))
-    elseif method.rtype == ffi.C.CTYPE_CONST_CHAR_PTR then
-        local str = ffi.C.exception_get_string(err, method)
-        if str == nil then
-            return nil
-        end
-        return ffi.string(str)
-    end
-end
+const struct error_field *
+error_field_find(const struct error *e, const char *name);
+]]
 
 local function error_base_type(err)
     return ffi.string(err._type.name)
@@ -175,11 +139,11 @@ local function error_unpack(err)
     for key, getter in pairs(error_fields)  do
         result[key] = getter(err)
     end
-    for key, getter in pairs(reflection_enumerate(err)) do
-        local value = reflection_get(err, getter)
-        if value ~= nil then
-            result[key] = value
-        end
+    local payload = err._payload
+    local fields = payload._fields
+    for i = 0, payload._count - 1 do
+        local f = fields[i]
+        result[ffi.string(f._name)] = mp_decode(f._data)
     end
     return result
 end
@@ -216,12 +180,9 @@ local function error_index(err, key)
     if getter ~= nil then
         return getter(err)
     end
-    getter = reflection_enumerate(err)[key]
-    if getter ~= nil and getter.nargs == 0 then
-        local val = reflection_get(err, getter)
-        if val ~= nil then
-            return val
-        end
+    local f = ffi.C.error_field_find(err, key)
+    if f ~= nil then
+        return mp_decode(f._data)
     end
     return error_methods[key]
 end
diff --git a/src/lua/init.lua b/src/lua/init.lua
index 9e3c813c3..f808a5c32 100644
--- a/src/lua/init.lua
+++ b/src/lua/init.lua
@@ -3,37 +3,13 @@
 
 local ffi = require('ffi')
 ffi.cdef[[
-struct type_info;
 struct method_info;
 
-enum ctype {
-    CTYPE_VOID = 0,
-    CTYPE_INT,
-    CTYPE_CONST_CHAR_PTR
-};
-
 struct type_info {
     const char *name;
     const struct type_info *parent;
     const struct method_info *methods;
 };
-
-enum { METHOD_ARG_MAX = 8 };
-
-struct method_info {
-    const struct type_info *owner;
-    const char *name;
-    enum ctype rtype;
-    enum ctype atype[METHOD_ARG_MAX];
-    int nargs;
-    bool isconst;
-
-    union {
-        /* Add extra space to get proper struct size in C */
-        void *_spacer[2];
-    };
-};
-
 double
 tarantool_uptime(void);
 typedef int32_t pid_t;
-- 
2.24.3 (Apple Git-128)



More information about the Tarantool-patches mailing list