New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MXS-1603: get session transation state from backend via session track mechanism #158
Conversation
cmake/BuildMariaDBConnector.cmake
Outdated
| @@ -9,7 +9,7 @@ set(MARIADB_CONNECTOR_C_REPO "https://github.com/MariaDB/mariadb-connector-c.git | |||
| CACHE STRING "MariaDB Connector-C Git repository") | |||
|
|
|||
| # Release 2.3.3 (preliminary) of the Connector-C | |||
| set(MARIADB_CONNECTOR_C_TAG "v3.0.2" | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://jira.mariadb.org/browse/MDEV-14647 this bug will lead monitor crash so current need master version
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bug is fixed but not yet released. Once the next Connector-C 3.0 version is released, this should be updated.
I suggest that this change is reverted and only updated once we know the tag.
cmake/BuildMariaDBConnector.cmake
Outdated
| @@ -9,7 +9,7 @@ set(MARIADB_CONNECTOR_C_REPO "https://github.com/MariaDB/mariadb-connector-c.git | |||
| CACHE STRING "MariaDB Connector-C Git repository") | |||
|
|
|||
| # Release 2.3.3 (preliminary) of the Connector-C | |||
| set(MARIADB_CONNECTOR_C_TAG "v3.0.2" | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bug is fixed but not yet released. Once the next Connector-C 3.0 version is released, this should be updated.
I suggest that this change is reverted and only updated once we know the tag.
server/core/config.cc
Outdated
| @@ -233,6 +234,7 @@ const char *config_listener_params[] = | |||
| CN_SSL_VERSION, | |||
| CN_SSL_CERT_VERIFY_DEPTH, | |||
| CN_SSL_VERIFY_PEER_CERTIFICATE, | |||
| CN_SESSION_TRACK_TRX_STATE, | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be set as a service parameter. Then the DCB and Listener would not have to be modified.
The listeners are a lower level object that are intended to represent a network socket. Services define higher level attributes so the transaction tracking should be put there.
| @@ -411,6 +411,11 @@ int MySQLSendHandshake(DCB* dcb) | |||
| */ | |||
| int gw_MySQLWrite_client(DCB *dcb, GWBUF *queue) | |||
| { | |||
| MySQLProtocol *protocol = DCB_PROTOCOL(dcb, MySQLProtocol); | |||
| if (GWBUF_IS_REPLY_OK(queue) && protocol->session_track_trx_state) | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The DCB has a service pointer which can be used to access the service parameters. Storing the session_track_trx_state in the service would make this easier.
| @@ -1279,6 +1285,9 @@ int gw_MySQLAccept(DCB *listener) | |||
| while ((client_dcb = dcb_accept(listener)) != NULL) | |||
| { | |||
| gw_process_one_new_client(client_dcb); | |||
| cli_proto = DCB_PROTOCOL(client_dcb, MySQLProtocol); | |||
| listener_proto = (SERV_LISTENER *)listener->listener; | |||
| cli_proto->session_track_trx_state = listener_proto->session_track_trx_state; | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be removed if the parameter is stored in the service.
|
|
||
| // get capabilities part 2 (2 bytes) | ||
| memcpy(&capab_ptr[2], &mysql_server_capabilities_two, 2); | ||
| conn->server_capabilities = mysql_server_capabilities_one | mysql_server_capabilities_two << 16; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although this is better than the original, we try to avoid doing unrelated changes when they are not required. Please remove this change and submit it in a separate commit and pull request.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
server_capabilities is needed in function mxs_mysql_get_session_track_info to determine whether the server support extended ok packet;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, this was my mistake. I didn't realize that the capab_ptr was not used for anything. This looks good now.
|
|
||
| uint8_t* ptr = GWBUF_DATA(buff); | ||
|
|
||
| ptr += (MYSQL_COM_OFFSET + 1); // Header and Command type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the MYSQL_HEADER_LEN macro from <maxscale/protocol/mysql.h>, this is what is used elsewhere.
|
|
||
| if (server_capabilities & GW_MYSQL_CAPABILITIES_SESSION_TRACK) | ||
| { | ||
| if (ptr < buff->end) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MaxScale code style places the opening curly brace on the next line.
| mysql_tx_state_t parse_trx_state(char *str) | ||
| { | ||
| int s = TX_EMPTY; | ||
| assert(str); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use ss_dassert from <maxscale/debug.h>
| } while(*(str++) != 0); | ||
|
|
||
| return (mysql_tx_state_t)s; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add newline at end of file.
| { | ||
| switch (*str) | ||
| { | ||
| case 'T': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these documented somewhere? If so, add a comment and a link to the documentation or document the meaning of these here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tell Beyonce come get me
| { | ||
| session_set_trx_state(ses, SESSION_TRX_INACTIVE); | ||
| } | ||
| else if(s & TX_READ_TRX) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space between if and (.
| { | ||
| session_set_trx_state(ses, SESSION_TRX_READ_WRITE); | ||
| } | ||
| else if((s & TX_EXPLICIT) | (s & TX_IMPLICIT)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As it's a logical comparison || would be more appropriate.
| } | ||
| } | ||
|
|
||
| mysql_tx_state_t parse_trx_state(char *str) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const char*
|
I have manually tested following cases, get the result from debug log (server/modules/protocol/MySQL/mariadbclient/mysql_client.cc:1953) case1:
case2:
case3:
case4:
case5:
##config [MySQL Monitor] [RwSplitRouter] [RwSplit Listener] [server1] [server2] ##my.cnf add these twosession_track_state_change = on |
… wrong state mapping
| @@ -1798,13 +1798,13 @@ void mxs_mysql_get_session_track_info(GWBUF *buff, uint32_t server_capabilities) | |||
|
|
|||
| if (server_capabilities & GW_MYSQL_CAPABILITIES_SESSION_TRACK) | |||
| { | |||
| if (ptr < buff->end) | |||
| if (ptr < (local_buf+len)) | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space on both sides of binary operator.
local_buff + len
|
I think that scanning the debug log would be an OK solution for a test case implementation. It's somewhat hard to unit test code that is inside the protocol modules. |
| * As described in https://dev.mysql.com/worklog/task/?id=6631 | ||
| * When session transation state changed | ||
| * SESSION_TRACK_TRANSACTION_TYPE (or SESSION_TRACK_TRANSACTION_STATE in MySQL) will | ||
| * return an 8 bytes string to indicate the transaction state details |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it would be OK to refer to that document and add the following excerpt from it:
The following states may be signaled:
Place 1: Transaction.
T explicitly started transaction ongoing
I implicitly started transaction (@autocommit=0) ongoing
_ no active transaction
Place 2: unsafe read
r one/several non-transactional tables were read
in the context of the current transaction
_ no non-transactional tables were read within
the current transaction so far
Place 3: transactional read
R one/several transactional tables were read
_ no transactional tables were read yet
Place 4: unsafe write
w one/several non-transactional tables were written
_ no non-transactional tables were written yet
Place 5: transactional write
W one/several transactional tables were written to
_ no transactional tables were written to yet
Place 6: unsafe statements
s one/several unsafe statements (such as UUID())
were used.
_ no such statements were used yet.
Place 7: result-set
S a result set was sent to the client
_ statement had no result-set
Place 8: LOCKed TABLES
L tables were explicitly locked using LOCK TABLES
_ LOCK TABLES is not active in this session
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
|
As is required by our contribution policy, please indicate that you submit this pull request under BSD-new by posting a comment with the following text:
|
|
I am contributing the new code of the whole pull request, including one or several files that are either new files or modified ones, under the BSD-new license. |
|
Executing the following SQL through readwritesplit seems to hang with this patch applied: create table t1(id int);
insert into t1 select seq from seq_0_to_10000;
select '' from t1;The log contains the following warning: |
|
Hi markus, could you give more detail about the problem, I cannot recurrent it with mysql 5.7 and mariadb 10.2 |
|
Seems that a non-OK packet interpreted as an OK packet which causes a debug assertion to be hit. This was spotted when we ran our test suite on the patched code but right now I can't think of a consistent way to reproduce it. Another problem is that the server can send multiple packets at once and the code only checks whether the first packet is an OK packet (this happens when MULTI_RESULTS capability is in use). This is why I suggested moving the call to |
|
THX, I know where is wrong now, I taken the output of modutil_get_complete_packets as a single packet, so in mxs_mysql_get_session_track_info the packets after ok packet be treated as ok packet's session track info; because need server_capablitities to decode ok packet, cannot move mxs_mysql_get_session_track_info into modutil_get_complete_packets, I have tried get server_capablitities from this way "((MysqlProtocol *)buff->server->protocol)->server_capabilities, but it not works, so I keep mxs_mysql_get_session_track_info behind mxs_mysql_get_session_track_info; |
|
imitate test_modutil.c write a ut for session_track; |
| enum_session_state_type type = | ||
| (enum enum_session_state_type)mxs_leint_consume(&ptr); | ||
| #if defined(SS_DEBUG) | ||
| ss_dassert(type <= SESSION_TRACK_TRANSACTION_TYPE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for test
| ptr += 2; // status | ||
| ptr += 2; // number of warnings | ||
|
|
||
| if (server_capabilities & GW_MYSQL_CAPABILITIES_SESSION_TRACK) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be moved before the while loop in mxs_mysql_get_session_track_info so that if the server doesn't support the capability, the code won't be executed.
| size_t offset = 0; | ||
| uint8_t header_and_command[MYSQL_HEADER_LEN+1]; | ||
|
|
||
| while(gwbuf_copy_data(buff, offset, MYSQL_HEADER_LEN+1, header_and_command) == (MYSQL_HEADER_LEN+1)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space between while and (. The MaxScale style guide can be found here.
| { | ||
| size_t packet_len = gw_mysql_get_byte3(header_and_command) + MYSQL_HEADER_LEN; | ||
| uint8_t cmd = header_and_command[MYSQL_COM_OFFSET]; | ||
| if (packet_len > MYSQL_OK_PACKET_MIN_LEN && cmd == MYSQL_REPLY_OK) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The following set of SQL statements should cause a false positive to be triggered.
CREATE TABLE t1(a VARCHAR(20), b INT, c INT, d INT);
INSERT INTO t1 VALUES ('', 100, 200, 300);
SELECT * FROM t1;The result set row will be wrongly interpreted due to the fact that the MariaDB protocol is stateful. To work around this, the number of EOF packets could be tracked inside the protocol object stored in the DCB. To see whether a result set is in progress, we can just check if num_eof_packets % 2 == 0.
| proto.num_eof_packets = 0; | ||
| ss_dfprintf(stderr,"test_session_track : Functional tests.\n"); | ||
| //BEGIN | ||
| buffer = gwbuf_alloc_and_load(PACKET_1_LEN, resultset1+PACKET_1_IDX); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space around binary operators.
...resultset1 + PACKET_1_IDX...
| uint8_t header_and_command[MYSQL_HEADER_LEN+1]; | ||
| if (proto->server_capabilities & GW_MYSQL_CAPABILITIES_SESSION_TRACK) | ||
| { | ||
| while (gwbuf_copy_data(buff, offset, MYSQL_HEADER_LEN+1, header_and_command) == (MYSQL_HEADER_LEN+1)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space around binary operators. Please fix all places.
include/maxscale/protocol/mysql.h
Outdated
| @@ -339,6 +353,7 @@ typedef struct | |||
| int ignore_replies; /*< How many replies should be discarded */ | |||
| GWBUF* stored_query; /*< Temporarily stored queries */ | |||
| bool collect_result; /*< Collect the next result set as one buffer */ | |||
| uint32_t num_eof_packets; /*< Signal number to indicate is current packet is ok packet*/ | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment is a bit unclear. What is "signal" here?
|
Thanks for all your patience, currently the develop branch build failed on 'qlafilter.cc:1169:64: error: cannot pass objects of non-trivially-copyable type', so this pr also failed; I tested for my local branch, passed all test; |
|
Ah, that would be caused by something we did. I think the pull request is OK and we'll begin merging it into the We would like to thank you for contributing to the MaxScale project, it's really nice to see that external contributions work well. |
|
@ybbct I've merged the pull request into develop. I also realized that there's no documentation for the feature. If you could create a new pull request that adds a short description of what the parameter does into the configuration guide, we would really appreciate it. |
parse session track info( autocommit and transaction state) from ok packet in mysql_backend, and save it to gwbuf property;
when reply to client in mysql_client, mapping all the information provided by session track info to mxs_session_trx_state_t
add config parameter to enable/disable this behavior