[Tarantool-patches] [PATCH v3] iproto: make iproto thread more independent from tx

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Wed Oct 28 01:06:54 MSK 2020


Привет. Далее будет ревью на русском, чтобы лучше понимать друг
друга.

>     > There are some other
>     > cases where we might not want to spend precious tx time to process
>     > the connection in case iproto can do it all alone.
> 
>     3. What are these other cases? I can think only of SWIM in iproto thread,
>     but it is not related at all.
> 
> The cases are that we can now add more logic to request
> processing in iproto, if needed, when tx is not really needed to answer.
> For example, see #4646.
> This can also solve some problems with improper tx answers. 

Какие improper tx answers?

>     > This patch allows iproto to accept connection and send greeting by
>     > itself. The connection is initialized in tx thread when the real
>     > request comes through iproto_msg_decode(). In case request type was not
>     > recognized we can also send reply with an error without using tx. It is
>     > planned to add more iproto logic to prevent extra interaction with
>     > tx thread. This patch already to some extent solves descriptors leakage
>     > problem as far as connection establishes and stays in fetch_schema
>     > state while tx thread is unresponsive.
>     > The other user visible change is that on_connect triggers won't run on
>     > connections that don't provide any input, as reflected in
>     > bad_trigger.test.py.
>     >
>     > Part of #3776
>     >
>     > @TarantoolBot document
>     > Title: iproto: on_connect triggers execution
>     > Update the documentation for on_connect triggers to reflect that they
>     > are now being executed only with the first request. Though the triggers
>     > are still the first thing to be executed on a new connection. While it
>     > is quite a synthetic case to establish a connection without making
>     > any requests it is technically possible and now your triggers won't be
>     > executed in this case. Some request is required to start their
>     > execution.
> 
>     4. I am not sure I understand. According to 3776 there was a problem, that
>     the connections were made. So they didn't do any requests? And the
>     case is not that syntetic as it seems?
> 
> They didn’t make any requests just because they weren’t even greeted.
> Instead they were reconnecting all the time. As soon as they are greeted
> they are sending requests.

Не совсем так. Да, они не были greeted, но проблема не в том, что они слали или
не слали реквесты. А в том, что даже если они делали дисконнект, он должен был
пройти через tx поток. После твоего патча вроде как не должен. В итоге они так
же коннектятся, зависают, отключаются, но теперь закрытие сокета ловится как
EV_READ в ипрото потоке, и там же закрывается. Правда объект iproto_connection,
все буферы, и struct iproto_msg не удаляются все равно. Как бы это не вылетело
по памяти еще раньше.

Все-таки неправильно, что ты сразу шлешь запросы в tx поток. Надо чтоб TX явно
говорил, что это можно делать. До тех пор даже не пытаться туда ничего слать.
Если учесть, что инстанс может подниматься часами, у него может кончиться память
при агрессивных реконнектах с кучи клиентов.

Сейчас время на это есть, поэтому кмк лучше сделать это одним нормальным
патчсетом, торопиться некуда.

>     What was the problem to preserve the original behaviour? For example,
>     you could make the on_connect execution delayed. TX thread could tell
>     when recovery is done, and iproto would send the pending connections to it.
> 
> I think we don’t really need to deal with the connections that don’t send requests.

Тут не про то, кто как думает, а как не сломать совместимость. Походу это ломает.
Раньше триггер звался на все коннекты, и юзер мог их например отлуплять, выдав
ошибку в триггере. Или как-то логгировать.

Я все еще не вижу препятствий это не ломать. Пока ТХ тред не дал разрешение передавать
ему запросы, отлупляем всех.

Когда ТХ тред дал разрешение, все еще не закрытые коннекты идут в ТХ, даже если у них
нет запросов. В чем проблема это сделать и не ломать то, что уже есть?

>     > const char *errmsg;
>     > while (con->parse_size != 0 && !stop_input) {
>     > if (iproto_check_msg_max()) {
>     > @@ -1314,13 +1367,24 @@ iproto_msg_decode(struct iproto_msg *msg, const char **pos, const char *reqend,
>     > (uint32_t) type);
>     > goto error;
>     > }
>     > - return;
>     > + return 0;
>     > error:
>     > /** Log and send the error. */
>     > diag_log();
>     > - diag_create(&msg->diag);
>     > - diag_move(&fiber()->diag, &msg->diag);
>     > - cmsg_init(&msg->base, error_route);
>     > + if (msg->connection->session != NULL) {
>     > + diag_create(&msg->diag);
>     > + diag_move(&fiber()->diag, &msg->diag);
>     > + cmsg_init(&msg->base, error_route);
>     > + return 1;
> 
>     10. Why do you need 3 return values? You only check for -1. So you
>     could return 0 here like it was before, and -1 below. In the
>     calling code you would check != 0 like we do everywhere.
> 
> Well, the idea was that we have 2 different error cases. But actually
> it should be: 0 if the route was inited. -1 otherwise. Now it is like that.
> Fixed in v4.

Идея понятна, что там разное может внутри произойти. Но ты использовал только
2 случая. Какой смысл в третьем? Это был просто мертвый код. Добавлять его
"на всякий случай" нет никакого смысла.

>     > + }
>     > + /*
>     > + * In case session was not created we can process error path
>     > + * without tx thread.
>     > + */
>     > + tx_accept_wpos(msg->connection, &msg->wpos);
>     > + tx_reply_error(msg);
> 
>     11. There is a naming convention, that all tx_ functions are called in
>     TX thread always. All net_ and iproto_ functions are called in IProto
>     thread. Lets not violate the rule and obfuscate the iproto.cc code
>     even more that it is. Please, come up with new names reflecting where
>     the functions are used. Or at least not specifying it as tx_.
> 
> Well, this convention is already broken to some extent. For example,
> tx_reply_error() itself calls iproto_reply_error() and
> iproto_wpos_create(). tx_process_sql() calls iproto_reply_sql().

Возможно я напиздел. Скорее всего iproto_ - это общие функции. net_ - для
сетевого потока, и tx_ - для главного потока. С некоторыми исключениями,
которые скорее всего просто неправильны.

>     > +{
>     > + if (!msg->close_connection)
>     > + return false;
>     > + struct iproto_connection *con = msg->connection;
>     > + int64_t nwr = sio_writev(con->output.fd, msg->wpos.obuf->iov,
>     > + obuf_iovcnt(msg->wpos.obuf));
> 
>     16. You can't just write to a socket whenever you want. It may be
>     not writable. Please, use libev events and callbacks to send anything.
>     You can do a write only when you get EV_WRITE event from libev, who
>     in turn gets it from select/poll/epoll/kqueue/whatever-else-is-provided
>     by the OS.
> 
> Right. As discussed in voice, it is special error case. In case we will
> do the normal way, we won’t be able to send the error. I checked the
> case with bad_trigger.test and it clearly shows that the client won’t
> receive  the error message in case we will try to wait for the event here,
> while sio_writev() does its job.

Ясен пень, если ты сокет закроешь, то писать в него будет нельзя, и никакие
события на него больше не придут от libev. Надо его не закрывать, и тогда
все будет.

Голосом мы обсудили, что это не специальный случай, когда записать ошибку нормально
невозможно, а что просто автору оригинального кода было лень сделать это
нормально через события. И он решил записать в сокет напрямую. Теперь это
протаскивается дальше. Еще вероятная причина - все заточено на использование
obuf, в который нельзя было писать в ипрото потоке впринципе. Я пока не могу
сказать, что с этим делать. Зависит от того, что дальше будет с obuf. См
другое письмо.


More information about the Tarantool-patches mailing list