diff --git a/server/core/test/CMakeLists.txt b/server/core/test/CMakeLists.txt index d74fee918..17435dcff 100644 --- a/server/core/test/CMakeLists.txt +++ b/server/core/test/CMakeLists.txt @@ -25,6 +25,7 @@ add_executable(test_trxcompare test_trxcompare.cc ../../../query_classifier/test add_executable(test_trxtracking test_trxtracking.cc) add_executable(test_users test_users.cc) add_executable(test_utils test_utils.cc) +add_executable(test_session_track test_session_track.cc) target_link_libraries(profile_trxboundaryparser maxscale-common) target_link_libraries(test_adminusers maxscale-common) @@ -53,6 +54,7 @@ target_link_libraries(test_trxcompare maxscale-common) target_link_libraries(test_trxtracking maxscale-common) target_link_libraries(test_users maxscale-common) target_link_libraries(test_utils maxscale-common) +target_link_libraries(test_session_track mysqlcommon) add_test(test_adminusers test_adminusers) add_test(test_atomic test_atomic) @@ -88,5 +90,6 @@ add_test(test_trxcompare_maxscale test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/.. add_test(test_trxtracking test_trxtracking) add_test(test_users test_users) add_test(test_utils test_utils) +add_test(test_session_track test_session_track) add_subdirectory(rest-api) diff --git a/server/core/test/test_session_track.cc b/server/core/test/test_session_track.cc new file mode 100644 index 000000000..6b30bbb33 --- /dev/null +++ b/server/core/test/test_session_track.cc @@ -0,0 +1,187 @@ + +#include +#include +#include + +#include +#include +#include + +static const uint8_t resultset1[] = +{ + /* BEGIN;*/ + 0x29, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, + 0x40, 0x00, 0x00, 0x00, 0x20, 0x05, 0x09, 0x08, + 0x54, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, + 0x04, 0x13, 0x12, 0x53, 0x54, 0x41, 0x52, 0x54, + 0x20, 0x54, 0x52, 0x41, 0x4E, 0x53, 0x41, 0x43, + 0x54, 0x49, 0x4F, 0x4E, 0x3B, + /* COMMIT;*/ + 0x17, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, + 0x40, 0x00, 0x00, 0x00, 0x0E, 0x05, 0x09, 0x08, + 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, + 0x04, 0x01, 0x00, + /* START TRANSACTION;*/ + 0x29, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, + 0x40, 0x00, 0x00, 0x00, 0x20, 0x05, 0x09, 0x08, + 0x54, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, + 0x04, 0x13, 0x12, 0x53, 0x54, 0x41, 0x52, 0x54, + 0x20, 0x54, 0x52, 0x41, 0x4E, 0x53, 0x41, 0x43, + 0x54, 0x49, 0x4F, 0x4E, 0x3B, + /* START TRANSACTION READ ONLY;*/ + 0x28, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, + 0x60, 0x00, 0x00, 0x00, 0x1F, 0x04, 0x1D, 0x1C, + 0x53, 0x54, 0x41, 0x52, 0x54, 0x20, 0x54, 0x52, + 0x41, 0x4E, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4F, + 0x4E, 0x20, 0x52, 0x45, 0x41, 0x44, 0x20, 0x4F, + 0x4E, 0x4C, 0x59, 0x3B, + /* COMMIT;*/ + 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, + /* SET AUTOCOMMIT=0;*/ + 0x1D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0F, 0x0A, + 0x61, 0x75, 0x74, 0x6F, 0x63, 0x6F, 0x6D, 0x6D, + 0x69, 0x74, 0x03, 0x4F, 0x46, 0x46, 0x02, 0x01, + 0x31, + /* INSERT INTO t1 VALUES(1);*/ + 0x14, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x40, 0x00, 0x00, 0x00, 0x0B, 0x05, 0x09, 0x08, + 0x49, 0x5F, 0x5F, 0x5F, 0x57, 0x5F, 0x5F, 0x5F, + /* COMMIT;*/ + 0x14, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x0B, 0x05, 0x09, 0x08, + 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F +}; + +#define PACKET_HDR_LEN 4 + +#define PACKET_1_IDX 0 +#define PACKET_1_LEN (PACKET_HDR_LEN + 0x29) +#define PACKET_2_IDX (PACKET_1_IDX + PACKET_1_LEN) +#define PACKET_2_LEN (PACKET_HDR_LEN + 0x17) +#define PACKET_3_IDX (PACKET_2_IDX + PACKET_2_LEN) +#define PACKET_3_LEN (PACKET_HDR_LEN + 0x29) +#define PACKET_4_IDX (PACKET_3_IDX + PACKET_3_LEN) +#define PACKET_4_LEN (PACKET_HDR_LEN + 0x28) +#define PACKET_5_IDX (PACKET_4_IDX + PACKET_4_LEN) +#define PACKET_5_LEN (PACKET_HDR_LEN + 0x07) +#define PACKET_6_IDX (PACKET_5_IDX + PACKET_5_LEN) +#define PACKET_6_LEN (PACKET_HDR_LEN + 0x1D) +#define PACKET_7_IDX (PACKET_6_IDX + PACKET_6_LEN) +#define PACKET_7_LEN (PACKET_HDR_LEN + 0x14) +#define PACKET_8_IDX (PACKET_7_IDX + PACKET_7_LEN) +#define PACKET_8_LEN (PACKET_HDR_LEN + 0x14) + +/* multi statments;*/ +static const uint8_t resultset2[] = +{ + /** + * set autocommit=0; + * create table t1(id int); + * insert into t1 select seq from seq_0_to_20; + * select '' from t1; + **/ + 0x1D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0F, 0x0A, + 0x61, 0x75, 0x74, 0x6F, 0x63, 0x6F, 0x6D, 0x6D, + 0x69, 0x74, 0x03, 0x4F, 0x46, 0x46, 0x02, 0x01, + 0x31, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x01, + 0x00, 0x15, 0x00, 0x21, 0x40, 0x00, 0x00, 0x27, + 0x52, 0x65, 0x63, 0x6F, 0x72, 0x64, 0x73, 0x3A, + 0x20, 0x32, 0x31, 0x20, 0x20, 0x44, 0x75, 0x70, + 0x6C, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x3A, + 0x20, 0x30, 0x20, 0x20, 0x57, 0x61, 0x72, 0x6E, + 0x69, 0x6E, 0x67, 0x73, 0x3A, 0x20, 0x30, 0x0B, + 0x05, 0x09, 0x08, 0x49, 0x5F, 0x52, 0x5F, 0x57, + 0x5F, 0x5F, 0x5F, 0x01, 0x00, 0x00, 0x01, 0x01, + 0x16, 0x00, 0x00, 0x02, 0x03, 0x64, 0x65, 0x66, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x21, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFD, 0x01, 0x00, 0x27, + 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, 0xFE, 0x00, + 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, + 0x01, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, + 0x06, 0x00, 0x01, 0x00, 0x00, 0x07, 0x00, 0x01, + 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x09, + 0x00, 0x01, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, + 0x00, 0x0B, 0x00, 0x01, 0x00, 0x00, 0x0C, 0x00, + 0x01, 0x00, 0x00, 0x0D, 0x00, 0x01, 0x00, 0x00, + 0x0E, 0x00, 0x01, 0x00, 0x00, 0x0F, 0x00, 0x01, + 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x11, + 0x00, 0x01, 0x00, 0x00, 0x12, 0x00, 0x01, 0x00, + 0x00, 0x13, 0x00, 0x01, 0x00, 0x00, 0x14, 0x00, + 0x01, 0x00, 0x00, 0x15, 0x00, 0x01, 0x00, 0x00, + 0x16, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00, 0x01, + 0x00, 0x00, 0x18, 0x00, 0x05, 0x00, 0x00, 0x19, + 0xFE, 0x00, 0x00, 0x21, 0x40 +}; + +/* functional test , test packet by packet */ +void test1() +{ + GWBUF *buffer; + uint32_t server_capabilities = GW_MYSQL_CAPABILITIES_SESSION_TRACK; + ss_dfprintf(stderr,"test_session_track : Functional tests.\n"); + //BEGIN + buffer = gwbuf_alloc_and_load(PACKET_1_LEN, resultset1+PACKET_1_IDX); + mxs_mysql_get_session_track_info(buffer, server_capabilities); + ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "T_______", 8) == 0); + gwbuf_free(buffer); + //COMMIT + buffer = gwbuf_alloc_and_load(PACKET_2_LEN, resultset1+PACKET_2_IDX); + mxs_mysql_get_session_track_info(buffer, server_capabilities); + ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "________", 8) == 0); + gwbuf_free(buffer); + //START TRANSACTION + buffer = gwbuf_alloc_and_load(PACKET_3_LEN, resultset1+PACKET_3_IDX); + mxs_mysql_get_session_track_info(buffer, server_capabilities); + ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "T_______", 8) == 0); + gwbuf_free(buffer); + //START TRANSACTION READ ONLY + buffer = gwbuf_alloc_and_load(PACKET_4_LEN, resultset1+PACKET_4_IDX); + mxs_mysql_get_session_track_info(buffer, server_capabilities); + ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_characteristics"), + "START TRANSACTION READ ONLY;", 28) == 0); + gwbuf_free(buffer); + //COMMIT + buffer = gwbuf_alloc_and_load(PACKET_5_LEN, resultset1+PACKET_5_IDX); + mxs_mysql_get_session_track_info(buffer, server_capabilities); + ss_dassert(gwbuf_get_property(buffer, (char *)"trx_characteristics") == NULL); + ss_dassert(gwbuf_get_property(buffer, (char *)"trx_state") == NULL); + gwbuf_free(buffer); + //SET AUTOCOMMIT=0; + buffer = gwbuf_alloc_and_load(PACKET_6_LEN, resultset1+PACKET_6_IDX); + mxs_mysql_get_session_track_info(buffer, server_capabilities); + ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"autocommit"), "OFF", 3) == 0); + gwbuf_free(buffer); + //INSERT INTO t1 VALUES(1); + buffer = gwbuf_alloc_and_load(PACKET_7_LEN, resultset1+PACKET_7_IDX); + mxs_mysql_get_session_track_info(buffer, server_capabilities); + ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "I___W___", 8) == 0); + gwbuf_free(buffer); + //COMMIT + buffer = gwbuf_alloc_and_load(PACKET_8_LEN, resultset1+PACKET_8_IDX); + mxs_mysql_get_session_track_info(buffer, server_capabilities); + ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "________", 8) == 0); + gwbuf_free(buffer); +} + +/* multi results combine in one buffer, test for check boundary handle properly */ +void test2() +{ + GWBUF *buffer; + uint32_t server_capabilities = GW_MYSQL_CAPABILITIES_SESSION_TRACK; + ss_dfprintf(stderr, "test_session_track : multi results test\n"); + buffer = gwbuf_alloc_and_load(sizeof(resultset2), resultset2); + mxs_mysql_get_session_track_info(buffer, server_capabilities); + ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "I_R_W___", 8) == 0); + gwbuf_free(buffer); +} + +int main(int argc, char **argv) +{ + test1(); + test2(); + return 0; +} \ No newline at end of file diff --git a/server/modules/protocol/MySQL/mysql_common.cc b/server/modules/protocol/MySQL/mysql_common.cc index 9ae9fcf59..daea29fa8 100644 --- a/server/modules/protocol/MySQL/mysql_common.cc +++ b/server/modules/protocol/MySQL/mysql_common.cc @@ -1769,27 +1769,21 @@ void mxs_mysql_execute_kill_user(MXS_SESSION* issuer, const char* user, kill_typ } /** - * Decode ok packet and get session track info - * - * @param buffer Buffer contain ok packet - * @param server_capabilities Server capabilities - * + * Parse ok packet to get session track info, save to buff properties + * @param buff Buffer contain multi compelte packets + * @param packet_offset Ok packet offset in this buff + * @param packet_len Ok packet lengh */ -void mxs_mysql_get_session_track_info(GWBUF *buff, uint32_t server_capabilities) +void mxs_mysql_parse_ok_packet(GWBUF *buff, + size_t packet_offset, + size_t packet_len, + uint32_t server_capabilities) { - ss_dassert(buff); - char *trx_info, *var_name, *var_value; - size_t len = GWBUF_LENGTH(buff); - uint8_t local_buf[len]; + uint8_t local_buf[packet_len]; uint8_t *ptr = local_buf; - - if (len < MYSQL_OK_PACKET_MIN_LEN || !mxs_mysql_is_ok_packet(buff)) - { - return; - } + char *trx_info, *var_name, *var_value; - gwbuf_copy_data(buff, 0, len, local_buf); - buff->gwbuf_type |= GWBUF_TYPE_REPLY_OK; + gwbuf_copy_data(buff, packet_offset, packet_len, local_buf); ptr += (MYSQL_HEADER_LEN + 1); // Header and Command type mxs_leint_consume(&ptr); // Affected rows mxs_leint_consume(&ptr); // Last insert-id @@ -1799,15 +1793,19 @@ void mxs_mysql_get_session_track_info(GWBUF *buff, uint32_t server_capabilities) if (server_capabilities & GW_MYSQL_CAPABILITIES_SESSION_TRACK) { - if (ptr < (local_buf + len)) + if (ptr < (local_buf + packet_len)) { ptr += mxs_leint_consume(&ptr); // info if (server_status & SERVER_SESSION_STATE_CHANGED) { mxs_leint_consume(&ptr); // total SERVER_SESSION_STATE_CHANGED length - while (ptr < (local_buf + len)) + while (ptr < (local_buf + packet_len)) { - enum_session_state_type type = (enum enum_session_state_type)mxs_leint_consume(&ptr); + 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); +#endif switch (type) { case SESSION_TRACK_STATE_CHANGE: @@ -1849,6 +1847,29 @@ void mxs_mysql_get_session_track_info(GWBUF *buff, uint32_t server_capabilities) } } +/** + * Check every packet type, if is ok packet then parse it + * @param buff Buffer contain multi compelte packets + * @param server_capabilities Server capabilities + */ +void mxs_mysql_get_session_track_info(GWBUF *buff, uint32_t server_capabilities) +{ + 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)) + { + 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) + { + buff->gwbuf_type |= GWBUF_TYPE_REPLY_OK; + mxs_mysql_parse_ok_packet(buff, offset, packet_len, server_capabilities); + } + offset += packet_len; + } +} + /*** * As described in https://dev.mysql.com/worklog/task/?id=6631 * When session transation state changed