Tarantool development patches archive
 help / color / mirror / Atom feed
From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
To: tarantool-patches@freelists.org
Cc: kostja@tarantool.org
Subject: [tarantool-patches] [PATCH 1/1] netbox: optimize body decoding
Date: Mon, 14 May 2018 14:41:14 +0300	[thread overview]
Message-ID: <db0a312e9485108d051ad9f718dd759fe47d5640.1526298032.git.v.shpilevoy@tarantool.org> (raw)

Now netbox decodes body twice: MessagePack -> Lua, Lua -> tuples.
Lets do MessagePack -> tuples.

Part of #3333
---
Branch: https://github.com/tarantool/tarantool/tree/gh-3333-netbox-high-cpu
Issue: https://github.com/tarantool/tarantool/issues/3333

 src/box/lua/net_box.c   | 42 ++++++++++++++++++++++++++++++++++++++++
 src/box/lua/net_box.lua | 51 +++++++++++++++++++++----------------------------
 2 files changed, 64 insertions(+), 29 deletions(-)

diff --git a/src/box/lua/net_box.c b/src/box/lua/net_box.c
index 04fe70b03..3d9479283 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,46 @@ 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.
+ */
+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. */
+	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);
+			}
+		}
+	}
+	if (data != end)
+		return luaL_error(L, "invalid xrow length");
+	return 1;
+}
+
 int
 luaopen_net_box(struct lua_State *L)
 {
@@ -572,6 +613,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..194a1c86b 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
@@ -51,30 +50,28 @@ local E_PROC_LUA             = box.error.PROC_LUA
 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_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]
+end
+local function decode_tuple(raw_data, raw_data_end)
+    return internal.decode_body(raw_data, raw_data_end)[1]
 end
-local function decode_get(response)
-    if response[2] then
+local function decode_get(raw_data, raw_data_end)
+    local body = internal.decode_body(raw_data, raw_data_end)
+    if body[2] then
         return nil, box.error.MORE_THAN_ONE_TUPLE
     end
-    if response[1] then
-        return box.tuple.new(response[1])
-    end
+    return body[1]
 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)
-    end
-    return response
+local function decode_select(raw_data, raw_data_end)
+    return internal.decode_body(raw_data, raw_data_end)
 end
-local function decode_count(response)
-    return response[1]
+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]
 end
 
 local method_encoder = {
@@ -103,8 +100,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 +112,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 +467,8 @@ 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
+        request.response, request.errno =
+            method_decoder[request.method](body_rpos, body_end)
         request.cond:broadcast()
     end
 
-- 
2.15.1 (Apple Git-101)

             reply	other threads:[~2018-05-14 11:41 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-05-14 11:41 Vladislav Shpilevoy [this message]
2018-05-15 18:31 ` [tarantool-patches] " Vladislav Shpilevoy
2018-05-15 18:38 ` Konstantin Osipov
2018-05-15 18:42   ` Vladislav Shpilevoy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=db0a312e9485108d051ad9f718dd759fe47d5640.1526298032.git.v.shpilevoy@tarantool.org \
    --to=v.shpilevoy@tarantool.org \
    --cc=kostja@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --subject='Re: [tarantool-patches] [PATCH 1/1] netbox: optimize body decoding' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox