Tarantool development patches archive
 help / color / mirror / Atom feed
From: Konstantin Osipov <kostja@tarantool.org>
To: tarantool-patches@freelists.org
Cc: vdavydov.dev@gmail.com
Subject: Re: [tarantool-patches] [PATCH v2 08/10] session: introduce text box.session.push
Date: Thu, 10 May 2018 22:27:54 +0300	[thread overview]
Message-ID: <20180510192754.GH30593@atlas> (raw)
In-Reply-To: <f16c5d5a1089229efe330bf4385fdd5434be052b.1524228894.git.v.shpilevoy@tarantool.org>

* Vladislav Shpilevoy <v.shpilevoy@tarantool.org> [18/04/20 16:31]:
> +/**
> + * Push a tagged YAML document into a console socket.
> + * @param session Console session.
> + * @param port Port with YAML to push.
> + *
> + * @retval  0 Success.
> + * @retval -1 Error.
> + */
> +static int
> +console_session_push(struct session *session, struct port *port)
> +{
> +	assert(session_vtab_registry[session->type].push ==
> +	       console_session_push);
> +	uint32_t text_len;
> +	const char *text = port_dump_plain(port, &text_len);
> +	if (text == NULL)
> +		return -1;
> +	int fd = session_fd(session);
> +	while (text_len > 0) {
> +		while (coio_wait(fd, COIO_WRITE,
> +				 TIMEOUT_INFINITY) != COIO_WRITE);

Nitpick: the socket is ready in 99% of cases, there is no reason
to call coio_wait() unless you get EINTR. 
Second, why the choice of fio_writev() rather than write() or
send? 

What is wrong with coio_writev or similar?

> +		const struct iovec iov = {
> +			.iov_base = (void *) text,
> +			.iov_len = text_len
> +		};
> +		ssize_t rc = fio_writev(fd, &iov, 1);
> +		if (rc < 0)
> +			return -1;
> +		text_len -= rc;
> +		text += rc;
> +	}
> +	return 0;
> +}
> @@ -92,13 +93,27 @@ local text_connection_mt = {
>          --
>          eval = function(self, text)
>              text = text..'$EOF$\n'
> -            if self:write(text) then
> +            if not self:write(text) then
> +                error(self:set_error())
> +            end
> +            while true do
>                  local rc = self:read()
> -                if rc then
> +                if not rc then
> +                    break
> +                end
> +                local handle, prefix = yaml.decode_tag(rc)
> +                assert(handle or not prefix)
> +                if not handle then
> +                    -- Can not fail - tags are encoded with no
> +                    -- user participation and are correct always.
> +                    assert(not prefix)

In Lua, asserts take CPU time. Please don't use them unless in a
test.

>                      return rc
>                  end
> +                if handle == PUSH_TAG_HANDLE and self.print_f then
> +                    self.print_f(rc)
> +                end
>              end
> -            error(self:set_error())
> +            return rc
>          end,
>          --
>          -- Make the connection be in error state, set error
> @@ -121,15 +136,18 @@ local text_connection_mt = {
>  -- netbox-like object.
>  -- @param connection Socket to wrap.
>  -- @param url Parsed destination URL.
> +-- @param print_f Function to print push messages.
> +--
>  -- @retval nil, err Error, and err contains an error message.
>  -- @retval  not nil Netbox-like object.
>  --
> -local function wrap_text_socket(connection, url)
> +local function wrap_text_socket(connection, url, print_f)
>      local conn = setmetatable({
>          _socket = connection,
>          state = 'active',
>          host = url.host or 'localhost',
>          port = url.service,
> +        print_f = print_f,
>      }, text_connection_mt)
>      if not conn:write('require("console").delimiter("$EOF$")\n') or
>         not conn:read() then
> @@ -369,7 +387,8 @@ local function connect(uri, opts)
>      end
>      local remote
>      if greeting.protocol == 'Lua console' then
> -        remote = wrap_text_socket(connection, u)
> +        remote = wrap_text_socket(connection, u,
> +                                  function(msg) self:print(msg) end)
>      else
>          opts = {
>              connect_timeout = opts.timeout,
> diff --git a/src/box/lua/session.c b/src/box/lua/session.c
> index 5fe5f08d4..306271809 100644
> --- a/src/box/lua/session.c
> +++ b/src/box/lua/session.c
> @@ -41,6 +41,8 @@
>  #include "box/session.h"
>  #include "box/user.h"
>  #include "box/schema.h"
> +#include "box/port.h"
> +#include "box/lua/console.h"
>  
>  static const char *sessionlib_name = "box.session";
>  
> @@ -355,6 +357,52 @@ lbox_push_on_access_denied_event(struct lua_State *L, void *event)
>  	return 3;
>  }
>  
> +/**
> + * Port to push a message from Lua.
> + */
> +struct lua_push_port {
> +	const struct port_vtab *vtab;
> +	/**
> +	 * Lua state, containing data to dump on top of the stack.
> +	 */
> +	struct lua_State *L;
> +};
> +
> +static const char *
> +lua_push_port_dump_plain(struct port *port, uint32_t *size);
> +
> +static const struct port_vtab lua_push_port_vtab = {
> +       .dump_msgpack = NULL,
> +       /*
> +        * Dump_16 has no sense, since push appears since 1.10
> +        * protocol.
> +        */
> +       .dump_msgpack_16 = NULL,
> +       .dump_plain = lua_push_port_dump_plain,
> +       .destroy = NULL,
> +};
> +
> +static const char *
> +lua_push_port_dump_plain(struct port *port, uint32_t *size)
> +{
> +	struct lua_push_port *lua_port = (struct lua_push_port *) port;
> +	assert(lua_port->vtab == &lua_push_port_vtab);
> +	struct lua_State *L = lua_port->L;
> +	int rc = console_encode_push(L);
> +	if (rc == 2) {
> +		assert(lua_isnil(L, -2));
> +		assert(lua_isstring(L, -1));
> +		diag_set(ClientError, ER_PROC_LUA, lua_tostring(L, -1));
> +		return NULL;
> +	}
> +	assert(rc == 1);
> +	assert(lua_isstring(L, -1));
> +	size_t len;
> +	const char *result = lua_tolstring(L, -1, &len);
> +	*size = (uint32_t) len;
> +	return result;
> +}
> +
>  /**
>   * Push a message using a protocol, depending on a session type.
>   * @param data Data to push, first argument on a stack.
> @@ -367,7 +415,11 @@ lbox_session_push(struct lua_State *L)
>  	if (lua_gettop(L) != 1)
>  		return luaL_error(L, "Usage: box.session.push(data)");
>  
> -	if (session_push(current_session(), NULL) != 0) {
> +	struct lua_push_port port;
> +	port.vtab = &lua_push_port_vtab;

Why do you need a separate port? 

And why do you need to create a port for every push? Can't you
reuse the same port as is used for the Lua call itself?

> +	port.L = L;
> +
> +	if (session_push(current_session(), (struct port *) &port) != 0) {
>  		lua_pushnil(L);
>  		luaT_pusherror(L, box_error_last());
>  		return 2;
> diff --git a/src/box/port.c b/src/box/port.c
> index 255eb732c..f9b655840 100644

-- 
Konstantin Osipov, Moscow, Russia, +7 903 626 22 32
http://tarantool.io - www.twitter.com/kostja_osipov

  reply	other threads:[~2018-05-10 19:27 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-20 13:24 [PATCH v2 00/10] session: introduce box.session.push Vladislav Shpilevoy
2018-04-20 13:24 ` [PATCH v2 01/10] yaml: don't throw OOM on any error in yaml encoding Vladislav Shpilevoy
2018-05-10 18:10   ` [tarantool-patches] " Konstantin Osipov
2018-04-20 13:24 ` [tarantool-patches] [PATCH v2 10/10] session: introduce binary box.session.push Vladislav Shpilevoy
2018-05-10 19:50   ` Konstantin Osipov
2018-05-24 20:50     ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-20 13:24 ` [PATCH v2 02/10] yaml: introduce yaml.encode_tagged Vladislav Shpilevoy
2018-05-10 18:22   ` [tarantool-patches] " Konstantin Osipov
2018-05-24 20:50     ` [tarantool-patches] " Vladislav Shpilevoy
2018-05-30 19:15       ` Konstantin Osipov
2018-05-30 20:49         ` Vladislav Shpilevoy
2018-05-31 10:46           ` Konstantin Osipov
2018-04-20 13:24 ` [PATCH v2 03/10] yaml: introduce yaml.decode_tag Vladislav Shpilevoy
2018-05-10 18:41   ` [tarantool-patches] " Konstantin Osipov
2018-05-24 20:50     ` [tarantool-patches] " Vladislav Shpilevoy
2018-05-31 10:54       ` Konstantin Osipov
2018-05-31 11:36       ` Konstantin Osipov
2018-04-20 13:24 ` [PATCH v2 04/10] console: use Lua C API to do formatting for console Vladislav Shpilevoy
2018-05-10 18:46   ` [tarantool-patches] " Konstantin Osipov
2018-05-24 20:50     ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-20 13:24 ` [PATCH v2 05/10] session: move salt into iproto connection Vladislav Shpilevoy
2018-05-10 18:47   ` [tarantool-patches] " Konstantin Osipov
2018-04-20 13:24 ` [PATCH v2 06/10] session: introduce session vtab and meta Vladislav Shpilevoy
2018-05-10 19:20   ` [tarantool-patches] " Konstantin Osipov
2018-05-24 20:50     ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-20 13:24 ` [PATCH v2 07/10] port: rename dump() into dump_msgpack() Vladislav Shpilevoy
2018-05-10 19:21   ` [tarantool-patches] " Konstantin Osipov
2018-04-20 13:24 ` [PATCH v2 08/10] session: introduce text box.session.push Vladislav Shpilevoy
2018-05-10 19:27   ` Konstantin Osipov [this message]
2018-05-24 20:50     ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-20 13:24 ` [PATCH v2 09/10] session: enable box.session.push in local console Vladislav Shpilevoy
2018-05-10 19:28   ` [tarantool-patches] " Konstantin Osipov
2018-05-24 20:50 ` [tarantool-patches] [PATCH 1/1] netbox: introduce iterable future objects Vladislav Shpilevoy
2018-06-04 22:17   ` [tarantool-patches] " 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=20180510192754.GH30593@atlas \
    --to=kostja@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --cc=vdavydov.dev@gmail.com \
    --subject='Re: [tarantool-patches] [PATCH v2 08/10] session: introduce text box.session.push' \
    /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