Skip to content

Commit 92e525f

Browse files
BUG#19502202 - SERVER SHUTDOWN HANG SEEN IN SOME INNODB
& RPL TESTS A MTR test binlog.binlog_xa_prepared_disconnect fails sporadically on PB2. When the server is shutdown during the execution of the tests, the shutdown of the mysql server doesn't happen within a specified timeout thereby causing SIGABRT to be sent to the server and the test aborts. As part of the shutdown sequence, sockets are shutdown and closed in one thread and this shall cause the POLLHUP event to be generated for the sockets that are stuck in poll sleep state on another thread. The generation of POLLHUP from the kernel is async and not deterministic and time-bound. Hence shutdown hangs and could not complete in a specified timeout period. The patch fixes this by using ppoll in vio_io_wait and sending pthread_kill to the thread that is stuck on poll when the socket is undergoing shutdown. The constructor and destructor functionality to the patch was addded by Tor Didriksen <tor.didriksen@oracle.com>.
1 parent 0208744 commit 92e525f

21 files changed

+321
-182
lines changed

include/mysql.h.pp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,8 @@
8383
SERVER_STATUS_IN_TRANS_READONLY= 8192,
8484
SERVER_SESSION_STATE_CHANGED= (1UL << 14)
8585
};
86-
struct st_vio;
87-
typedef struct st_vio Vio;
8886
typedef struct st_net {
89-
Vio *vio;
87+
void *vio;
9088
unsigned char *buff,*buff_end,*write_pos,*read_pos;
9189
my_socket fd;
9290
unsigned long remain_in_buf,length, buf_length, where_b;
@@ -141,7 +139,7 @@
141139
SESSION_TRACK_TRANSACTION_CHARACTERISTICS,
142140
SESSION_TRACK_TRANSACTION_STATE
143141
};
144-
my_bool my_net_init(NET *net, Vio* vio);
142+
my_bool my_net_init(NET *net, void *vio);
145143
void my_net_local_init(NET *net);
146144
void net_end(NET *net);
147145
void net_clear(NET *net, my_bool check_buffer);

include/mysql_com.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -749,9 +749,13 @@ enum SERVER_STATUS_flags_enum
749749
*/
750750
#define ONLY_KILL_QUERY 1
751751

752-
753-
struct st_vio; /* Only C */
752+
#ifdef __cplusplus
753+
struct st_vio;
754754
typedef struct st_vio Vio;
755+
#define MYSQL_VIO Vio*
756+
#else
757+
#define MYSQL_VIO void*
758+
#endif
755759

756760
#define MAX_TINYINT_WIDTH 3 /**< Max width for a TINY w.o. sign */
757761
#define MAX_SMALLINT_WIDTH 5 /**< Max width for a SHORT w.o. sign */
@@ -762,7 +766,7 @@ typedef struct st_vio Vio;
762766
#define MAX_BLOB_WIDTH 16777216 /**< Default width for blob */
763767

764768
typedef struct st_net {
765-
Vio *vio;
769+
MYSQL_VIO vio;
766770
unsigned char *buff,*buff_end,*write_pos,*read_pos;
767771
my_socket fd; /* For Perl DBI/dbd */
768772
/**
@@ -937,7 +941,7 @@ enum enum_session_state_type
937941
extern "C" {
938942
#endif
939943

940-
my_bool my_net_init(NET *net, Vio* vio);
944+
my_bool my_net_init(NET *net, MYSQL_VIO vio);
941945
void my_net_local_init(NET *net);
942946
void net_end(NET *net);
943947
void net_clear(NET *net, my_bool check_buffer);

include/sql_common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ void set_mysql_extended_error(MYSQL *mysql, int errcode, const char *sqlstate,
189189

190190
/* client side of the pluggable authentication */
191191
struct st_plugin_vio_info;
192-
void mpvio_info(Vio *vio, struct st_plugin_vio_info *info);
192+
void mpvio_info(MYSQL_VIO vio, struct st_plugin_vio_info *info);
193193
int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
194194
const char *data_plugin, const char *db);
195195
int mysql_client_plugin_init();

include/violite.h

Lines changed: 117 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@
2828

2929
/* Simple vio interface in C; The functions are implemented in violite.c */
3030

31+
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__SUNPRO_CC)
32+
#define USE_PPOLL_IN_VIO
33+
#endif
34+
35+
#if defined(__cplusplus) && defined(USE_PPOLL_IN_VIO)
36+
#include <signal.h>
37+
#include <atomic>
38+
#endif
39+
3140
#ifdef __cplusplus
3241
extern "C" {
3342
#endif /* __cplusplus */
@@ -38,6 +47,9 @@ void init_vio_psi_keys();
3847

3948
#ifdef __cplusplus
4049
typedef struct st_vio Vio;
50+
#define MYSQL_VIO Vio*
51+
#else
52+
#define MYSQL_VIO void*
4153
#endif /* __cplusplus */
4254

4355
enum enum_vio_type
@@ -104,13 +116,13 @@ enum enum_vio_io_event
104116
#define VIO_LOCALHOST 1 /* a localhost connection */
105117
#define VIO_BUFFERED_READ 2 /* use buffered read */
106118
#define VIO_READ_BUFFER_SIZE 16384 /* size of read buffer */
107-
#define VIO_DESCRIPTION_SIZE 30 /* size of description */
108119

109-
Vio* vio_new(my_socket sd, enum enum_vio_type type, uint flags);
110-
Vio* mysql_socket_vio_new(MYSQL_SOCKET mysql_socket, enum enum_vio_type type, uint flags);
120+
MYSQL_VIO vio_new(my_socket sd, enum enum_vio_type type, uint flags);
121+
MYSQL_VIO mysql_socket_vio_new(MYSQL_SOCKET mysql_socket, enum enum_vio_type type, uint flags);
122+
111123
#ifdef _WIN32
112-
Vio* vio_new_win32pipe(HANDLE hPipe);
113-
Vio* vio_new_win32shared_memory(HANDLE handle_file_map,
124+
MYSQL_VIO vio_new_win32pipe(HANDLE hPipe);
125+
MYSQL_VIO vio_new_win32shared_memory(HANDLE handle_file_map,
114126
HANDLE handle_map,
115127
HANDLE event_server_wrote,
116128
HANDLE event_server_read,
@@ -121,41 +133,42 @@ Vio* vio_new_win32shared_memory(HANDLE handle_file_map,
121133
#define HANDLE void *
122134
#endif /* _WIN32 */
123135

124-
void vio_delete(Vio* vio);
125-
int vio_shutdown(Vio* vio);
126-
my_bool vio_reset(Vio* vio, enum enum_vio_type type,
136+
void vio_delete(MYSQL_VIO vio);
137+
int vio_shutdown(MYSQL_VIO vio);
138+
my_bool vio_reset(MYSQL_VIO vio, enum enum_vio_type type,
127139
my_socket sd, void *ssl, uint flags);
128-
size_t vio_read(Vio *vio, uchar * buf, size_t size);
129-
size_t vio_read_buff(Vio *vio, uchar * buf, size_t size);
130-
size_t vio_write(Vio *vio, const uchar * buf, size_t size);
140+
size_t vio_read(MYSQL_VIO vio, uchar * buf, size_t size);
141+
size_t vio_read_buff(MYSQL_VIO vio, uchar * buf, size_t size);
142+
size_t vio_write(MYSQL_VIO vio, const uchar * buf, size_t size);
131143
/* setsockopt TCP_NODELAY at IPPROTO_TCP level, when possible */
132-
int vio_fastsend(Vio *vio);
144+
int vio_fastsend(MYSQL_VIO vio);
133145
/* setsockopt SO_KEEPALIVE at SOL_SOCKET level, when possible */
134-
int vio_keepalive(Vio *vio, my_bool onoff);
146+
int vio_keepalive(MYSQL_VIO vio, my_bool onoff);
135147
/* Whenever we should retry the last read/write operation. */
136-
my_bool vio_should_retry(Vio *vio);
148+
my_bool vio_should_retry(MYSQL_VIO vio);
137149
/* Check that operation was timed out */
138-
my_bool vio_was_timeout(Vio *vio);
150+
my_bool vio_was_timeout(MYSQL_VIO vio);
139151
/* Short text description of the socket for those, who are curious.. */
140-
const char* vio_description(Vio *vio);
152+
#define VIO_DESCRIPTION_SIZE 30 /* size of description */
153+
void vio_description(MYSQL_VIO vio, char *buf);
141154
/* Return the type of the connection */
142-
enum enum_vio_type vio_type(Vio* vio);
155+
enum enum_vio_type vio_type(MYSQL_VIO vio);
143156
/* Return last error number */
144-
int vio_errno(Vio*vio);
157+
int vio_errno(MYSQL_VIO vio);
145158
/* Get socket number */
146-
my_socket vio_fd(Vio*vio);
159+
my_socket vio_fd(MYSQL_VIO vio);
147160
/* Remote peer's address and name in text form */
148-
my_bool vio_peer_addr(Vio *vio, char *buf, uint16 *port, size_t buflen);
161+
my_bool vio_peer_addr(MYSQL_VIO vio, char *buf, uint16 *port, size_t buflen);
149162
/* Wait for an I/O event notification. */
150-
int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout);
151-
my_bool vio_is_connected(Vio *vio);
163+
int vio_io_wait(MYSQL_VIO vio, enum enum_vio_io_event event, int timeout);
164+
my_bool vio_is_connected(MYSQL_VIO vio);
152165
#ifndef DBUG_OFF
153-
ssize_t vio_pending(Vio *vio);
166+
ssize_t vio_pending(MYSQL_VIO vio);
154167
#endif
155168
/* Set timeout for a network operation. */
156-
int vio_timeout(Vio *vio, uint which, int timeout_sec);
169+
int vio_timeout(MYSQL_VIO vio, uint which, int timeout_sec);
157170
/* Connect to a peer. */
158-
my_bool vio_socket_connect(Vio *vio, struct sockaddr *addr, socklen_t len,
171+
my_bool vio_socket_connect(MYSQL_VIO vio, struct sockaddr *addr, socklen_t len,
159172
int timeout);
160173

161174
my_bool vio_get_normalized_ip_string(const struct sockaddr *addr, size_t addr_length,
@@ -207,8 +220,8 @@ struct st_VioSSLFd
207220
SSL_CTX *ssl_context;
208221
};
209222

210-
int sslaccept(struct st_VioSSLFd*, Vio *, long timeout, unsigned long *errptr);
211-
int sslconnect(struct st_VioSSLFd*, Vio *, long timeout, unsigned long *errptr);
223+
int sslaccept(struct st_VioSSLFd*, MYSQL_VIO, long timeout, unsigned long *errptr);
224+
int sslconnect(struct st_VioSSLFd*, MYSQL_VIO, long timeout, unsigned long *errptr);
212225

213226
struct st_VioSSLFd
214227
*new_VioSSLConnectorFd(const char *key_file, const char *cert_file,
@@ -258,32 +271,49 @@ enum SSL_type
258271
SSL_TYPE_SPECIFIED
259272
};
260273

261-
274+
#ifdef __cplusplus
262275
/* HFTODO - hide this if we don't want client in embedded server */
263276
/* This structure is for every connection on both sides */
264277
struct st_vio
265278
{
266279
MYSQL_SOCKET mysql_socket; /* Instrumented socket */
267-
my_bool localhost; /* Are we from localhost? */
280+
bool localhost= { false }; /* Are we from localhost? */
281+
enum_vio_type type= { NO_VIO_TYPE }; /* Type of connection */
282+
283+
int read_timeout= { -1 }; /* Timeout value (ms) for read ops. */
284+
int write_timeout= { -1 }; /* Timeout value (ms) for write ops. */
285+
int retry_count= { 1 }; /* Retry count */
286+
bool inactive= { false }; /* Connection has been shutdown */
287+
268288
struct sockaddr_storage local; /* Local internet address */
269289
struct sockaddr_storage remote; /* Remote internet address */
270-
size_t addrLen; /* Length of remote address */
271-
enum enum_vio_type type; /* Type of connection */
272-
my_bool inactive; /* Connection inactive (has been shutdown) */
273-
char desc[VIO_DESCRIPTION_SIZE]; /* Description string. This
274-
member MUST NOT be
275-
used directly, but only
276-
via function
277-
"vio_description" */
278-
char *read_buffer; /* buffer for vio_read_buff */
279-
char *read_pos; /* start of unfetched data in the
280-
read buffer */
281-
char *read_end; /* end of unfetched data */
282-
int read_timeout; /* Timeout value (ms) for read ops. */
283-
int write_timeout; /* Timeout value (ms) for write ops. */
284-
int retry_count; /* Retry count */
290+
size_t addrLen= { 0 }; /* Length of remote address */
291+
char *read_buffer= { nullptr }; /* buffer for vio_read_buff */
292+
char *read_pos= { nullptr }; /* start of unfetched data in the
293+
read buffer */
294+
char *read_end= { nullptr }; /* end of unfetched data */
295+
296+
#ifdef USE_PPOLL_IN_VIO
297+
my_thread_t thread_id= { 0 }; // Thread PID
298+
sigset_t signal_mask; // Signal mask
299+
/*
300+
Flag to indicate whether we are in poll or shutdown.
301+
A true value of flag indicates either the socket
302+
has called shutdown or it is sleeping on a poll call.
303+
False value of this flag means that the socket is
304+
not sleeping on a poll call.
305+
This flag provides synchronization between two threads
306+
one entering vio_io_wait and another entering vio_shutdown
307+
for the same socket. If the other thread is waiting on poll
308+
sleep, it wakes up the thread by sending a signal via
309+
pthread_kill. Also it ensures that no other thread enters in
310+
to a poll call if it's socket has undergone shutdown.
285311
286-
/*
312+
*/
313+
std::atomic_flag poll_shutdown_flag= ATOMIC_FLAG_INIT;
314+
#endif
315+
316+
/*
287317
VIO vtable interface to be implemented by VIO's like SSL, Socket,
288318
Named Pipe, etc.
289319
*/
@@ -292,49 +322,61 @@ struct st_vio
292322
viodelete is responsible for cleaning up the VIO object by freeing
293323
internal buffers, closing descriptors, handles.
294324
*/
295-
void (*viodelete)(Vio*);
296-
int (*vioerrno)(Vio*);
297-
size_t (*read)(Vio*, uchar *, size_t);
298-
size_t (*write)(Vio*, const uchar *, size_t);
299-
int (*timeout)(Vio*, uint, my_bool);
300-
int (*viokeepalive)(Vio*, my_bool);
301-
int (*fastsend)(Vio*);
302-
my_bool (*peer_addr)(Vio*, char *, uint16*, size_t);
303-
void (*in_addr)(Vio*, struct sockaddr_storage*);
304-
my_bool (*should_retry)(Vio*);
305-
my_bool (*was_timeout)(Vio*);
325+
void (*viodelete)(MYSQL_VIO)= { nullptr };
326+
int (*vioerrno)(MYSQL_VIO)= { nullptr };
327+
size_t (*read)(MYSQL_VIO, uchar *, size_t)= { nullptr };
328+
size_t (*write)(MYSQL_VIO, const uchar *, size_t)= { nullptr };
329+
int (*timeout)(MYSQL_VIO, uint, my_bool)= { nullptr };
330+
int (*viokeepalive)(MYSQL_VIO, my_bool)= { nullptr };
331+
int (*fastsend)(MYSQL_VIO)= { nullptr };
332+
my_bool (*peer_addr)(MYSQL_VIO, char *, uint16*, size_t)= { nullptr };
333+
void (*in_addr)(MYSQL_VIO, struct sockaddr_storage*)= { nullptr };
334+
my_bool (*should_retry)(MYSQL_VIO)= { nullptr };
335+
my_bool (*was_timeout)(MYSQL_VIO)= { nullptr };
306336
/*
307337
vioshutdown is resposnible to shutdown/close the channel, so that no
308338
further communications can take place, however any related buffers,
309339
descriptors, handles can remain valid after a shutdown.
310340
*/
311-
int (*vioshutdown)(Vio*);
312-
my_bool (*is_connected)(Vio*);
313-
my_bool (*has_data) (Vio*);
314-
int (*io_wait)(Vio*, enum enum_vio_io_event, int);
315-
my_bool (*connect)(Vio*, struct sockaddr *, socklen_t, int);
341+
int (*vioshutdown)(MYSQL_VIO)= { nullptr };
342+
my_bool (*is_connected)(MYSQL_VIO)= { nullptr };
343+
my_bool (*has_data) (MYSQL_VIO)= { nullptr };
344+
int (*io_wait)(MYSQL_VIO, enum enum_vio_io_event, int)= { nullptr };
345+
my_bool (*connect)(MYSQL_VIO, struct sockaddr *, socklen_t, int)= { nullptr };
316346
#ifdef _WIN32
317-
OVERLAPPED overlapped;
318-
HANDLE hPipe;
347+
OVERLAPPED overlapped = { 0 };
348+
HANDLE hPipe { nullptr };
319349
#endif
320350
#ifdef HAVE_OPENSSL
321-
void *ssl_arg;
351+
void *ssl_arg= { nullptr };
322352
#endif
323353
#if defined (_WIN32) && !defined (EMBEDDED_LIBRARY)
324-
HANDLE handle_file_map;
325-
char *handle_map;
326-
HANDLE event_server_wrote;
327-
HANDLE event_server_read;
328-
HANDLE event_client_wrote;
329-
HANDLE event_client_read;
330-
HANDLE event_conn_closed;
331-
size_t shared_memory_remain;
332-
char *shared_memory_pos;
354+
HANDLE handle_file_map= { nullptr };
355+
char *handle_map= { nullptr };
356+
HANDLE event_server_wrote= { nullptr };
357+
HANDLE event_server_read= { nullptr };
358+
HANDLE event_client_wrote= { nullptr };
359+
HANDLE event_client_read= { nullptr };
360+
HANDLE event_conn_closed= { nullptr };
361+
size_t shared_memory_remain= { 0 };
362+
char *shared_memory_pos= { nullptr };
333363
#endif /* _WIN32 && !EMBEDDED_LIBRARY */
364+
365+
private:
366+
friend st_vio *internal_vio_create(uint flags);
367+
friend void internal_vio_delete(st_vio *vio);
368+
friend my_bool vio_reset(Vio* vio, enum_vio_type type,
369+
my_socket sd, void *ssl, uint flags);
370+
371+
explicit st_vio(uint flags);
372+
~st_vio();
373+
374+
public:
375+
st_vio(const st_vio&) = delete;
376+
st_vio &operator=(const st_vio&) = delete;
334377
};
335378

336-
#ifdef __cplusplus
337379
}
338-
#endif
380+
#endif /* __cpluscplus */
339381

340382
#endif /* vio_violite_h_ */

mysql-test/collections/default.experimental

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ perfschema.transaction_nested_events # Bug#17752288 2013-12-17 agopi Fails s
1818
main.ssl-big @windows # Bug#18200216 2014-03-14 horst Fails too often in daily in PB2.
1919
rpl_gtid.rpl_gtid_stress_failover # Bug#20630589 2015-03-19 agopi Originally made experimental due to bug#16409537 which was closed as not reproducible.
2020

21-
binlog.binlog_xa_prepared_disconnect # Bug#19502202 2015-12-02 erlend experimental while waiting for a fix
22-
main.xa_prepared_binlog_off # Bug#19502202 2015-12-02 erlend experimental while waiting for a fix
2321
main.user_var # Bug#21907546 2015-12-11 erlend experimental to reduce noise
2422
main.locking_service # Bug#22304322 2015-12-11 erlend experimental to reduce noise
2523
main.partition_pruning # Bug#20597049 2015-12-11 erlend experimental to reduce noise

plugin/semisync/semisync_master_ack_receiver.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,9 @@ bool Ack_receiver::add_slave(THD *thd)
130130
function_enter(kWho);
131131

132132
slave.thd= thd;
133-
slave.vio= *thd->get_protocol_classic()->get_vio();
134-
slave.vio.mysql_socket.m_psi= NULL;
135-
slave.vio.read_timeout= 1;
133+
slave.vio= thd->get_protocol_classic()->get_vio();
134+
slave.vio->mysql_socket.m_psi= NULL;
135+
slave.vio->read_timeout= 1;
136136

137137
/* push_back() may throw an exception */
138138
try
@@ -284,7 +284,7 @@ void Ack_receiver::run()
284284
ulong len;
285285

286286
net_clear(&net, 0);
287-
net.vio= &m_slaves[i].vio;
287+
net.vio= m_slaves[i].vio;
288288

289289
len= my_net_read(&net);
290290
if (likely(len != packet_error))

plugin/semisync/semisync_master_ack_receiver.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -104,9 +104,9 @@ class Ack_receiver : public ReplSemiSyncBase
104104
struct Slave
105105
{
106106
THD *thd;
107-
Vio vio;
107+
Vio *vio;
108108

109-
my_socket sock_fd() { return vio.mysql_socket.fd; }
109+
my_socket sock_fd() { return vio->mysql_socket.fd; }
110110
uint server_id() { return thd->server_id; }
111111
};
112112

0 commit comments

Comments
 (0)