diff --git a/log_manager/log_manager.cc b/log_manager/log_manager.cc index 92eaaff0f..230e44804 100644 --- a/log_manager/log_manager.cc +++ b/log_manager/log_manager.cc @@ -94,7 +94,9 @@ char* syslog_ident_str = NULL; */ static int lmlock; static logmanager_t* lm; - +static bool flushall_flag; +static bool flushall_started_flag; +static bool flushall_done_flag; /** Writer thread structure */ struct filewriter_st { @@ -286,12 +288,14 @@ static char* add_slash(char* str); static bool check_file_and_path( char* filename, - bool* writable); + bool* writable, + bool do_log); static bool file_is_symlink(char* filename); static int skygw_log_disable_raw(logfile_id_t id, bool emergency); /*< no locking */ static int find_last_seqno(strpart_t* parts, int seqno, int seqnoidx); - +void flushall_logfiles(bool flush); +bool thr_flushall_check(); const char* get_suffix_default(void) { @@ -441,17 +445,6 @@ static bool logmanager_init_nomutex( return_succp: if (err != 0) { - if (lm != NULL) - { - if (lm->lm_clientmes != NULL) - { - skygw_message_done(lm->lm_clientmes); - } - if (lm->lm_logmes != NULL) - { - skygw_message_done(lm->lm_logmes); - } - } /** This releases memory of all created objects */ logmanager_done_nomutex(); fprintf(stderr, "*\n* Error : Initializing log manager failed.\n*\n"); @@ -2053,7 +2046,7 @@ static bool logfile_create( * If file exists but is different type, create fails and * new, increased sequence number is added to file name. */ - if (check_file_and_path(lf->lf_full_file_name, &writable)) + if (check_file_and_path(lf->lf_full_file_name, &writable, true)) { /** Found similarly named file which isn't writable */ if (!writable || file_is_symlink(lf->lf_full_file_name)) @@ -2077,13 +2070,11 @@ static bool logfile_create( if (store_shmem) { - if (check_file_and_path(lf->lf_full_file_name, &writable)) + if (check_file_and_path(lf->lf_full_link_name, &writable, true)) { - /** Found similarly named file which isn't writable */ - if (!writable || - file_is_symlink(lf->lf_full_file_name)) + /** Found similarly named link which isn't writable */ + if (!writable) { - unlink(lf->lf_full_file_name); nameconflicts = true; } } @@ -2214,7 +2205,6 @@ return_succp: * * @return Pointer to filename, of NULL if failed. * - * */ static char* form_full_file_name( strpart_t* parts, @@ -2231,9 +2221,21 @@ static char* form_full_file_name( if (lf->lf_name_seqno != -1) { - lf->lf_name_seqno = find_last_seqno(parts, - lf->lf_name_seqno, - seqnoidx); + int file_sn; + int link_sn = 0; + char* tmp = parts[0].sp_string; + + file_sn = find_last_seqno(parts, lf->lf_name_seqno, seqnoidx); + + if (lf->lf_linkpath != NULL) + { + tmp = parts[0].sp_string; + parts[0].sp_string = lf->lf_linkpath; + link_sn = find_last_seqno(parts, lf->lf_name_seqno, seqnoidx); + parts[0].sp_string = tmp; + } + lf->lf_name_seqno = MAX(file_sn, link_sn); + seqno = lf->lf_name_seqno; s = UINTLEN(seqno); seqnostr = (char *)malloc((int)s+1); @@ -2354,7 +2356,8 @@ static char* add_slash( */ static bool check_file_and_path( char* filename, - bool* writable) + bool* writable, + bool do_log) { int fd; bool exists; @@ -2382,11 +2385,23 @@ static bool check_file_and_path( if (fd == -1) { - fprintf(stderr, - "*\n* Error : Can't access %s due " - "to %s.\n", - filename, - strerror(errno)); + if (do_log && file_is_symlink(filename)) + { + fprintf(stderr, + "*\n* Error : Can't access " + "file pointed to by %s due " + "to %s.\n", + filename, + strerror(errno)); + } + else if (do_log) + { + fprintf(stderr, + "*\n* Error : Can't access %s due " + "to %s.\n", + filename, + strerror(errno)); + } if (writable) { *writable = false; @@ -2403,11 +2418,24 @@ static bool check_file_and_path( } else { - fprintf(stderr, - "*\n* Error : Can't write to " - "%s due to %s.\n", - filename, - strerror(errno)); + if (do_log && + file_is_symlink(filename)) + { + fprintf(stderr, + "*\n* Error : Can't write to " + "file pointed to by %s due to " + "%s.\n", + filename, + strerror(errno)); + } + else if (do_log) + { + fprintf(stderr, + "*\n* Error : Can't write to " + "%s due to %s.\n", + filename, + strerror(errno)); + } *writable = false; } } @@ -2417,10 +2445,21 @@ static bool check_file_and_path( } else { - fprintf(stderr, - "*\n* Error : Can't access %s due to %s.\n", - filename, - strerror(errno)); + if (do_log && file_is_symlink(filename)) + { + fprintf(stderr, + "*\n* Error : Can't access the file " + "pointed to by %s due to %s.\n", + filename, + strerror(errno)); + } + else if (do_log) + { + fprintf(stderr, + "*\n* Error : Can't access %s due to %s.\n", + filename, + strerror(errno)); + } exists = false; if (writable) @@ -2572,7 +2611,7 @@ static bool logfile_init( logfile_free_memory(logfile); goto return_with_succp; } -#if defined(SS_DEBUG) + if (store_shmem) { fprintf(stderr, "%s\t: %s->%s\n", @@ -2586,7 +2625,6 @@ static bool logfile_init( STRLOGNAME(logfile_id), logfile->lf_full_file_name); } -#endif succp = true; logfile->lf_state = RUN; CHK_LOGFILE(logfile); @@ -2802,13 +2840,15 @@ static void* thr_filewriter_fun( int i; blockbuf_state_t flush_blockbuf; /**< flush single block buffer. */ bool flush_logfile; /**< flush logfile */ - bool flushall_logfiles;/**< flush all logfiles */ + bool do_flushall = false; bool rotate_logfile; /*< close current and open new file */ size_t vn1; size_t vn2; thr = (skygw_thread_t *)data; fwr = (filewriter_t *)skygw_thread_get_data(thr); + flushall_logfiles(false); + CHK_FILEWRITER(fwr); ss_debug(skygw_thread_set_state(thr, THR_RUNNING)); @@ -2821,8 +2861,9 @@ static void* thr_filewriter_fun( * Reset message to avoid redundant calls. */ skygw_message_wait(fwr->fwr_logmes); - - flushall_logfiles = skygw_thread_must_exit(thr); + if(skygw_thread_must_exit(thr)){ + flushall_logfiles(true); + } /** Process all logfiles which have buffered writes. */ for (i=LOGFILE_FIRST; i<=LOGFILE_LAST; i <<= 1) @@ -2831,6 +2872,10 @@ static void* thr_filewriter_fun( /** * Get file pointer of current logfile. */ + + + + do_flushall = thr_flushall_check(); file = fwr->fwr_file[i]; lf = &lm->lm_logfile[(logfile_id_t)i]; @@ -2901,7 +2946,7 @@ static void* thr_filewriter_fun( if (bb->bb_buf_used != 0 && (flush_blockbuf == BB_FULL || flush_logfile || - flushall_logfiles)) + do_flushall)) { /** * buffer is at least half-full @@ -2920,7 +2965,7 @@ static void* thr_filewriter_fun( (void *)bb->bb_buf, bb->bb_buf_used, (flush_logfile || - flushall_logfiles)); + do_flushall)); if (err) { fprintf(stderr, @@ -2967,13 +3012,28 @@ static void* thr_filewriter_fun( * Loop is restarted to ensure that all logfiles are * flushed. */ - if (!flushall_logfiles && skygw_thread_must_exit(thr)) + + if(flushall_started_flag){ + flushall_started_flag = false; + flushall_done_flag = true; + i = LOGFILE_FIRST; + goto retry_flush_on_exit; + } + + if (!thr_flushall_check() && skygw_thread_must_exit(thr)) { - flushall_logfiles = true; + flushall_logfiles(true); i = LOGFILE_FIRST; goto retry_flush_on_exit; } - } /* for */ + }/* for */ + + if(flushall_done_flag){ + flushall_done_flag = false; + flushall_logfiles(false); + skygw_message_send(fwr->fwr_clientmes); + } + } /* while (!skygw_thread_must_exit) */ ss_debug(skygw_thread_set_state(thr, THR_STOPPED)); @@ -3061,7 +3121,7 @@ static int find_last_seqno( } } - if (check_file_and_path(filename, NULL)) + if (check_file_and_path(filename, NULL, false)) { seqno++; } @@ -3073,4 +3133,34 @@ static int find_last_seqno( free(snstr); return seqno; -} \ No newline at end of file +} + +bool thr_flushall_check() +{ + bool rval = false; + simple_mutex_lock(&lm->lm_mutex,true); + rval = flushall_flag; + if(rval && !flushall_started_flag && !flushall_done_flag){ + flushall_started_flag = true; + } + simple_mutex_unlock(&lm->lm_mutex); + return rval; +} + +void flushall_logfiles(bool flush) +{ + simple_mutex_lock(&lm->lm_mutex,true); + flushall_flag = flush; + simple_mutex_unlock(&lm->lm_mutex); +} + +/** + * Flush all log files synchronously + */ +void skygw_log_sync_all(void) +{ + skygw_log_write(LOGFILE_TRACE,"Starting log flushing to disk."); + flushall_logfiles(true); + skygw_message_send(lm->lm_logmes); + skygw_message_wait(lm->lm_clientmes); +} diff --git a/server/MaxScale_template.cnf b/server/MaxScale_template.cnf index cb49c3e14..a3f44ebf1 100644 --- a/server/MaxScale_template.cnf +++ b/server/MaxScale_template.cnf @@ -31,7 +31,7 @@ threads=4 # backend_write_timeout= # backend_read_timeout= # -## mysql_monitor specific options: +## MySQL monitor-specific options: # # Enable detection of replication slaves lag via replication_heartbeat # table - optional. @@ -43,6 +43,13 @@ threads=4 # # detect_stale_master=[1|0] (default 0) # +## Galera monitor-specific options: +# +# If disable_master_failback is not set, recovery of previously failed master +# causes mastership to be switched back to it. Enabling the option prevents it. +# +# disable_master_failback=[0|1] (default 0) +# ## Examples: [MySQL Monitor] @@ -65,6 +72,7 @@ servers=server1,server2,server3 user=myuser passwd=mypwd monitor_interval=10000 +#disable_master_failback= ## Filter definition # diff --git a/server/modules/include/mysql_client_server_protocol.h b/server/modules/include/mysql_client_server_protocol.h index f15c9e62b..803981e46 100644 --- a/server/modules/include/mysql_client_server_protocol.h +++ b/server/modules/include/mysql_client_server_protocol.h @@ -95,6 +95,7 @@ typedef enum { MYSQL_AUTH_SENT, MYSQL_AUTH_RECV, MYSQL_AUTH_FAILED, + MYSQL_HANDSHAKE_FAILED, MYSQL_IDLE } mysql_auth_state_t; diff --git a/server/modules/protocol/mysql_backend.c b/server/modules/protocol/mysql_backend.c index 97121cf4f..ea8afa522 100644 --- a/server/modules/protocol/mysql_backend.c +++ b/server/modules/protocol/mysql_backend.c @@ -211,12 +211,13 @@ static int gw_read_backend_event(DCB *dcb) { /** Read cached backend handshake */ if (gw_read_backend_handshake(backend_protocol) != 0) { - backend_protocol->protocol_auth_state = MYSQL_AUTH_FAILED; + backend_protocol->protocol_auth_state = MYSQL_HANDSHAKE_FAILED; + LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, "%lu [gw_read_backend_event] after " "gw_read_backend_handshake, fd %d, " - "state = MYSQL_AUTH_FAILED.", + "state = MYSQL_HANDSHAKE_FAILED.", pthread_self(), backend_protocol->owner_dcb->fd))); } @@ -256,6 +257,7 @@ static int gw_read_backend_event(DCB *dcb) { * -- handle a previous handshake error */ if (backend_protocol->protocol_auth_state == MYSQL_AUTH_RECV || + backend_protocol->protocol_auth_state == MYSQL_HANDSHAKE_FAILED || backend_protocol->protocol_auth_state == MYSQL_AUTH_FAILED) { spinlock_acquire(&dcb->authlock); @@ -264,6 +266,7 @@ static int gw_read_backend_event(DCB *dcb) { CHK_PROTOCOL(backend_protocol); if (backend_protocol->protocol_auth_state == MYSQL_AUTH_RECV || + backend_protocol->protocol_auth_state == MYSQL_HANDSHAKE_FAILED || backend_protocol->protocol_auth_state == MYSQL_AUTH_FAILED) { ROUTER_OBJECT *router = NULL; @@ -286,7 +289,7 @@ static int gw_read_backend_event(DCB *dcb) { if (backend_protocol->protocol_auth_state == MYSQL_AUTH_RECV) { /** - * Read backed's reply to authentication message + * Read backend's reply to authentication message */ receive_rc = gw_receive_backend_auth(backend_protocol); @@ -340,7 +343,8 @@ static int gw_read_backend_event(DCB *dcb) { } /* switch */ } - if (backend_protocol->protocol_auth_state == MYSQL_AUTH_FAILED) + if (backend_protocol->protocol_auth_state == MYSQL_AUTH_FAILED || + backend_protocol->protocol_auth_state == MYSQL_HANDSHAKE_FAILED) { /** * protocol state won't change anymore, @@ -362,7 +366,9 @@ static int gw_read_backend_event(DCB *dcb) { bool succp; /* try reload users' table for next connection */ - service_refresh_users(dcb->session->service); + if (backend_protocol->protocol_auth_state == MYSQL_AUTH_FAILED) { + service_refresh_users(dcb->session->service); + } #if defined(SS_DEBUG) LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, @@ -428,7 +434,7 @@ static int gw_read_backend_event(DCB *dcb) { spinlock_release(&dcb->authlock); - } /* MYSQL_AUTH_RECV || MYSQL_AUTH_FAILED */ + } /* MYSQL_AUTH_RECV || MYSQL_AUTH_FAILED || MYSQL_HANDSHAKE_FAILED */ /* reading MySQL command output from backend and writing to the client */ { @@ -693,6 +699,7 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue) * return 1. */ switch (backend_protocol->protocol_auth_state) { + case MYSQL_HANDSHAKE_FAILED: case MYSQL_AUTH_FAILED: { size_t len; diff --git a/server/modules/protocol/mysql_common.c b/server/modules/protocol/mysql_common.c index 27159dc21..80c3319a8 100644 --- a/server/modules/protocol/mysql_common.c +++ b/server/modules/protocol/mysql_common.c @@ -214,12 +214,12 @@ int gw_read_backend_handshake( if (h_len <= 4) { /* log error this exit point */ - conn->protocol_auth_state = MYSQL_AUTH_FAILED; + conn->protocol_auth_state = MYSQL_HANDSHAKE_FAILED; LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, "%lu [gw_read_backend_handshake] after " "dcb_read, fd %d, " - "state = MYSQL_AUTH_FAILED.", + "state = MYSQL_HANDSHAKE_FAILED.", dcb->fd, pthread_self()))); @@ -232,6 +232,8 @@ int gw_read_backend_handshake( uint16_t errcode = MYSQL_GET_ERRCODE(payload); char* bufstr = strndup(&((char *)payload)[7], len-3); + conn->protocol_auth_state = MYSQL_HANDSHAKE_FAILED; + LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, "%lu [gw_receive_backend_auth] Invalid " @@ -261,12 +263,14 @@ int gw_read_backend_handshake( * data in buffer less than expected in the * packet. Log error this exit point */ - conn->protocol_auth_state = MYSQL_AUTH_FAILED; + + conn->protocol_auth_state = MYSQL_HANDSHAKE_FAILED; + LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, "%lu [gw_read_backend_handshake] after " "gw_mysql_get_byte3, fd %d, " - "state = MYSQL_AUTH_FAILED.", + "state = MYSQL_HANDSHAKE_FAILED.", pthread_self(), dcb->fd, pthread_self()))); @@ -285,12 +289,13 @@ int gw_read_backend_handshake( * we cannot continue * log error this exit point */ - conn->protocol_auth_state = MYSQL_AUTH_FAILED; + conn->protocol_auth_state = MYSQL_HANDSHAKE_FAILED; + LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, "%lu [gw_read_backend_handshake] after " "gw_decode_mysql_server_handshake, fd %d, " - "state = MYSQL_AUTH_FAILED.", + "state = MYSQL_HANDSHAKE_FAILED.", pthread_self(), conn->owner_dcb->fd, pthread_self()))); @@ -577,8 +582,8 @@ int gw_send_authentication_to_backend( dcb = conn->owner_dcb; final_capabilities = gw_mysql_get_byte4((uint8_t *)&server_capabilities); - /** Copy client's flags to backend */ - final_capabilities |= conn->client_capabilities; + /** Copy client's flags to backend but with the known capabilities mask */ + final_capabilities |= (conn->client_capabilities & GW_MYSQL_CAPABILITIES_CLIENT); /* get charset the client sent and use it for connection auth */ charset = conn->charset; diff --git a/utils/skygw_utils.cc b/utils/skygw_utils.cc index 8e285c6a2..fd25c60cf 100644 --- a/utils/skygw_utils.cc +++ b/utils/skygw_utils.cc @@ -1680,12 +1680,12 @@ static bool file_write_header( if (wbytes1 != 1 || wbytes2 != 1 || wbytes3 != 1 || wbytes4 != 1) { fprintf(stderr, - "* Writing header %s %s %s to %s failed.\n", + "\nError : Writing header %s %s %s %s failed.\n", header_buf1, header_buf2, header_buf3, header_buf4); - perror("Logfile header write.\n"); + perror("Logfile header write"); goto return_succp; } #endif @@ -1757,11 +1757,11 @@ static bool file_write_footer( if (wbytes1 != 1 || wbytes3 != 1 || wbytes4 != 1) { fprintf(stderr, - "* Writing header %s %s to %s failed.\n", + "\nError : Writing header %s %s to %s failed.\n", header_buf1, header_buf3, header_buf4); - perror("Logfile header write.\n"); + perror("Logfile header write"); goto return_succp; } #endif @@ -1875,7 +1875,7 @@ skygw_file_t* skygw_file_init( int eno = errno; errno = 0; fprintf(stderr, - "* Writing header of log file %s failed due %d, %s.\n", + "\nError : Writing header of log file %s failed due %d, %s.\n", file->sf_fname, eno, strerror(eno));