From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id E02C46EC5A; Fri, 23 Jul 2021 14:13:03 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org E02C46EC5A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1627038783; bh=5kWa8rFv7WIGz9ISSR+5jQ2jquHbr0f/NbmuKIvlz2o=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=caJMo60r/hhiUIluhRFwopsFrp7b2rHS8HBpnWNpFPYc+8FkwjV91OMMVWdH2WlSO pSbBnO3jb3T4pZq+GC308G1qWpYPVKttWNZgotLxbZtQ6x7YL4LqWvTrpcBGFPXxj0 NuyNkBDB2Mv/XdtHKKwaRyLhAD9KOIFwFnCCbJbo= Received: from smtpng1.i.mail.ru (smtpng1.i.mail.ru [94.100.181.251]) (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 B10676F3CA for ; Fri, 23 Jul 2021 14:07:45 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org B10676F3CA Received: by smtpng1.m.smailru.net with esmtpa (envelope-from ) id 1m6t1t-0004dl-2D; Fri, 23 Jul 2021 14:07:45 +0300 To: tarantool-patches@dev.tarantool.org Date: Fri, 23 Jul 2021 14:07:21 +0300 Message-Id: <6c3509125f24f6276be678d6b8f1ac264631d048.1627024646.git.vdavydov@tarantool.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-174C08C4: 5188C02AEC42908C481ED7ADC579193296BBA28369E3F2D2713F3D5F7D406D31BCF678C7329BA986 X-7564579A: B8F34718100C35BD X-77F55803: 4F1203BC0FB41BD941C43E597735A9C30A5AB0699C09BB51962E4FF0DD431C8A182A05F5380850402B962636762B6D6F90B8283D3C8412DC880D75021D4E492E58C9F6AB9C81EA85 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE70B8ADF238913687CB287FD4696A6DC2FA8DF7F3B2552694A4E2F5AFA99E116B42401471946AA11AF23F8577A6DFFEA7CED6B9921EE2920938F08D7030A58E5AD1A62830130A00468AEEEE3FBA3A834EE7353EFBB5533756616CF367659D795C097DF04476810CA9F6F3D01F64C2D129FA471835C12D1D9774AD6D5ED66289B5278DA827A17800CE71AE4D56B06699BBC9FA2833FD35BB23D2EF20D2F80756B5F868A13BD56FB6657A471835C12D1D977725E5C173C3A84C362968DCAA3E4B45B117882F4460429728AD0CFFFB425014E868A13BD56FB6657E2021AF6380DFAD1A18204E546F3947CB11811A4A51E3B096D1867E19FE1407959CC434672EE6371089D37D7C0E48F6C8AA50765F79006376A91CFDE938F542CEFF80C71ABB335746BA297DBC24807EABDAD6C7F3747799A X-C1DE0DAB: 8BD88D57C5CADBC8B2710865C386751094C72BDDC9A8ED5CA3B1A56EE2B804F6B226C914C996894645FD9D8A29397D6EFF55FE49A3C2BFCFC8C84E951CD0BE2F296C473AB1E14218EA052B563B0B06C67866D6147AF826D8EB8E4098AAAAFBA490BB6C7F0C148FAEF972CCD2F8FE1EF1CFC4036BBF6A4EA93224940D4130729BCB5012B2E24CD356 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D344EF254DC71474AA385035B99F8AA76DBC573080A2E886D3DE73213AC0CEBC3A042E5657AF82F5D651D7E09C32AA3244C426870FEA1E4092799A9449CC76766D8725D5B54B2FE4575729B2BEF169E0186 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojbL9S8ysBdXiEX0g4jkpDtXa9C6MdlXE0 X-Mailru-Sender: 689FA8AB762F7393C37E3C1AEC41BA5D74FC6F489EB88D5E2FC2DAB50B64BFC1274CEFED1673C562683ABF942079399BFB559BB5D741EB966A65DFF43FF7BE03240331F90058701C67EA787935ED9F1B X-Mras: Ok Subject: [Tarantool-patches] [PATCH 11/20] net.box: rewrite response decoder in C X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Vladimir Davydov via Tarantool-patches Reply-To: Vladimir Davydov Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" This patch moves method_decoder table from Lua to C. This is a step towards rewriting performance-critical parts of net.box in C. --- src/box/lua/net_box.c | 235 +++++++++++++++++++++++++++++++--------- src/box/lua/net_box.lua | 43 +------- 2 files changed, 189 insertions(+), 89 deletions(-) diff --git a/src/box/lua/net_box.c b/src/box/lua/net_box.c index 49030aabea69..c0c3725e5350 100644 --- a/src/box/lua/net_box.c +++ b/src/box/lua/net_box.c @@ -678,6 +678,79 @@ netbox_encode_method(struct lua_State *L) return 0; } +/** + * This function handles a response that is supposed to have an empty body + * (e.g. IPROTO_PING result). It doesn't decode anything per se. Instead it + * simply pushes nil to Lua stack and advances the data ptr to data_end. + */ +static void +netbox_decode_nil(struct lua_State *L, const char **data, + const char *data_end, struct tuple_format *format) +{ + (void) format; + *data = data_end; + lua_pushnil(L); +} + +/** + * This helper skips a MessagePack map header and IPROTO_DATA key so that + * *data points to the actual response content. + */ +static void +netbox_skip_to_data(const char **data) +{ + 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); + (void) map_size; + uint32_t key = mp_decode_uint(data); + assert(key == IPROTO_DATA); + (void) key; +} + +/** + * Decode Tarantool response body consisting of single + * IPROTO_DATA key into Lua table. + * @param L Lua stack to push result on. + * @param data MessagePack. + * @retval Lua table + */ +static void +netbox_decode_table(struct lua_State *L, const char **data, + const char *data_end, struct tuple_format *format) +{ + (void) data_end; + (void) format; + netbox_skip_to_data(data); + luamp_decode(L, cfg, data); +} + +/** + * Same as netbox_decode_table, but only decodes the first element of the + * table, skipping the rest. Used to decode index.count() call result. + * @param L Lua stack to push result on. + * @param data MessagePack. + * @retval count or nil. + */ +static void +netbox_decode_value(struct lua_State *L, const char **data, + const char *data_end, struct tuple_format *format) +{ + (void) data_end; + (void) format; + netbox_skip_to_data(data); + uint32_t count = mp_decode_array(data); + for (uint32_t i = 0; i < count; ++i) { + if (i == 0) + luamp_decode(L, cfg, data); + else + mp_next(data); + } + if (count == 0) + lua_pushnil(L); +} + /** * Decode IPROTO_DATA into tuples array. * @param L Lua stack to push result on. @@ -704,31 +777,45 @@ netbox_decode_data(struct lua_State *L, const char **data, /** * Decode Tarantool response body consisting of single * IPROTO_DATA key into array of tuples. - * @param Lua stack[1] Raw MessagePack pointer. - * @retval Tuples array and position of the body end. + * @param L Lua stack to push result on. + * @param data MessagePack. + * @retval Tuples array. */ -static int -netbox_decode_select(struct lua_State *L) +static void +netbox_decode_select(struct lua_State *L, const char **data, + const char *data_end, struct tuple_format *format) { - uint32_t ctypeid; - assert(lua_gettop(L) == 3); - struct tuple_format *format; - if (lua_type(L, 3) == LUA_TCDATA) - format = lbox_check_tuple_format(L, 3); - else - format = tuple_format_runtime; - 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); - (void) map_size; - uint32_t key = mp_decode_uint(&data); - assert(key == IPROTO_DATA); - (void) key; - netbox_decode_data(L, &data, format); - *(const char **)luaL_pushcdata(L, ctypeid) = data; - return 2; + (void) data_end; + netbox_skip_to_data(data); + netbox_decode_data(L, data, format); +} + +/** + * Same as netbox_decode_select, but only decodes the first tuple of the array, + * skipping the rest. + * @param L Lua stack to push result on. + * @param data MessagePack. + * @retval Tuple or nil. + */ +static void +netbox_decode_tuple(struct lua_State *L, const char **data, + const char *data_end, struct tuple_format *format) +{ + (void) data_end; + netbox_skip_to_data(data); + uint32_t count = mp_decode_array(data); + for (uint32_t i = 0; i < count; ++i) { + const char *begin = *data; + mp_next(data); + if (i > 0) + continue; + struct tuple *tuple = box_tuple_new(format, begin, *data); + if (tuple == NULL) + luaT_error(L); + luaT_pushtuple(L, tuple); + } + if (count == 0) + lua_pushnil(L); } /** Decode optional (i.e. may be present in response) metadata fields. */ @@ -847,28 +934,29 @@ netbox_decode_sql_info(struct lua_State *L, const char **data) } } -static int -netbox_decode_execute(struct lua_State *L) +static void +netbox_decode_execute(struct lua_State *L, const char **data, + const char *data_end, struct tuple_format *format) { - 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); + (void) data_end; + (void) format; + assert(mp_typeof(**data) == MP_MAP); + uint32_t map_size = mp_decode_map(data); int rows_index = 0, meta_index = 0, info_index = 0; for (uint32_t i = 0; i < map_size; ++i) { - uint32_t key = mp_decode_uint(&data); + uint32_t key = mp_decode_uint(data); switch(key) { case IPROTO_DATA: - netbox_decode_data(L, &data, tuple_format_runtime); + netbox_decode_data(L, data, tuple_format_runtime); rows_index = i - map_size; break; case IPROTO_METADATA: - netbox_decode_metadata(L, &data); + netbox_decode_metadata(L, data); meta_index = i - map_size; break; default: assert(key == IPROTO_SQL_INFO); - netbox_decode_sql_info(L, &data); + netbox_decode_sql_info(L, data); info_index = i - map_size; break; } @@ -885,42 +973,41 @@ netbox_decode_execute(struct lua_State *L) assert(meta_index == 0); assert(rows_index == 0); } - *(const char **)luaL_pushcdata(L, ctypeid) = data; - return 2; } -static int -netbox_decode_prepare(struct lua_State *L) +static void +netbox_decode_prepare(struct lua_State *L, const char **data, + const char *data_end, struct tuple_format *format) { - 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); + (void) data_end; + (void) format; + assert(mp_typeof(**data) == MP_MAP); + uint32_t map_size = mp_decode_map(data); int stmt_id_idx = 0, meta_idx = 0, bind_meta_idx = 0, bind_count_idx = 0; uint32_t stmt_id = 0; for (uint32_t i = 0; i < map_size; ++i) { - uint32_t key = mp_decode_uint(&data); + uint32_t key = mp_decode_uint(data); switch(key) { case IPROTO_STMT_ID: { - stmt_id = mp_decode_uint(&data); + stmt_id = mp_decode_uint(data); luaL_pushuint64(L, stmt_id); stmt_id_idx = i - map_size; break; } case IPROTO_METADATA: { - netbox_decode_metadata(L, &data); + netbox_decode_metadata(L, data); meta_idx = i - map_size; break; } case IPROTO_BIND_METADATA: { - netbox_decode_metadata(L, &data); + netbox_decode_metadata(L, data); bind_meta_idx = i - map_size; break; } default: { assert(key == IPROTO_BIND_COUNT); - uint32_t bind_count = mp_decode_uint(&data); + uint32_t bind_count = mp_decode_uint(data); luaL_pushuint64(L, bind_count); bind_count_idx = i - map_size; break; @@ -940,8 +1027,58 @@ netbox_decode_prepare(struct lua_State *L) lua_pushvalue(L, meta_idx - 1); lua_setfield(L, -2, "metadata"); } +} - *(const char **)luaL_pushcdata(L, ctypeid) = data; +/* + * Decodes a response body for the specified method. Pushes the result and the + * end of the decoded data to Lua stack. + * + * Takes the following arguments: + * - method: a value from the netbox_method enumeration + * - data: pointer to the data to decode (char ptr) + * - data_end: pointer to the end of the data (char ptr) + * - format: tuple format to use for decoding the body or nil + */ +static int +netbox_decode_method(struct lua_State *L) +{ + typedef void (*method_decoder_f)(struct lua_State *L, const char **data, + const char *data_end, + struct tuple_format *format); + static method_decoder_f method_decoder[] = { + [NETBOX_PING] = netbox_decode_nil, + [NETBOX_CALL_16] = netbox_decode_select, + [NETBOX_CALL_17] = netbox_decode_table, + [NETBOX_EVAL] = netbox_decode_table, + [NETBOX_INSERT] = netbox_decode_tuple, + [NETBOX_REPLACE] = netbox_decode_tuple, + [NETBOX_DELETE] = netbox_decode_tuple, + [NETBOX_UPDATE] = netbox_decode_tuple, + [NETBOX_UPSERT] = netbox_decode_nil, + [NETBOX_SELECT] = netbox_decode_select, + [NETBOX_EXECUTE] = netbox_decode_execute, + [NETBOX_PREPARE] = netbox_decode_prepare, + [NETBOX_UNPREPARE] = netbox_decode_nil, + [NETBOX_GET] = netbox_decode_tuple, + [NETBOX_MIN] = netbox_decode_tuple, + [NETBOX_MAX] = netbox_decode_tuple, + [NETBOX_COUNT] = netbox_decode_value, + [NETBOX_INJECT] = netbox_decode_table, + }; + enum netbox_method method = lua_tointeger(L, 1); + assert(method < netbox_method_MAX); + uint32_t ctypeid; + const char *data = *(const char **)luaL_checkcdata(L, 2, &ctypeid); + assert(ctypeid == CTID_CHAR_PTR || ctypeid == CTID_CONST_CHAR_PTR); + const char *data_end = *(const char **)luaL_checkcdata(L, 3, &ctypeid); + assert(ctypeid == CTID_CHAR_PTR || ctypeid == CTID_CONST_CHAR_PTR); + struct tuple_format *format; + if (!lua_isnil(L, 4)) + format = lbox_check_tuple_format(L, 4); + else + format = tuple_format_runtime; + method_decoder[method](L, &data, data_end, format); + *(const char **)luaL_pushcdata(L, CTID_CONST_CHAR_PTR) = data; return 2; } @@ -952,10 +1089,8 @@ luaopen_net_box(struct lua_State *L) { "encode_auth", netbox_encode_auth }, { "encode_method", netbox_encode_method }, { "decode_greeting",netbox_decode_greeting }, + { "decode_method", netbox_decode_method }, { "communicate", netbox_communicate }, - { "decode_select", netbox_decode_select }, - { "decode_execute", netbox_decode_execute }, - { "decode_prepare", netbox_decode_prepare }, { NULL, NULL} }; /* luaL_register_module polutes _G */ diff --git a/src/box/lua/net_box.lua b/src/box/lua/net_box.lua index bb844184fa01..9e41d6c0844b 100644 --- a/src/box/lua/net_box.lua +++ b/src/box/lua/net_box.lua @@ -26,6 +26,7 @@ local communicate = internal.communicate local encode_auth = internal.encode_auth local encode_method = internal.encode_method local decode_greeting = internal.decode_greeting +local decode_method = internal.decode_method local TIMEOUT_INFINITY = 500 * 365 * 86400 local VSPACE_ID = 281 @@ -83,21 +84,6 @@ error_unref(struct error *e); -- utility tables local is_final_state = {closed = 1, error = 1} -local function decode_nil(raw_data, raw_data_end) -- luacheck: no unused args - return nil, raw_data_end -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_tuple(raw_data, raw_data_end, format) -- luacheck: no unused args - local response, raw_end = internal.decode_select(raw_data, nil, format) - return response[1], raw_end -end -local function decode_count(raw_data) - local response, raw_end = decode(raw_data) - return response[IPROTO_DATA_KEY][1], raw_end -end local function decode_push(raw_data) local response, raw_end = decode(raw_data) return response[IPROTO_DATA_KEY][1], raw_end @@ -111,27 +97,6 @@ local function version_at_least(peer_version_id, major, minor, patch) return peer_version_id >= version_id(major, minor, patch) end -local method_decoder = { - [M_PING] = decode_nil, - [M_CALL_16] = internal.decode_select, - [M_CALL_17] = decode_data, - [M_EVAL] = decode_data, - [M_INSERT] = decode_tuple, - [M_REPLACE] = decode_tuple, - [M_DELETE] = decode_tuple, - [M_UPDATE] = decode_tuple, - [M_UPSERT] = decode_nil, - [M_SELECT] = internal.decode_select, - [M_EXECUTE] = internal.decode_execute, - [M_PREPARE] = internal.decode_prepare, - [M_UNPREPARE] = decode_nil, - [M_GET] = decode_tuple, - [M_MIN] = decode_tuple, - [M_MAX] = decode_tuple, - [M_COUNT] = decode_count, - [M_INJECT] = decode_data, -} - local function decode_error(raw_data) local ptr = ffi.new('const char *[1]', raw_data) local err = ffi.C.error_unpack_unsafe(ptr) @@ -642,9 +607,9 @@ local function create_transport(host, port, user, password, callback, local real_end -- Decode xrow.body[DATA] to Lua objects if status == IPROTO_OK_KEY then - request.response, real_end = - method_decoder[request.method](body_rpos, body_end, - request.format) + request.response, real_end = decode_method(request.method, + body_rpos, body_end, + request.format) assert(real_end == body_end, "invalid body length") requests[id] = nil request.id = nil -- 2.25.1