From bfa198c2e700c96f46743a217459470a6dc19a67 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Thu, 26 Mar 2009 20:17:27 -0300 Subject: Bug#33899: Deadlock in mysql_real_query with shared memory connections The problem is that the read and write methods of the shared memory transport (protocol) didn't react to asynchronous close events, which could lead to a lock up as the client would wait (until time out) for a server response that will never come. The solution is to also wait for close events while waiting for I/O from or to the server. --- mysql-test/r/shm.result | 7 +++++++ mysql-test/t/shm.test | 19 +++++++++++++++++++ vio/viosocket.c | 20 +++++++++++++------- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/shm.result b/mysql-test/r/shm.result index 09adebad10f..9d555e9878c 100644 --- a/mysql-test/r/shm.result +++ b/mysql-test/r/shm.result @@ -2152,4 +2152,11 @@ Warnings: Warning 1052 Column 'kundentyp' in group statement is ambiguous drop table t1; mysqld is alive +SET @max_allowed_packet= @@global.max_allowed_packet; +SET @net_buffer_length= @@global.net_buffer_length; +SET GLOBAL max_allowed_packet= 1024; +SET GLOBAL net_buffer_length= 1024; +ERROR 1153 (08S01) at line 1: Got a packet bigger than 'max_allowed_packet' bytes +SET GLOBAL max_allowed_packet= @max_allowed_packet; +SET GLOBAL net_buffer_length= @net_buffer_length; End of 5.0 tests. diff --git a/mysql-test/t/shm.test b/mysql-test/t/shm.test index 380607d8ebf..88e96ae7b45 100644 --- a/mysql-test/t/shm.test +++ b/mysql-test/t/shm.test @@ -16,4 +16,23 @@ if (`SELECT '$shm' != 'ON'`){ # --exec $MYSQLADMIN --no-defaults --user=root --host=127.0.0.1 --port=$MASTER_MYPORT --shared-memory-base-name=HeyMrBaseNameXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ping +# +# Bug #33899: Deadlock in mysql_real_query with shared memory connections +# + +let $name= query_get_value("SHOW GLOBAL VARIABLES LIKE 'shared_memory_base_name'", Value, 1); +let $stmt= `SELECT REPEAT('a', 2048)`; + +SET @max_allowed_packet= @@global.max_allowed_packet; +SET @net_buffer_length= @@global.net_buffer_length; + +SET GLOBAL max_allowed_packet= 1024; +SET GLOBAL net_buffer_length= 1024; + +--error 1 +--exec echo SELECT '$stmt'| $MYSQL --protocol=memory --shared-memory-base-name=$name 2>&1 + +SET GLOBAL max_allowed_packet= @max_allowed_packet; +SET GLOBAL net_buffer_length= @net_buffer_length; + --echo End of 5.0 tests. diff --git a/vio/viosocket.c b/vio/viosocket.c index 13fbf5d98d8..59ec78014d0 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -479,26 +479,28 @@ int vio_read_shared_memory(Vio * vio, gptr buf, int size) int length; int remain_local; char *current_postion; + HANDLE events[2]; DBUG_ENTER("vio_read_shared_memory"); DBUG_PRINT("enter", ("sd: %d buf: 0x%lx size: %d", vio->sd, buf, size)); remain_local = size; current_postion=buf; + + events[0]= vio->event_server_wrote; + events[1]= vio->event_conn_closed; + do { if (vio->shared_memory_remain == 0) { - HANDLE events[2]; - events[0]= vio->event_server_wrote; - events[1]= vio->event_conn_closed; /* WaitForMultipleObjects can return next values: WAIT_OBJECT_0+0 - event from vio->event_server_wrote WAIT_OBJECT_0+1 - event from vio->event_conn_closed. We can't read anything WAIT_ABANDONED_0 and WAIT_TIMEOUT - fail. We can't read anything */ - if (WaitForMultipleObjects(2, (HANDLE*)&events,FALSE, + if (WaitForMultipleObjects(array_elements(events), events, FALSE, vio->net->read_timeout*1000) != WAIT_OBJECT_0) { DBUG_RETURN(-1); @@ -537,19 +539,23 @@ int vio_write_shared_memory(Vio * vio, const gptr buf, int size) { int length; uint remain; - HANDLE pos; int sz; char *current_postion; + HANDLE pos, events[2]; DBUG_ENTER("vio_write_shared_memory"); DBUG_PRINT("enter", ("sd: %d buf: 0x%lx size: %d", vio->sd, buf, size)); remain = size; current_postion = buf; + + events[0]= vio->event_server_read; + events[1]= vio->event_conn_closed; + while (remain != 0) { - if (WaitForSingleObject(vio->event_server_read, vio->net->write_timeout*1000) - != WAIT_OBJECT_0) + if (WaitForMultipleObjects(array_elements(events), events, FALSE, + vio->net->write_timeout*1000) != WAIT_OBJECT_0) { DBUG_RETURN(-1); }; -- cgit v1.2.1