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 904256EC5C; Fri, 23 Jul 2021 14:16:03 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 904256EC5C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1627038963; bh=3wZ8+c6aFvUNHYp5ShdytCmqWxZ2t7lMiYhstBBIiis=; 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=EdsJSuUDsjiIFotlIwMcROJj3ygUtBBHToVD+/g/z1wvRxKeCUMD9DzrHmwQdWfa4 w6005Q9GjdaGonXMR9AXmK2uRP8Hl0Sno8xKb4RKu1079E/SdlGvWhd0vKgvAtUOvd Ze1ZY4L5o7DBKU7kiWdO20nketDfLGvvz2Zy0jAA= 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 842D36E223 for ; Fri, 23 Jul 2021 14:07:56 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 842D36E223 Received: by smtpng1.m.smailru.net with esmtpa (envelope-from ) id 1m6t24-0004dl-0o; Fri, 23 Jul 2021 14:07:56 +0300 To: tarantool-patches@dev.tarantool.org Date: Fri, 23 Jul 2021 14:07:27 +0300 Message-Id: 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: 4F1203BC0FB41BD941C43E597735A9C30A5AB0699C09BB51962E4FF0DD431C8A182A05F53808504006E07B00837451EFA70035F8324E1AF9C4561B9733282C55A1C0C4C781B50F88 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7BC08626EA5717D14EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637C5BAFDCCAC60DA968638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D82B39BEB64917DE524242D0DAB337EDCE117882F4460429724CE54428C33FAD305F5C1EE8F4F765FCAA867293B0326636D2E47CDBA5A96583BD4B6F7A4D31EC0BC014FD901B82EE079FA2833FD35BB23D27C277FBC8AE2E8BAA867293B0326636D2E47CDBA5A96583BA9C0B312567BB231DD303D21008E29813377AFFFEAFD269A417C69337E82CC2E827F84554CEF50127C277FBC8AE2E8BA83251EDC214901ED5E8D9A59859A8B6045A9A90E9EED90B089D37D7C0E48F6C5571747095F342E88FB05168BE4CE3AF X-C1DE0DAB: 8BD88D57C5CADBC8B2710865C386751094C72BDDC9A8ED5CA3B1A56EE2B804F6B226C914C9968946695E9D90444CEC264DCC8C77FBA9901322D2CEDE4E95CF1BDBE8DEE28BC9005C095FFBCAB1CFE8AABCA57AF85F7723F205FDAB6A9E1FE8E195E441529BB1C770589120F7DAE46353205367B2BCC23E5B5427BE2C7D80C77DBDAD6C7F3747799A X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D3447DF5779098ECEE940F6F2C7530D9EF41DBB4BF965BC423F9911AFCFF9A0D1C37D1111BB638BB3921D7E09C32AA3244C5C0AA47CB7FB0A3C87930A01B9287052C3B3ADDA61883BB5729B2BEF169E0186 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojbL9S8ysBdXiEX0g4jkpDtRcg02+Sbt3W X-Mailru-Sender: 689FA8AB762F7393C37E3C1AEC41BA5D93626BC80A8A556F1EA00420495A9A7E274CEFED1673C562683ABF942079399BFB559BB5D741EB966A65DFF43FF7BE03240331F90058701C67EA787935ED9F1B X-Mras: Ok Subject: [Tarantool-patches] [PATCH 17/20] net.box: rewrite console handlers 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" Strictly speaking, it's not necessary, because console performance is not a problem. We do this for consistency with iproto. --- src/box/lua/net_box.c | 135 ++++++++++++++++++++++++++-------------- src/box/lua/net_box.lua | 49 +++++---------- 2 files changed, 106 insertions(+), 78 deletions(-) diff --git a/src/box/lua/net_box.c b/src/box/lua/net_box.c index 1a615797d485..85a45c54b979 100644 --- a/src/box/lua/net_box.c +++ b/src/box/lua/net_box.c @@ -850,30 +850,25 @@ netbox_send_and_recv_iproto(lua_State *L) /* * Sends and receives data over a console connection. - * Takes socket fd, send_buf (ibuf), recv_buf (ibuf), timeout. - * On success returns response (string). - * On error returns nil, error. + * Returns a pointer to a response string and its len. + * On error returns NULL. */ -static int -netbox_send_and_recv_console(lua_State *L) +static const char * +netbox_send_and_recv_console(int fd, struct ibuf *send_buf, + struct ibuf *recv_buf, double timeout, + size_t *response_len) { - int fd = lua_tointeger(L, 1); - struct ibuf *send_buf = (struct ibuf *) lua_topointer(L, 2); - struct ibuf *recv_buf = (struct ibuf *) lua_topointer(L, 3); - double timeout = (!lua_isnoneornil(L, 4) ? - lua_tonumber(L, 4) : TIMEOUT_INFINITY); const char delim[] = "\n...\n"; size_t delim_len = sizeof(delim) - 1; size_t delim_pos; if (netbox_communicate(fd, send_buf, recv_buf, /*limit=*/SIZE_MAX, delim, delim_len, timeout, &delim_pos) != 0) { - - luaL_testcancel(L); - return luaT_push_nil_and_error(L); + return NULL; } - lua_pushlstring(L, recv_buf->rpos, delim_pos + delim_len); + const char *response = recv_buf->rpos; recv_buf->rpos += delim_pos + delim_len; - return 1; + *response_len = delim_pos + delim_len; + return response; } static void @@ -1456,23 +1451,6 @@ luaT_netbox_registry_new_id(struct lua_State *L) return 1; } -/* - * Returns the next id (sync) without reserving it. - * If called with an argument, returns the id following its value. - */ -static int -luaT_netbox_registry_next_id(struct lua_State *L) -{ - struct netbox_registry *registry = luaT_check_netbox_registry(L, 1); - uint64_t next_sync; - if (lua_isnoneornil(L, 2)) - next_sync = registry->next_sync; - else - next_sync = luaL_touint64(L, 2) + 1; - luaL_pushuint64(L, next_sync); - return 1; -} - static int luaT_netbox_registry_reset(struct lua_State *L) { @@ -1802,24 +1780,93 @@ netbox_dispatch_response_iproto(struct lua_State *L) /* * Given a request registry, request id (sync), and a response string, assigns * the response to the request and completes it. + * + * Lua stack is used for temporarily storing the response string before getting + * a reference to it. */ -static int -netbox_dispatch_response_console(struct lua_State *L) +static void +netbox_dispatch_response_console(struct lua_State *L, + struct netbox_registry *registry, + uint64_t sync, const char *response, + size_t response_len) { - struct netbox_registry *registry = luaT_check_netbox_registry(L, 1); - uint64_t sync = luaL_touint64(L, 2); struct netbox_request *request = netbox_registry_lookup(registry, sync); if (request == NULL) { /* Nobody is waiting for the response. */ - return 0; + return; } - /* - * The response is the last argument of this function so it's already - * on the top of the Lua stack. - */ + lua_pushlstring(L, response, response_len); netbox_request_set_result(request, luaL_ref(L, LUA_REGISTRYINDEX)); netbox_request_complete(request); +} + +/* + * Sets up console delimiter. Should be called before serving any requests. + * Takes socket fd, send_buf (ibuf), recv_buf (ibuf), timeout. + * Returns none on success, error on failure. + */ +static int +netbox_console_setup(struct lua_State *L) +{ + static const char setup_delimiter_cmd[] = + "require('console').delimiter('$EOF$')\n"; + static const size_t setup_delimiter_cmd_len = + sizeof(setup_delimiter_cmd) - 1; + static const char ok_response[] = "---\n...\n"; + static const size_t ok_response_len = sizeof(ok_response) - 1; + int fd = lua_tointeger(L, 1); + struct ibuf *send_buf = (struct ibuf *) lua_topointer(L, 2); + struct ibuf *recv_buf = (struct ibuf *) lua_topointer(L, 3); + double timeout = (!lua_isnoneornil(L, 4) ? + lua_tonumber(L, 4) : TIMEOUT_INFINITY); + void *wpos = ibuf_alloc(send_buf, setup_delimiter_cmd_len); + if (wpos == NULL) + return luaL_error(L, "out of memory"); + memcpy(wpos, setup_delimiter_cmd, setup_delimiter_cmd_len); + size_t response_len; + const char *response = netbox_send_and_recv_console( + fd, send_buf, recv_buf, timeout, &response_len); + if (response == NULL) { + luaL_testcancel(L); + goto error; + } + if (strncmp(response, ok_response, ok_response_len) != 0) { + box_error_raise(ER_NO_CONNECTION, "Unexpected response"); + goto error; + } return 0; +error: + luaT_pusherror(L, box_error_last()); + return 1; +} + +/* + * Processes console requests in a loop until an error. + * Takes request registry, socket fd, send_buf (ibuf), recv_buf (ibuf), timeout. + * Returns the error that broke the loop. + */ +static int +netbox_console_loop(struct lua_State *L) +{ + struct netbox_registry *registry = luaT_check_netbox_registry(L, 1); + int fd = lua_tointeger(L, 2); + struct ibuf *send_buf = (struct ibuf *) lua_topointer(L, 3); + struct ibuf *recv_buf = (struct ibuf *) lua_topointer(L, 4); + double timeout = (!lua_isnoneornil(L, 5) ? + lua_tonumber(L, 5) : TIMEOUT_INFINITY); + uint64_t sync = registry->next_sync; + while (true) { + size_t response_len; + const char *response = netbox_send_and_recv_console( + fd, send_buf, recv_buf, timeout, &response_len); + if (response == NULL) { + luaL_testcancel(L); + luaT_pusherror(L, box_error_last()); + return 1; + } + netbox_dispatch_response_console(L, registry, sync++, + response, response_len); + } } int @@ -1828,7 +1875,6 @@ luaopen_net_box(struct lua_State *L) static const struct luaL_Reg netbox_registry_meta[] = { { "__gc", luaT_netbox_registry_gc }, { "new_id", luaT_netbox_registry_new_id }, - { "next_id", luaT_netbox_registry_next_id }, { "reset", luaT_netbox_registry_reset }, { NULL, NULL } }; @@ -1850,12 +1896,11 @@ luaopen_net_box(struct lua_State *L) { "encode_method", netbox_encode_method }, { "decode_greeting",netbox_decode_greeting }, { "send_and_recv_iproto", netbox_send_and_recv_iproto }, - { "send_and_recv_console", netbox_send_and_recv_console }, { "new_registry", netbox_new_registry }, { "new_request", netbox_new_request }, { "dispatch_response_iproto", netbox_dispatch_response_iproto }, - { "dispatch_response_console", - netbox_dispatch_response_console }, + { "console_setup", netbox_console_setup }, + { "console_loop", netbox_console_loop }, { NULL, NULL} }; /* luaL_register_module polutes _G */ diff --git a/src/box/lua/net_box.lua b/src/box/lua/net_box.lua index 0643477cbc9c..0a21c1341117 100644 --- a/src/box/lua/net_box.lua +++ b/src/box/lua/net_box.lua @@ -327,10 +327,6 @@ local function create_transport(host, port, user, password, callback, body_rpos, body_end) end - local function dispatch_response_console(rid, response) - internal.dispatch_response_console(requests, rid, response) - end - -- IO (WORKER FIBER) -- local function send_and_recv_iproto(timeout) local hdr, body_rpos, body_end = internal.send_and_recv_iproto( @@ -342,22 +338,14 @@ local function create_transport(host, port, user, password, callback, return nil, hdr, body_rpos, body_end end - local function send_and_recv_console(timeout) - local response, err = internal.send_and_recv_console( - connection:fd(), send_buf, recv_buf, timeout) - if not response then - return err.code, err.message - end - return nil, response - end - -- PROTOCOL STATE MACHINE (WORKER FIBER) -- -- -- The sm is implemented as a collection of functions performing -- tail-recursive calls to each other. Yep, Lua optimizes -- such calls, and yep, this is the canonical way to implement -- a state machine in Lua. - local console_sm, iproto_auth_sm, iproto_schema_sm, iproto_sm, error_sm + local console_setup_sm, console_sm, iproto_auth_sm, iproto_schema_sm, + iproto_sm, error_sm -- -- Protocol_sm is a core function of netbox. It calls all @@ -376,19 +364,7 @@ local function create_transport(host, port, user, password, callback, end -- @deprecated since 1.10 if greeting.protocol == 'Lua console' then - log.warn("Netbox text protocol support is deprecated since 1.10, ".. - "please use require('console').connect() instead") - local setup_delimiter = 'require("console").delimiter("$EOF$")\n' - encode_method(M_INJECT, send_buf, nil, setup_delimiter) - local err, response = send_and_recv_console() - if err then - return error_sm(err, response) - elseif response ~= '---\n...\n' then - return error_sm(E_NO_CONNECTION, 'Unexpected response') - end - local rid = requests:next_id() - set_state('active') - return console_sm(rid) + return console_setup_sm() elseif greeting.protocol == 'Binary' then return iproto_auth_sm(greeting.salt) else @@ -397,14 +373,21 @@ local function create_transport(host, port, user, password, callback, end end - console_sm = function(rid) - local err, response = send_and_recv_console() + console_setup_sm = function() + log.warn("Netbox text protocol support is deprecated since 1.10, ".. + "please use require('console').connect() instead") + local err = internal.console_setup(connection:fd(), send_buf, recv_buf) if err then - return error_sm(err, response) - else - dispatch_response_console(rid, response) - return console_sm(requests:next_id(rid)) + return error_sm(err.code, err.message) end + set_state('active') + return console_sm() + end + + console_sm = function() + local err = internal.console_loop(requests, connection:fd(), + send_buf, recv_buf) + return error_sm(err.code, err.message) end iproto_auth_sm = function(salt) -- 2.25.1