[Tarantool-patches] [PATCH v2 4/5] iproto: Add session settings for IPROTO

Leonid Vasiliev lvasiliev at tarantool.org
Fri Apr 10 11:10:42 MSK 2020


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



More information about the Tarantool-patches mailing list