# At a local mysql-5.1-bugteam repository of davi
3456 Davi Arnaut 2010-07-02
Bug#54790: Use of non-blocking mode for sockets limits performance
The problem was that a optimization for the case when the
server uses alarms for timeouts could cause a slowdown when
socket timeouts are used instead.
In case alarms are used for timeouts, a non-blocking read
is attempted first in order to avoid the cost of setting up
a alarm. If the non-blocking read fails, the socket mode is
changed to blocking and a alarm is armed.
If socket timeout is used, there is no point in attempting a
non-blocking read first as the timeout will be automatically
armed by the OS. Yet the server would attempt a non-blocking
read first and later switch the socket to blocking mode. This
could inadvertently impact performance as switching the blocking
mode of a socket requires at least two calls into the kernel,
apart from problems inherited by the scalability of fcntl.
The solution is to not attempt a non-blocking read first if
built-in socket timeouts are being used. Also, in this case,
spurious interruptions with a errno value of EINTR should
be ignored.
@ sql/net_serv.cc
Do not set socket to non-blocking if not using alarms.
Assert that the socket mode is blocking if using std
socket timeouts. Also, ignore spurious interruptions
in this mode.
modified:
sql/net_serv.cc
=== modified file 'sql/net_serv.cc'
--- a/sql/net_serv.cc 2010-06-09 08:29:27 +0000
+++ b/sql/net_serv.cc 2010-07-02 13:13:43 +0000
@@ -139,7 +139,7 @@ my_bool my_net_init(NET *net, Vio* vio)
if (vio != 0) /* If real connection */
{
net->fd = vio_fd(vio); /* For perl DBI/DBD */
-#if defined(MYSQL_SERVER) && !defined(__WIN__)
+#if defined(MYSQL_SERVER) && !defined(__WIN__) && !defined(NO_ALARM)
if (!(test_flags & TEST_BLOCKING))
{
my_bool old_mode;
@@ -805,6 +805,7 @@ my_real_read(NET *net, size_t *complen)
thr_alarm(&alarmed,net->read_timeout,&alarm_buff);
#else
/* Read timeout is set in my_net_set_read_timeout */
+ DBUG_ASSERT(net_blocking);
#endif /* NO_ALARM */
pos = net->buff + net->where_b; /* net->packet -4 */
@@ -815,10 +816,21 @@ my_real_read(NET *net, size_t *complen)
/* First read is done with non blocking mode */
if ((long) (length= vio_read(net->vio, pos, remain)) <= 0L)
{
- my_bool interrupted = vio_should_retry(net->vio);
+ my_bool interrupted;
DBUG_PRINT("info",("vio_read returned %ld errno: %d",
(long) length, vio_errno(net->vio)));
+
+#ifdef NO_ALARM
+ if (vio_errno(net->vio) == SOCKET_EINTR)
+ {
+ DBUG_PRINT("warning",("Interrupted read. Retrying..."));
+ continue;
+ }
+#endif
+
+ interrupted= vio_should_retry(net->vio);
+
#if !defined(__WIN__) || defined(MYSQL_SERVER)
/*
We got an error that there was no data on the socket. We now set up
Attachment: [text/bzr-bundle] bzr/davi.arnaut@sun.com-20100702131343-gy7tgcyv4ew3hat4.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-bugteam branch (davi:3456) Bug#54790 | Davi Arnaut | 2 Jul |