From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 4197329C20 for ; Thu, 5 Apr 2018 05:37:55 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id jrCj3OsvDOHq for ; Thu, 5 Apr 2018 05:37:55 -0400 (EDT) Received: from smtp36.i.mail.ru (smtp36.i.mail.ru [94.100.177.96]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 701EB2973D for ; Thu, 5 Apr 2018 05:37:54 -0400 (EDT) Subject: [tarantool-patches] Re: Fwd: [PATCH 1/1] rfc: describe a Tarantool wire protocol References: <5ad2e4261e5ee48c84fecad13a32c8f9f38aeff0.1522876737.git.v.shpilevoy@tarantool.org> <1522918872.186733999@f420.i.mail.ru> From: Vladislav Shpilevoy Message-ID: Date: Thu, 5 Apr 2018 12:37:50 +0300 MIME-Version: 1.0 In-Reply-To: <1522918872.186733999@f420.i.mail.ru> Content-Type: text/plain; charset="utf-8"; format="flowed" Content-Transfer-Encoding: 8bit Content-Language: en-US Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: =?UTF-8?B?0JDQu9C10LrRgdC10Lkg0JPQsNC00LbQuNC10LI=?= , tarantool-patches@freelists.org Cc: Konstantin Osipov 05.04.2018 12:01, Алексей Гаджиев (Redacted sender alexey.gadzhiev for DMARC) пишет: > Looks cool! Now we can send chunked data! > > I have one question: > Is IPROTO_OK mandatory packet in the response messages sequence? Yes, IPROTO_OK is mandatory. > How can I detect if next push/result_set available if previous > consists only of one chunk without   SQL_INFO_HAS_NEXT_CHUNK? See the state machine picture - next chunk is available, if in the header the response type is IPROTO_CHUNK. SQL_INFO_HAS_NEXT_CHUNK just means, that the next chunk is logically linked with the current. And I have 2 better ideas instead of the 'has_next_chunk' flag: 1) Lets instead of SQL_INFO_HAS_NEXT_CHUNK, that is placed in body, introduce a header flag: IPROTO_CHUNK_IS_CHAIN. When a several chunks are logically linked (for example, they are parts of the same result set), all of them, except last, contains this flag. I think, that 'Chain' term is more easy to understand, than 'HAS_NEXT_CHUNK'. Moreover, HAS_NEXT_CHUNK can be false, but a client must read more responses, if the message does not contain IPROTO_OK - it confuses. Actually IPROTO_CHUNK in the header is the single sign, that more responses are available. The sample of responses: IPROTO_CHUNK     | IPROTO_CHUNK, IS_CHAIN     |     +--IPROTO_CHUNK, IS_CHAIN     |     +--IPROTO_CHUNK, IS_CHAIN     |     +--IPROTO_CHUNK     | IPROTO_CHUNK     | ...     | IPROTO_OK/ERROR 2) The similar idea - instead of IPROTO_CHUNK_IS_CHAIN lest introduce IPROTO_CHAIN_ID - it is an identifier, that is unique for each chunks sequence. And I like this variant most, because in a future it can be extended to allow mixing different chains. The sample of responses: IPROTO_CHUNK     | IPROTO_CHUNK, CHAIN_ID = 1     |     +--IPROTO_CHUNK, CHAIN_ID = 1     |     +--IPROTO_CHUNK, CHAIN_ID = 1     | IPROTO_CHUNK     | IPROTO_CHUNK, CHAIN_ID = 2     |     +--IPROTO_CHUNK, CHAIN_ID = 2     |     +--IPROTO_CHUNK, CHAIN_ID = 2     | IPROTO_CHUNK     | ...     | IPROTO_OK/ERROR > > With best regards, > Alex > > > Четверг, 5 апреля 2018, 9:32 +03:00 от Alexey Gadzhiev > : > > > ---------- Forwarded message ---------- > From: *Vladislav Shpilevoy* > > Date: Thu, Apr 5, 2018 at 12:22 AM > Subject: [PATCH 1/1] rfc: describe a Tarantool wire protocol > To: tarantool-patches@freelists.org > > Cc: kostja@tarantool.org > , > alg1973@gmail.com > , > Vladislav Shpilevoy > > > > --- > Original: > https://github.com/tarantool/tarantool/blob/sql-proto-rfc/doc/RFC/wire_protocol.md > >  doc/RFC/wire_protocol.md  | 214 > +++++++++++++++++++++++++++++++++++++++++ >  doc/RFC/wire_protocol_img1.png | Bin 0 -> 48970 bytes >  2 files changed, 214 insertions(+) >  create mode 100644 doc/RFC/wire_protocol.md >  create mode 100644 doc/RFC/wire_protocol_img1.png > > diff --git a/doc/RFC/wire_protocol.md > b/doc/RFC/wire_protocol.md > new file mode 100644 > index 000000000..d1fc1329c > --- /dev/null > +++ b/doc/RFC/wire_protocol.md > @@ -0,0 +1,214 @@ > +# Tarantool Wire protocol > + > +* **Status**: In progress > +* **Start date**: 04-04-2018 > +* **Authors**: Vladislav Shpilevoy @Gerold103 > v.shpilevoy@tarantool.org > , > Konstantin Osipov @kostja kostja@tarantool.org > , > Alexey Gadzhiev @alg1973 alg1973@gmail.com > > +* **Issues**: > [#2677](https://github.com/tarantool/tarantool/issues/2677), > [#2620](https://github.com/tarantool/tarantool/issues/2620), > [#2618](https://github.com/tarantool/tarantool/issues/2618) > + > +## Summary > + > +Tarantool wire protocol is a convention how to encode and send > results of execution of SQL, Lua and C stored functions, DML (Data > Manipulation Language), DDL (Data Definition Language), DQL (Data > Query Language) requests to remote clients via network. The > protocol is unified for all request types. For a single request > multiple responses of different types can be sent. > + > +## Background and motivation > + > +Tarantool wire protocol is called **IProto**, and is used by > database connectors written on different languages and working on > remote clients. The protocol describes how to distinguish > different message types and what data can be stored in each > message. Tarantool has the following response types: > +* A response, that finalizes a request, and has just data - > tuples array, or scalar values, or mixed. It has no any metadata. > This response type incorporates results of any pure Lua and C > calls including stored procedures, space and index methods. Such > response is single per request; > +* A response with just data, but with no request finalization - > it is so called push-message. During single request execution > multiple pushes can be sent, and they do not finalize the request > - a client must be ready to receive more responses; > +* A formatted response, that is sent on SQL DQL and does not > finalize a request. Such response contains metadata with result > set column names, types, flags etc; > +* A response with metadata only, that is sent on SQL DDL/DML > requests, and contains affected row count, last autoincrement > column value, flags; > +* A response with error message and code, that finalizes a request. > + > +In supporting this responses set 2 main challenges appear: > +1. How to unify responses; > +2. How to support multiple messages inside a single request. > + > +To understand how a single request can produce multiple > responses, consider the stored procedure (do not pay attention to > the syntax - it does not matter here): > +```SQL > +FUNCTION my_sql_func(a1, a2, a3, a4) BEGIN > +    SELECT my_lua_func(a1); > +    SELECT * FROM table1; > +    SELECT my_c_func(a2); > +    INSERT INTO table1 VALUES (1, 2, 3); > +    RETURN a4; > +END > +``` > +, where `my_lua_func()` is the function, written in Lua and > sending its own push-messages: > +```Lua > +function my_lua_func(arg) > +    box.session.push(arg) > +    return arg > +end > +``` > +and `my_c_func()` is the function, written in C and returning > some raw data: > +```C > +int > +my_c_func(box_function_ctx_t *ctx) { > +    box_tuple_t *tuple; > +    /* Fill a tuple with any data. */ > +    return box_return_tuple(ctx, tuple); > +} > +``` > +Consider each statement: > +* `SELECT FROM` can split a big result set in multiple messages; > +* `SELECT my_lua_func()` produces 2 messages: one is the > push-message generated in `my_lua_func` and another is the result > of `SELECT` itself; > +* `INSERT` creates 1 message with metadata; > +* `RETURN` creates a final response message. > + > +Of course, some of messages, or even all of them can be batched > and send as a single TCP packet, but it does not matter for the > wire protocol. > + > +In the next section it is described, how the Tarantool wire > protocol deals with this mess. > + > +For the protocol details - code values, all header and body keys > - see Tarantool [website](tarantool.io ). > + > +## Detailed design > + > +Tarantool response consists of a body and a header. Header is > used to store response code and some internal metainfo such as > schema version, request id (called **sync** in Tarantool). Body is > used to store result data and request-dependent metainfo. > + > +### Header > + > +There are 3 response codes in header: > +* `IPROTO_OK` - the last response in a request, that is finished > successfully; > +* `IPROTO_CHUNK` - non-final response. One request can generate > multuple chunk messages; > +* `IPROTO_ERROR | error code` - the last response in a request, > that is finished with an error. > + > +`IPROTO_ERROR` response is trivial, and consists just of code and > message. It is no considered further. > +`IPROTO_OK` and `IPROTO_CHUNK` have the same body format. The > only exception between them is that `IPROTO_OK` finalizes the > request. In the next subsection the body format is presented. > + > +### Body > + > +The common body structure: > +``` > ++----------------------------------------------+ > +| IPROTO_BODY: {                               | > +|     IPROTO_METADATA: [                       | > +|         {                                    | > +|             IPROTO_FIELD_NAME: string,       | > +|             IPROTO_FIELD_TYPE: number,       | > +|             IPROTO_FIELD_FLAGS: number,      | > +|         },                                   | > +|         ...                                  | > +|     ],                                       | > +|                                              | > +|     IPROTO_SQL_INFO: {                       | > +|         SQL_INFO_ROW_COUNT: number,          | > +|         SQL_INFO_LAST_ID: number,            | > +|         SQL_INFO_FLAGS: number,              | > +|         ...                                  | > +|     },                                       | > +|                                              | > +|     IPROTO_DATA: [                           | > +|         tuple/scalar,                        | > +|         ...                                  | > +|     ]                                        | > +| }                                            | > ++----------------------------------------------+ > +``` > +For a while the single `SQL_INFO_FLAGS` value is available: > `SQL_INFO_HAS_NEXT_CHUNK` - a response having this flag means, > that the current result set is not fully read - more responses are > available. For example, it could be big `SELECT FROM` sent in > multiple chunks. > + > +Consider, how different responses use the body, and how they can > be distinguished. > + > +_A non formatted response_ has only `IPROTO_DATA` key in a body. > It is the result of Lua and C DML, DDL, DQL, stored procedures > calls, push messages. Such response is never linked with next or > previous messages of the same request. > + > +_A non formatted response with metadata_ has only > `IPROTO_SQL_INFO` and it is always result of DDL/DML executed via > SQL. As well as the previous type, this response is all-independent. > + > +_A formatted response_ always has `IPROTO_DATA`, and can have > both `IPROTO_SQL_INFO` and `IPROTO_METADATA`. It is always result > of SQL DQL (`SELECT`). The response can be part of a continuous > sequence of responses. A first message of the sequence always > contains `IPROTO_METADATA`, while all non-last ones always contain > `IPROTO_SQL_INFO` with `SQL_INFO_HAS_NEXT_CHUNK` flag. The last > message has only `IPROTO_DATA` or nothing. > + > +On the picture the state machine of the protocol is showed: > +![alt > text](https://raw.githubusercontent.com/tarantool/tarantool/sql-proto-rfc/doc/RFC/wire_protocol_img1.png) > + > +For the `FUNCTION my_sql_func` call the following responses are sent: > +``` > +/* Push from my_lua_func(a1). */ > ++----------------------------------------------+ > +| HEADER: IPROTO_CHUNK                         | > ++- - - - - - - - - - - - - - - - - - - - - - - + > +| BODY: {                                      | > +|     IPROTO_DATA: [ a1 ]                      | > +| }                                            | > ++----------------------------------------------+ > + > +/* Result of SELECT my_lua_func(a1). */ > ++----------------------------------------------+ > +| HEADER: IPROTO_CHUNK                         | > ++- - - - - - - - - - - - - - - - - - - - - - - + > +| BODY: {                                      | > +|     IPROTO_DATA: [ [ a1 ] ],                 | > +|     IPROTO_METADATA: [                       | > +|         { /* field name, type ... */ }       | > +|     ]                                        | > +| }                                            | > ++----------------------------------------------+ > + > +/* First chunk of SELECT * FROM table1. */ > ++----------------------------------------------+ > +| HEADER: IPROTO_CHUNK                         | > ++- - - - - - - - - - - - - - - - - - - - - - - + > +| BODY: {                                      | > +|    IPROTO_DATA: [ tuple1, tuple2, ... ]      | > +|    IPROTO_METADATA: [                        | > +|        { /* field1 name, type ... */ },      | > +|        { /* field2 name, type ... */ },      | > +|        ...                                   | > +|    ],                                        | > +|    IPROTO_SQL_INFO: {                        | > +|        SQL_INFO_FLAGS:                       | > +|            SQL_INFO_HAS_NEXT_CHUNK           | > +|    }                                         | > +| }                                            | > ++----------------------------------------------+ > + > +        /* From second to next to last chunk. */ > +  +----------------------------------------------+ > +       | HEADER: IPROTO_CHUNK      | > +       +- - - - - - - - - - - - - - - - - - - - - - - + > +       | BODY: {     | > +       |    IPROTO_DATA: [ tuple1, tuple2, ... ],     | > +       |    IPROTO_SQL_INFO: {     | > +       |        SQL_INFO_FLAGS:      | > +       |            SQL_INFO_HAS_NEXT_CHUNK      | > +       |    }      | > +       | }     | > +  +----------------------------------------------+ > + > +       /* Last chunk. */ > +  +----------------------------------------------+ > +       | HEADER: IPROTO_CHUNK      | > +       +- - - - - - - - - - - - - - - - - - - - - - - + > +       | BODY: {     | > +       |    IPROTO_DATA: [ tuple1, tuple2, ... ]     | > +       | }     | > +  +----------------------------------------------+ > + > +/* Result of SELECT my_c_func(a2). */ > ++----------------------------------------------+ > +| HEADER: IPROTO_CHUNK                         | > ++- - - - - - - - - - - - - - - - - - - - - - - + > +| BODY: {                                      | > +|     IPROTO_DATA: [ [ tuple ] ],              | > +|     IPROTO_METADATA: [                       | > +|         { /* field name, type ... */ }       | > +|     ]                                        | > +| }                                            | > ++----------------------------------------------+ > + > +/* Result of INSERT INTO table1 VALUES (1, 2, 3). */ > ++----------------------------------------------+ > +| HEADER: IPROTO_CHUNK                         | > ++- - - - - - - - - - - - - - - - - - - - - - - + > +| BODY: {                                      | > +|     IPROTO_SQL_INFO: {                       | > +|         SQL_INFO_ROW_COUNT: number,          | > +|         SQL_INFO_LAST_ID: number,            | > +|     }                                        | > +| }                                            | > ++----------------------------------------------+ > + > +/* Result of RETURN a4 */ > ++----------------------------------------------+ > +| HEADER: IPROTO_OK                            | > ++- - - - - - - - - - - - - - - - - - - - - - - + > +| BODY: {                                      | > +|     IPROTO_DATA: [ a4 ]                      | > +| }                                            | > ++----------------------------------------------+ > +``` > -- > 2.14.3 (Apple Git-98) > > > > > -- >