Merge remote-tracking branch 'ybbct/MXS-1603' into develop
This commit is contained in:
commit
fe73458d65
@ -59,6 +59,7 @@ typedef enum
|
||||
GWBUF_TYPE_IGNORABLE = 0x10,
|
||||
GWBUF_TYPE_COLLECT_RESULT = 0x20,
|
||||
GWBUF_TYPE_RESULT = 0x40,
|
||||
GWBUF_TYPE_REPLY_OK = 0x80,
|
||||
} gwbuf_type_t;
|
||||
|
||||
#define GWBUF_IS_TYPE_UNDEFINED(b) (b->gwbuf_type == 0)
|
||||
@ -68,6 +69,7 @@ typedef enum
|
||||
#define GWBUF_IS_IGNORABLE(b) (b->gwbuf_type & GWBUF_TYPE_IGNORABLE)
|
||||
#define GWBUF_IS_COLLECTED_RESULT(b) (b->gwbuf_type & GWBUF_TYPE_RESULT)
|
||||
#define GWBUF_SHOULD_COLLECT_RESULT(b) (b->gwbuf_type & GWBUF_TYPE_COLLECT_RESULT)
|
||||
#define GWBUF_IS_REPLY_OK(b) (b->gwbuf_type & GWBUF_TYPE_REPLY_OK)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
@ -118,6 +118,20 @@ MXS_BEGIN_DECLS
|
||||
#define COM_QUIT_PACKET_SIZE (4+1)
|
||||
struct dcb;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TX_EMPTY = 0, ///< "none of the below"
|
||||
TX_EXPLICIT = 1, ///< an explicit transaction is active
|
||||
TX_IMPLICIT = 2, ///< an implicit transaction is active
|
||||
TX_READ_TRX = 4, ///< transactional reads were done
|
||||
TX_READ_UNSAFE = 8, ///< non-transaction reads were done
|
||||
TX_WRITE_TRX = 16, ///< transactional writes were done
|
||||
TX_WRITE_UNSAFE = 32, ///< non-transactional writes were done
|
||||
TX_STMT_UNSAFE = 64, ///< "unsafe" (non-deterministic like UUID()) stmts
|
||||
TX_RESULT_SET = 128, ///< result-set was sent
|
||||
TX_WITH_SNAPSHOT= 256, ///< WITH CONSISTENT SNAPSHOT was used
|
||||
TX_LOCKED_TABLES= 512 ///< LOCK TABLES is active
|
||||
} mysql_tx_state_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@ -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; /*< Encountered eof packet number, used for check packet type */
|
||||
#if defined(SS_DEBUG)
|
||||
skygw_chk_t protocol_chk_tail;
|
||||
#endif
|
||||
@ -478,6 +493,8 @@ char* create_auth_fail_str(char *username, char *hostaddr, bool password, char *
|
||||
void init_response_status(GWBUF* buf, uint8_t cmd, int* npackets, size_t* nbytes);
|
||||
bool read_complete_packet(DCB *dcb, GWBUF **readbuf);
|
||||
bool gw_get_shared_session_auth_info(DCB* dcb, MYSQL_session* session);
|
||||
void mxs_mysql_get_session_track_info(GWBUF *buff, MySQLProtocol *proto);
|
||||
mysql_tx_state_t parse_trx_state(const char *str);
|
||||
|
||||
/**
|
||||
* Decode server handshake
|
||||
|
@ -158,6 +158,7 @@ typedef struct service
|
||||
bool log_auth_warnings; /**< Log authentication failures and warnings */
|
||||
uint64_t capabilities; /**< The capabilities of the service, @see enum routing_capability */
|
||||
int max_retry_interval; /**< Maximum retry interval */
|
||||
bool session_track_trx_state; /**< Get transaction state via session track mechanism */
|
||||
} SERVICE;
|
||||
|
||||
typedef enum count_spec_t
|
||||
|
@ -147,6 +147,7 @@ const char CN_USER[] = "user";
|
||||
const char CN_USERS[] = "users";
|
||||
const char CN_VERSION_STRING[] = "version_string";
|
||||
const char CN_WEIGHTBY[] = "weightby";
|
||||
const char CN_SESSION_TRACK_TRX_STATE[] = "session_track_trx_state";
|
||||
|
||||
typedef struct duplicate_context
|
||||
{
|
||||
@ -213,6 +214,7 @@ const char *config_service_params[] =
|
||||
CN_WEIGHTBY,
|
||||
CN_LOG_AUTH_WARNINGS,
|
||||
CN_RETRY_ON_FAILURE,
|
||||
CN_SESSION_TRACK_TRX_STATE,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -2886,7 +2888,7 @@ int create_new_service(CONFIG_CONTEXT *obj)
|
||||
serviceSetVersionString(service, gateway.version_string);
|
||||
}
|
||||
|
||||
|
||||
service->session_track_trx_state = config_get_bool(obj->parameters, CN_SESSION_TRACK_TRX_STATE);
|
||||
/** Store the configuration parameters for the service */
|
||||
const MXS_MODULE *mod = get_module(router, MODULE_ROUTER);
|
||||
|
||||
|
@ -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)
|
||||
|
249
server/core/test/test_session_track.cc
Normal file
249
server/core/test/test_session_track.cc
Normal file
@ -0,0 +1,249 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <maxscale/alloc.h>
|
||||
#include <maxscale/buffer.h>
|
||||
#include <maxscale/protocol/mysql.h>
|
||||
|
||||
MySQLProtocol proto;
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
/**
|
||||
* SET AUTOCOMMIT=0;
|
||||
* CREATE TABLE t1(a VARCHAR(20), b INT, c INT, d INT);
|
||||
* INSERT INTO t1 VALUES ('', 100, 200, 300);
|
||||
* SELECT * FROM t1;
|
||||
**/
|
||||
static const uint8_t resultset3[] =
|
||||
{
|
||||
0x28, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
|
||||
0x40, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x0F, 0x0A,
|
||||
0x61, 0x75, 0x74, 0x6F, 0x63, 0x6F, 0x6D, 0x6D,
|
||||
0x69, 0x74, 0x03, 0x4F, 0x46, 0x46, 0x02, 0x01,
|
||||
0x31, 0x05, 0x09, 0x08, 0x49, 0x5F, 0x52, 0x5F,
|
||||
0x5F, 0x5F, 0x53, 0x5F, 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,
|
||||
0x14, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
|
||||
0x40, 0x00, 0x00, 0x00, 0x0B, 0x05, 0x09, 0x08,
|
||||
0x49, 0x5F, 0x5F, 0x5F, 0x57, 0x5F, 0x5F, 0x5F,
|
||||
0x01, 0x00, 0x00, 0x01, 0x04, 0x20, 0x00, 0x00,
|
||||
0x02, 0x03, 0x64, 0x65, 0x66, 0x04, 0x74, 0x65,
|
||||
0x73, 0x74, 0x02, 0x74, 0x31, 0x02, 0x74, 0x31,
|
||||
0x01, 0x61, 0x01, 0x61, 0x0C, 0x21, 0x00, 0x3C,
|
||||
0x00, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x00, 0x03, 0x03, 0x64, 0x65,
|
||||
0x66, 0x04, 0x74, 0x65, 0x73, 0x74, 0x02, 0x74,
|
||||
0x31, 0x02, 0x74, 0x31, 0x01, 0x62, 0x01, 0x62,
|
||||
0x0C, 0x3F, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
|
||||
0x04, 0x03, 0x64, 0x65, 0x66, 0x04, 0x74, 0x65,
|
||||
0x73, 0x74, 0x02, 0x74, 0x31, 0x02, 0x74, 0x31,
|
||||
0x01, 0x63, 0x01, 0x63, 0x0C, 0x3F, 0x00, 0x0B,
|
||||
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x00, 0x05, 0x03, 0x64, 0x65,
|
||||
0x66, 0x04, 0x74, 0x65, 0x73, 0x74, 0x02, 0x74,
|
||||
0x31, 0x02, 0x74, 0x31, 0x01, 0x64, 0x01, 0x64,
|
||||
0x0C, 0x3F, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
|
||||
0x06, 0xFE, 0x00, 0x00, 0x21, 0x00, 0x05, 0x00,
|
||||
0x00, 0x07, 0xFE, 0x00, 0x00, 0x21, 0x00
|
||||
};
|
||||
|
||||
/* functional test , test packet by packet */
|
||||
void test1()
|
||||
{
|
||||
GWBUF *buffer;
|
||||
proto.server_capabilities = GW_MYSQL_CAPABILITIES_SESSION_TRACK;
|
||||
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);
|
||||
mxs_mysql_get_session_track_info(buffer, &proto);
|
||||
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, &proto);
|
||||
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, &proto);
|
||||
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, &proto);
|
||||
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, &proto);
|
||||
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, &proto);
|
||||
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, &proto);
|
||||
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, &proto);
|
||||
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;
|
||||
ss_dfprintf(stderr, "test_session_track: multi results test\n");
|
||||
proto.server_capabilities = GW_MYSQL_CAPABILITIES_SESSION_TRACK;
|
||||
proto.num_eof_packets = 0;
|
||||
buffer = gwbuf_alloc_and_load(sizeof(resultset2), resultset2);
|
||||
mxs_mysql_get_session_track_info(buffer, &proto);
|
||||
ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "I_R_W___", 8) == 0);
|
||||
gwbuf_free(buffer);
|
||||
}
|
||||
|
||||
void test3()
|
||||
{
|
||||
GWBUF *buffer;
|
||||
proto.server_capabilities = GW_MYSQL_CAPABILITIES_SESSION_TRACK;
|
||||
proto.num_eof_packets = 0;
|
||||
ss_dfprintf(stderr, "test_session_track: protocol state test\n");
|
||||
buffer = gwbuf_alloc_and_load(sizeof(resultset2), resultset2);
|
||||
mxs_mysql_get_session_track_info(buffer, &proto);
|
||||
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();
|
||||
test3();
|
||||
return 0;
|
||||
}
|
@ -770,6 +770,9 @@ gw_read_and_write(DCB *dcb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Get sesion track info from ok packet and save it to gwbuf properties */
|
||||
mxs_mysql_get_session_track_info(tmp, proto);
|
||||
|
||||
read_buffer = tmp;
|
||||
|
||||
if (rcap_type_required(capabilities, RCAP_TYPE_CONTIGUOUS_OUTPUT) ||
|
||||
|
@ -76,7 +76,7 @@ static spec_com_res_t process_special_commands(DCB *client_dcb, GWBUF *read_buff
|
||||
static spec_com_res_t handle_query_kill(DCB* dcb, GWBUF* read_buffer, spec_com_res_t current,
|
||||
bool is_complete, unsigned int packet_len);
|
||||
static bool parse_kill_query(char *query, uint64_t *thread_id_out, kill_type_t *kt_out, std::string* user);
|
||||
|
||||
static void parse_and_set_trx_state(MXS_SESSION *ses, GWBUF *data);
|
||||
/**
|
||||
* The module entry point routine. It is this routine that
|
||||
* must populate the structure that is referred to as the
|
||||
@ -410,7 +410,11 @@ int MySQLSendHandshake(DCB* dcb)
|
||||
* @param queue Queue of buffers to write
|
||||
*/
|
||||
int gw_MySQLWrite_client(DCB *dcb, GWBUF *queue)
|
||||
{
|
||||
{
|
||||
if (GWBUF_IS_REPLY_OK(queue) && dcb->service->session_track_trx_state)
|
||||
{
|
||||
parse_and_set_trx_state(dcb->session, queue);
|
||||
}
|
||||
return dcb_write(dcb, queue);
|
||||
}
|
||||
|
||||
@ -1266,7 +1270,6 @@ int gw_MySQLListener(DCB *listen_dcb, char *config_bind)
|
||||
int gw_MySQLAccept(DCB *listener)
|
||||
{
|
||||
DCB *client_dcb;
|
||||
MySQLProtocol *protocol;
|
||||
|
||||
CHK_DCB(listener);
|
||||
|
||||
@ -1509,8 +1512,8 @@ static int route_by_statement(MXS_SESSION* session, uint64_t capabilities, GWBUF
|
||||
goto return_rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (rcap_type_required(capabilities, RCAP_TYPE_TRANSACTION_TRACKING))
|
||||
SERVICE *service = session->client_dcb->service;
|
||||
if (rcap_type_required(capabilities, RCAP_TYPE_TRANSACTION_TRACKING) && !service->session_track_trx_state)
|
||||
{
|
||||
if (session_trx_is_ending(session))
|
||||
{
|
||||
@ -1889,3 +1892,64 @@ static bool parse_kill_query(char *query, uint64_t *thread_id_out, kill_type_t *
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Mapping three session tracker's info to mxs_session_trx_state_t
|
||||
* SESSION_TRACK_STATE_CHANGE:
|
||||
* Get lasted autocommit value;
|
||||
* https://dev.mysql.com/worklog/task/?id=6885
|
||||
* SESSION_TRACK_TRANSACTION_TYPE:
|
||||
* Get transaction boundaries
|
||||
* TX_EMPTY => SESSION_TRX_INACTIVE
|
||||
* TX_EXPLICIT | TX_IMPLICIT => SESSION_TRX_ACTIVE
|
||||
* https://dev.mysql.com/worklog/task/?id=6885
|
||||
* SESSION_TRACK_TRANSACTION_CHARACTERISTICS
|
||||
* Get trx characteristics such as read only, read write, snapshot ...
|
||||
*
|
||||
*/
|
||||
static void parse_and_set_trx_state(MXS_SESSION *ses, GWBUF *data)
|
||||
{
|
||||
char *autocommit = gwbuf_get_property(data, (char *)"autocommit");
|
||||
|
||||
if (autocommit)
|
||||
{
|
||||
MXS_DEBUG("autocommit:%s", autocommit);
|
||||
if (strncasecmp(autocommit, "ON", 2) == 0)
|
||||
{
|
||||
session_set_autocommit(ses, true);
|
||||
}
|
||||
if (strncasecmp(autocommit, "OFF", 3) == 0)
|
||||
{
|
||||
session_set_autocommit(ses, false);
|
||||
}
|
||||
}
|
||||
char *trx_state = gwbuf_get_property(data, (char *)"trx_state");
|
||||
if (trx_state)
|
||||
{
|
||||
mysql_tx_state_t s = parse_trx_state(trx_state);
|
||||
|
||||
if (s == TX_EMPTY)
|
||||
{
|
||||
session_set_trx_state(ses, SESSION_TRX_INACTIVE);
|
||||
}
|
||||
else if ((s & TX_EXPLICIT) || (s & TX_IMPLICIT))
|
||||
{
|
||||
session_set_trx_state(ses, SESSION_TRX_ACTIVE);
|
||||
}
|
||||
}
|
||||
char *trx_characteristics = gwbuf_get_property(data, (char *)"trx_characteristics");
|
||||
if (trx_characteristics)
|
||||
{
|
||||
if (strncmp(trx_characteristics, "START TRANSACTION READ ONLY;", 28) == 0)
|
||||
{
|
||||
session_set_trx_state(ses, SESSION_TRX_READ_ONLY);
|
||||
}
|
||||
|
||||
if (strncmp(trx_characteristics, "START TRANSACTION READ WRITE;", 29) == 0)
|
||||
{
|
||||
session_set_trx_state(ses, SESSION_TRX_READ_WRITE);
|
||||
}
|
||||
}
|
||||
MXS_DEBUG("trx state:%s", session_trx_state_to_string(ses->trx_state));
|
||||
MXS_DEBUG("autcommit:%s", session_is_autocommit(ses)?"ON":"OFF");
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ MySQLProtocol* mysql_protocol_init(DCB* dcb, int fd)
|
||||
p->extra_capabilities = 0;
|
||||
p->ignore_replies = 0;
|
||||
p->collect_result = false;
|
||||
p->num_eof_packets = 0;
|
||||
#if defined(SS_DEBUG)
|
||||
p->protocol_chk_top = CHK_NUM_PROTOCOL;
|
||||
p->protocol_chk_tail = CHK_NUM_PROTOCOL;
|
||||
@ -1228,6 +1229,8 @@ create_capabilities(MySQLProtocol *conn, bool with_ssl, bool db_specified, bool
|
||||
/* Maybe it should depend on whether CA certificate is provided */
|
||||
/* final_capabilities |= (uint32_t)GW_MYSQL_CAPABILITIES_SSL_VERIFY_SERVER_CERT; */
|
||||
}
|
||||
/** add session track */
|
||||
final_capabilities |= (uint32_t)GW_MYSQL_CAPABILITIES_SESSION_TRACK;
|
||||
|
||||
/* Compression is not currently supported */
|
||||
ss_dassert(!compress);
|
||||
@ -1459,10 +1462,7 @@ int gw_decode_mysql_server_handshake(MySQLProtocol *conn, uint8_t *payload)
|
||||
|
||||
mysql_server_capabilities_two = gw_mysql_get_byte2(payload);
|
||||
|
||||
memcpy(capab_ptr, &mysql_server_capabilities_one, 2);
|
||||
|
||||
// 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;
|
||||
|
||||
// 2 bytes shift
|
||||
payload += 2;
|
||||
@ -1768,3 +1768,197 @@ void mxs_mysql_execute_kill_user(MXS_SESSION* issuer, const char* user, kill_typ
|
||||
|
||||
mxs_mysql_send_ok(issuer->client_dcb, info.targets.size(), 0, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_parse_ok_packet(GWBUF *buff, size_t packet_offset, size_t packet_len)
|
||||
{
|
||||
uint8_t local_buf[packet_len];
|
||||
uint8_t *ptr = local_buf;
|
||||
char *trx_info, *var_name, *var_value;
|
||||
|
||||
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
|
||||
uint16_t server_status = gw_mysql_get_byte2(ptr);
|
||||
ptr += 2; // status
|
||||
ptr += 2; // number of warnings
|
||||
|
||||
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 + packet_len))
|
||||
{
|
||||
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:
|
||||
case SESSION_TRACK_SCHEMA:
|
||||
case SESSION_TRACK_GTIDS:
|
||||
ptr += mxs_leint_consume(&ptr);
|
||||
break;
|
||||
case SESSION_TRACK_TRANSACTION_CHARACTERISTICS:
|
||||
mxs_leint_consume(&ptr); //length
|
||||
var_value = mxs_lestr_consume_dup(&ptr);
|
||||
gwbuf_add_property(buff, (char *)"trx_characteristics", var_value);
|
||||
MXS_FREE(var_value);
|
||||
break;
|
||||
case SESSION_TRACK_SYSTEM_VARIABLES:
|
||||
mxs_leint_consume(&ptr); //lenth
|
||||
// system variables like autocommit, schema, charset ...
|
||||
var_name = mxs_lestr_consume_dup(&ptr);
|
||||
var_value = mxs_lestr_consume_dup(&ptr);
|
||||
gwbuf_add_property(buff, var_name, var_value);
|
||||
MXS_DEBUG("SESSION_TRACK_SYSTEM_VARIABLES, name:%s, value:%s", var_name, var_value);
|
||||
MXS_FREE(var_name);
|
||||
MXS_FREE(var_value);
|
||||
break;
|
||||
case SESSION_TRACK_TRANSACTION_TYPE:
|
||||
mxs_leint_consume(&ptr); // length
|
||||
trx_info = mxs_lestr_consume_dup(&ptr);
|
||||
MXS_DEBUG("get trx_info:%s", trx_info);
|
||||
gwbuf_add_property(buff, (char *)"trx_state", trx_info);
|
||||
MXS_FREE(trx_info);
|
||||
break;
|
||||
default:
|
||||
ptr += mxs_leint_consume(&ptr);
|
||||
MXS_WARNING("recieved unexpecting session track type:%d", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, MySQLProtocol *proto)
|
||||
{
|
||||
size_t offset = 0;
|
||||
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))
|
||||
{
|
||||
size_t packet_len = gw_mysql_get_byte3(header_and_command);
|
||||
uint8_t cmd = header_and_command[MYSQL_COM_OFFSET];
|
||||
|
||||
if (packet_len > MYSQL_OK_PACKET_MIN_LEN &&
|
||||
cmd == MYSQL_REPLY_OK &&
|
||||
(proto->num_eof_packets % 2) == 0)
|
||||
{
|
||||
buff->gwbuf_type |= GWBUF_TYPE_REPLY_OK;
|
||||
mxs_mysql_parse_ok_packet(buff, offset, packet_len + MYSQL_HEADER_LEN);
|
||||
}
|
||||
|
||||
if ((proto->current_command == MXS_COM_QUERY ||
|
||||
proto->current_command == MXS_COM_STMT_FETCH ||
|
||||
proto->current_command == MXS_COM_STMT_EXECUTE) &&
|
||||
cmd == MYSQL_REPLY_EOF)
|
||||
{
|
||||
proto->num_eof_packets++;
|
||||
}
|
||||
offset += (packet_len + MYSQL_HEADER_LEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 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
|
||||
* 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
|
||||
* */
|
||||
mysql_tx_state_t parse_trx_state(const char *str)
|
||||
{
|
||||
int s = TX_EMPTY;
|
||||
ss_dassert(str);
|
||||
do
|
||||
{
|
||||
switch (*str)
|
||||
{
|
||||
case 'T':
|
||||
s |= TX_EXPLICIT;
|
||||
break;
|
||||
case 'I':
|
||||
s |= TX_IMPLICIT;
|
||||
break;
|
||||
case 'r':
|
||||
s |= TX_READ_UNSAFE;
|
||||
break;
|
||||
case 'R':
|
||||
s |= TX_READ_TRX;
|
||||
break;
|
||||
case 'w':
|
||||
s |= TX_WRITE_UNSAFE;
|
||||
break;
|
||||
case 'W':
|
||||
s |= TX_WRITE_TRX;
|
||||
break;
|
||||
case 's':
|
||||
s |= TX_STMT_UNSAFE;
|
||||
break;
|
||||
case 'S':
|
||||
s |= TX_RESULT_SET;
|
||||
break;
|
||||
case 'L':
|
||||
s |= TX_LOCKED_TABLES;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} while(*(str++) != 0);
|
||||
|
||||
return (mysql_tx_state_t)s;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user