[tarantool-patches] Re: [PATCH 1/1] netbox: optimize body decoding

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Tue May 15 21:31:20 MSK 2018


Hello.

> Константин Осипов, [15 мая 2018 г., 21:16:08]:
> я всё же считаю что у decode_body должна быть такая же сигнатура как у decode
> 
> вот эта проверка должна быть снаружи:
> 
> +       if (data != end)
> +               return luaL_error(L, "invalid xrow length");
> 
> и сообщение кривое
> 
> это не xrow length
> 
> это body length

Below the fix is presented. At the end of the letter the whole patch is
attached.

diff --git a/src/box/lua/net_box.c b/src/box/lua/net_box.c
index 3d9479283..adf5f7603 100644
--- a/src/box/lua/net_box.c
+++ b/src/box/lua/net_box.c
@@ -560,14 +560,13 @@ handle_error:
   * Decode Tarantool response body.
   * @param Lua stack[1] Raw MessagePack pointer.
   * @param Lua stack[2] End of body pointer.
- * @retval Decoded body.
+ * @retval Decoded body and position of the body end.
   */
  static int
  netbox_decode_body(struct lua_State *L)
  {
  	uint32_t ctypeid;
  	const char *data = *(const char **)luaL_checkcdata(L, 1, &ctypeid);
-	const char *end = *(const char **)luaL_checkcdata(L, 2, &ctypeid);
  	assert(mp_typeof(*data) == MP_MAP);
  	uint32_t map_size = mp_decode_map(&data);
  	/* Until 2.0 body has no keys except DATA. */
@@ -591,9 +590,8 @@ netbox_decode_body(struct lua_State *L)
  			}
  		}
  	}
-	if (data != end)
-		return luaL_error(L, "invalid xrow length");
-	return 1;
+	*(const char **)luaL_pushcdata(L, ctypeid) = data;
+	return 2;
  }
  
  int
diff --git a/src/box/lua/net_box.lua b/src/box/lua/net_box.lua
index 194a1c86b..8fcaf89e8 100644
--- a/src/box/lua/net_box.lua
+++ b/src/box/lua/net_box.lua
@@ -49,29 +49,30 @@ local E_PROC_LUA             = box.error.PROC_LUA
  -- utility tables
  local is_final_state         = {closed = 1, error = 1}
  
-local function decode_nil(...) end
-local function decode_data(raw_data, raw_data_end)
-    local response, real_end = decode(raw_data)
-    assert(real_end == raw_data_end, "invalid xrow length")
-    return response[IPROTO_DATA_KEY]
+local function decode_nil(raw_data, raw_data_end)
+    return nil, raw_data_end
  end
-local function decode_tuple(raw_data, raw_data_end)
-    return internal.decode_body(raw_data, raw_data_end)[1]
+local function decode_data(raw_data)
+    local response, raw_end = decode(raw_data)
+    return response[IPROTO_DATA_KEY], raw_end
  end
-local function decode_get(raw_data, raw_data_end)
-    local body = internal.decode_body(raw_data, raw_data_end)
+local function decode_tuple(raw_data)
+    local response, raw_end = internal.decode_body(raw_data)
+    return response[1], raw_end
+end
+local function decode_get(raw_data)
+    local body, raw_end = internal.decode_body(raw_data)
      if body[2] then
-        return nil, box.error.MORE_THAN_ONE_TUPLE
+        return nil, raw_end, box.error.MORE_THAN_ONE_TUPLE
      end
-    return body[1]
+    return body[1], raw_end
  end
-local function decode_select(raw_data, raw_data_end)
-    return internal.decode_body(raw_data, raw_data_end)
+local function decode_select(raw_data)
+    return internal.decode_body(raw_data)
  end
-local function decode_count(raw_data, raw_data_end)
-    local response, real_end = decode(raw_data)
-    assert(real_end == raw_data_end, "invalid xrow length")
-    return response[IPROTO_DATA_KEY][1]
+local function decode_count(raw_data)
+    local response, raw_end = decode(raw_data)
+    return response[IPROTO_DATA_KEY][1], raw_end
  end
  
  local method_encoder = {
@@ -467,8 +468,10 @@ local function create_transport(host, port, user, password, callback,
          end
  
          -- Decode xrow.body[DATA] to Lua objects
-        request.response, request.errno =
+        local real_end
+        request.response, real_end, request.errno =
              method_decoder[request.method](body_rpos, body_end)
+        assert(real_end == body_end, "invalid body length")
          request.cond:broadcast()
      end
  
===========================================================================================

diff --git a/src/box/lua/net_box.c b/src/box/lua/net_box.c
index 04fe70b03..adf5f7603 100644
--- a/src/box/lua/net_box.c
+++ b/src/box/lua/net_box.c
@@ -38,6 +38,7 @@
  #include "box/iproto_constants.h"
  #include "box/lua/tuple.h" /* luamp_convert_tuple() / luamp_convert_key() */
  #include "box/xrow.h"
+#include "box/tuple.h"
  
  #include "lua/msgpack.h"
  #include "third_party/base64.h"
@@ -555,6 +556,44 @@ handle_error:
  	return 2;
  }
  
+/**
+ * Decode Tarantool response body.
+ * @param Lua stack[1] Raw MessagePack pointer.
+ * @param Lua stack[2] End of body pointer.
+ * @retval Decoded body and position of the body end.
+ */
+static int
+netbox_decode_body(struct lua_State *L)
+{
+	uint32_t ctypeid;
+	const char *data = *(const char **)luaL_checkcdata(L, 1, &ctypeid);
+	assert(mp_typeof(*data) == MP_MAP);
+	uint32_t map_size = mp_decode_map(&data);
+	/* Until 2.0 body has no keys except DATA. */
+	assert(map_size == 1);
+	for (uint32_t i = 0; i < map_size; ++i) {
+		uint32_t key = mp_decode_uint(&data);
+		if (key == IPROTO_DATA) {
+			uint32_t count = mp_decode_array(&data);
+			lua_createtable(L, count, 0);
+			struct tuple_format *format =
+				box_tuple_format_default();
+			for (uint32_t j = 0; j < count; ++j) {
+				const char *begin = data;
+				mp_next(&data);
+				struct tuple *tuple =
+					box_tuple_new(format, begin, data);
+				if (tuple == NULL)
+					luaT_error(L);
+				luaT_pushtuple(L, tuple);
+				lua_rawseti(L, -2, j + 1);
+			}
+		}
+	}
+	*(const char **)luaL_pushcdata(L, ctypeid) = data;
+	return 2;
+}
+
  int
  luaopen_net_box(struct lua_State *L)
  {
@@ -572,6 +611,7 @@ luaopen_net_box(struct lua_State *L)
  		{ "encode_auth",    netbox_encode_auth },
  		{ "decode_greeting",netbox_decode_greeting },
  		{ "communicate",    netbox_communicate },
+		{ "decode_body",    netbox_decode_body },
  		{ NULL, NULL}
  	};
  	/* luaL_register_module polutes _G */
diff --git a/src/box/lua/net_box.lua b/src/box/lua/net_box.lua
index 46382129f..8fcaf89e8 100644
--- a/src/box/lua/net_box.lua
+++ b/src/box/lua/net_box.lua
@@ -27,7 +27,6 @@ local encode_auth     = internal.encode_auth
  local encode_select   = internal.encode_select
  local decode_greeting = internal.decode_greeting
  
-local sequence_mt      = { __serialize = 'sequence' }
  local TIMEOUT_INFINITY = 500 * 365 * 86400
  local VSPACE_ID        = 281
  local VINDEX_ID        = 289
@@ -50,31 +49,30 @@ local E_PROC_LUA             = box.error.PROC_LUA
  -- utility tables
  local is_final_state         = {closed = 1, error = 1}
  
-local function decode_nil(...) end
-local function decode_nop(...) return ... end
-local function decode_tuple(response)
-    if response[1] then
-        return box.tuple.new(response[1])
-    end
+local function decode_nil(raw_data, raw_data_end)
+    return nil, raw_data_end
  end
-local function decode_get(response)
-    if response[2] then
-        return nil, box.error.MORE_THAN_ONE_TUPLE
-    end
-    if response[1] then
-        return box.tuple.new(response[1])
-    end
+local function decode_data(raw_data)
+    local response, raw_end = decode(raw_data)
+    return response[IPROTO_DATA_KEY], raw_end
  end
-local function decode_select(response)
-    setmetatable(response, sequence_mt)
-    local tnew = box.tuple.new
-    for i, v in pairs(response) do
-        response[i] = tnew(v)
+local function decode_tuple(raw_data)
+    local response, raw_end = internal.decode_body(raw_data)
+    return response[1], raw_end
+end
+local function decode_get(raw_data)
+    local body, raw_end = internal.decode_body(raw_data)
+    if body[2] then
+        return nil, raw_end, box.error.MORE_THAN_ONE_TUPLE
      end
-    return response
+    return body[1], raw_end
+end
+local function decode_select(raw_data)
+    return internal.decode_body(raw_data)
  end
-local function decode_count(response)
-    return response[1]
+local function decode_count(raw_data)
+    local response, raw_end = decode(raw_data)
+    return response[IPROTO_DATA_KEY][1], raw_end
  end
  
  local method_encoder = {
@@ -103,8 +101,8 @@ local method_encoder = {
  local method_decoder = {
      ping    = decode_nil,
      call_16 = decode_select,
-    call_17 = decode_nop,
-    eval    = decode_nop,
+    call_17 = decode_data,
+    eval    = decode_data,
      insert  = decode_tuple,
      replace = decode_tuple,
      delete  = decode_tuple,
@@ -115,7 +113,7 @@ local method_decoder = {
      min     = decode_get,
      max     = decode_get,
      count   = decode_count,
-    inject  = decode_nop,
+    inject  = decode_data,
  }
  
  local function next_id(id) return band(id + 1, 0x7FFFFFFF) end
@@ -470,12 +468,10 @@ local function create_transport(host, port, user, password, callback,
          end
  
          -- Decode xrow.body[DATA] to Lua objects
-        body, body_end_check = decode(body_rpos)
-        assert(body_end == body_end_check, "invalid xrow length")
-        if body and body[IPROTO_DATA_KEY] then
-            request.response, request.errno =
-                method_decoder[request.method](body[IPROTO_DATA_KEY])
-        end
+        local real_end
+        request.response, real_end, request.errno =
+            method_decoder[request.method](body_rpos, body_end)
+        assert(real_end == body_end, "invalid body length")
          request.cond:broadcast()
      end
  
diff --git a/test/box/call.result b/test/box/call.result
index e27e2127d..40d7ef952 100644
--- a/test/box/call.result
+++ b/test/box/call.result
@@ -632,7 +632,7 @@ conn:eval("return return_sparse1()")
  ...
  conn:call_16("return_sparse1")
  ---
-- - [{20: 1, 1: 1}]
+- - [{1: 1, 20: 1}]
  ...
  function return_sparse2() return { [1] = 1, [20] = 1} end
  ---







More information about the Tarantool-patches mailing list