From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp54.i.mail.ru (smtp54.i.mail.ru [217.69.128.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 54EF04696C8 for ; Fri, 10 Apr 2020 11:10:51 +0300 (MSK) From: Leonid Vasiliev Date: Fri, 10 Apr 2020 11:10:42 +0300 Message-Id: <4d6b0c27784a8abe7573baa3c859a3ebca07f1fb.1586505741.git.lvasiliev@tarantool.org> In-Reply-To: References: In-Reply-To: References: Subject: [Tarantool-patches] [PATCH v2 4/5] iproto: Add session settings for IPROTO List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: v.shpilevoy@tarantool.org Cc: tarantool-patches@dev.tarantool.org IPROTO session settings for error transmission in various formats depending on session settings have been added. This is required for backward compatibility. @TarantoolBot document Title: Add session_setting iproto_error_format setting has been added to _session_settings Used to set the error transmission format in the session. Old format: transmits as string at IPROTO_BODY New format: transmits as error object at IPROTO_BODY Needed for #4398 --- src/box/iproto.cc | 97 ++++++++++++++++++++++++++++++++++++++++++++++ src/box/lua/net_box.lua | 12 ++++++ src/box/session.cc | 3 ++ src/box/session.h | 3 ++ src/box/session_settings.h | 1 + src/lua/utils.h | 20 ++++++++++ 6 files changed, 136 insertions(+) diff --git a/src/box/iproto.cc b/src/box/iproto.cc index 9dad43b..92be645 100644 --- a/src/box/iproto.cc +++ b/src/box/iproto.cc @@ -55,6 +55,7 @@ #include "call.h" #include "tuple_convert.h" #include "session.h" +#include "session_settings.h" #include "xrow.h" #include "schema.h" /* schema_version */ #include "replication.h" /* instance_uuid */ @@ -2183,6 +2184,100 @@ iproto_session_push(struct session *session, uint64_t sync, struct port *port) /** }}} */ +enum { + IPROTO_SESSION_SETTING_ERR_FORMAT = 0, + iproto_session_setting_MAX, +}; + +static const char *iproto_session_setting_strs[iproto_session_setting_MAX] = { + "iproto_error_format", +}; + +static int iproto_session_field_type[] = { + /** IPROTO_SESSION_SETTING_ERR_FORMAT */ + FIELD_TYPE_UNSIGNED, +}; + +static void +iproto_session_setting_get(int id, const char **mp_pair, + const char **mp_pair_end) +{ + if (id < 0 || id >= iproto_session_setting_MAX) { + diag_set(ClientError, ER_ILLEGAL_PARAMS, + "unknown session setting"); + return; + } + struct session *session = current_session(); + + const char *name = iproto_session_setting_strs[id]; + size_t name_len = strlen(name); + + /* Now we have only one iproto session setting. */ + size_t size = mp_sizeof_array(2) + mp_sizeof_str(name_len) + + mp_sizeof_uint(session->serializer_ctx.err_format_ver); + + char *pos = (char*)static_alloc(size); + assert(pos != NULL); + char *pos_end = mp_encode_array(pos, 2); + pos_end = mp_encode_str(pos_end, name, name_len); + pos_end = mp_encode_uint(pos_end, + session->serializer_ctx.err_format_ver); + *mp_pair = pos; + *mp_pair_end = pos_end; +} + +static int +iproto_session_setting_set(int id, const char *mp_value) +{ + if (id < 0 || id >= iproto_session_setting_MAX) { + diag_set(ClientError, ER_ILLEGAL_PARAMS, + "unknown session setting"); + return -1; + } + /*Current IPROTO session settings are used only for BINARY session */ + if (current_session()->type != SESSION_TYPE_BINARY) + return -1; + + enum mp_type mtype = mp_typeof(*mp_value); + int stype = iproto_session_field_type[id]; + switch(stype) { + case FIELD_TYPE_UNSIGNED: { + if (mtype != MP_UINT) + break; + int val = mp_decode_uint(&mp_value); + switch (id) { + case IPROTO_SESSION_SETTING_ERR_FORMAT: + if (val >= ERR_FORMAT_UNK) + break; + current_session()->serializer_ctx.err_format_ver = val; + return 0; + default: + diag_set(ClientError, ER_SESSION_SETTING_INVALID_VALUE, + iproto_session_setting_strs[id], + field_type_strs[stype]); + return -1; + } + break; + } + default: + unreachable(); + } + diag_set(ClientError, ER_SESSION_SETTING_INVALID_VALUE, + iproto_session_setting_strs[id], field_type_strs[stype]); + return -1; +} + +void +iproto_session_settings_init() +{ + struct session_setting_module *module = + &session_setting_modules[SESSION_SETTING_IPROTO]; + module->settings = iproto_session_setting_strs; + module->setting_count = iproto_session_setting_MAX; + module->get = iproto_session_setting_get; + module->set = iproto_session_setting_set; +} + /** Initialize the iproto subsystem and start network io thread */ void iproto_init() @@ -2201,6 +2296,8 @@ iproto_init() /* .sync = */ iproto_session_sync, }; session_vtab_registry[SESSION_TYPE_BINARY] = iproto_session_vtab; + + iproto_session_settings_init(); } /** Available iproto configuration changes. */ diff --git a/src/box/lua/net_box.lua b/src/box/lua/net_box.lua index 1e0cd7a..c8f76b0 100644 --- a/src/box/lua/net_box.lua +++ b/src/box/lua/net_box.lua @@ -1047,6 +1047,18 @@ local function new_sm(host, port, opts, connection, greeting) if opts.wait_connected ~= false then remote._transport.wait_state('active', tonumber(opts.wait_connected)) end + + -- Set extended error format for session. + if opts.error_extended then + local ext_err_supported = version_at_least(remote.peer_version_id, 2, 4, 1) + if not ext_err_supported then + box.error(box.error.PROC_LUA, + "Server doesn't support extended error format") + end + remote.space._session_settings:update('iproto_error_format', + {{'=', 2, 1}}) + end + return remote end diff --git a/src/box/session.cc b/src/box/session.cc index 8813182..0cd8675 100644 --- a/src/box/session.cc +++ b/src/box/session.cc @@ -144,6 +144,9 @@ session_create(enum session_type type) session->sql_default_engine = SQL_STORAGE_ENGINE_MEMTX; session->sql_stmts = NULL; + /* Set default Lua serializer context */ + session->serializer_ctx.err_format_ver = ERR_FORMAT_DEF; + /* For on_connect triggers. */ credentials_create(&session->credentials, guest_user); struct mh_i64ptr_node_t node; diff --git a/src/box/session.h b/src/box/session.h index 6dfc7cb..a8903aa 100644 --- a/src/box/session.h +++ b/src/box/session.h @@ -36,6 +36,7 @@ #include "fiber.h" #include "user.h" #include "authentication.h" +#include "lua/utils.h" #if defined(__cplusplus) extern "C" { @@ -110,6 +111,8 @@ struct session { struct credentials credentials; /** Trigger for fiber on_stop to cleanup created on-demand session */ struct trigger fiber_on_stop; + /** Session Lua serializer context */ + struct luaL_serializer_ctx serializer_ctx; }; struct session_vtab { diff --git a/src/box/session_settings.h b/src/box/session_settings.h index 25490a7..c139d30 100644 --- a/src/box/session_settings.h +++ b/src/box/session_settings.h @@ -41,6 +41,7 @@ * type list is used by setting iterators. */ enum session_setting_type { + SESSION_SETTING_IPROTO, SESSION_SETTING_SQL, session_setting_type_MAX, }; diff --git a/src/lua/utils.h b/src/lua/utils.h index 0b36727..5875ba3 100644 --- a/src/lua/utils.h +++ b/src/lua/utils.h @@ -266,6 +266,26 @@ struct luaL_serializer { struct rlist on_update; }; +/** + * An error serialization formats + */ +enum error_formats { + /** Default(old) format */ + ERR_FORMAT_DEF, + /** Extended format */ + ERR_FORMAT_EX, + /** The max version of error format */ + ERR_FORMAT_UNK +}; + +/** + * A serializer context (additional settings for a serializer) + */ +struct luaL_serializer_ctx { + /** Version of a format for an error transmission */ + uint8_t err_format_ver; +}; + extern int luaL_nil_ref; extern int luaL_map_metatable_ref; extern int luaL_array_metatable_ref; -- 2.7.4