Bug #20782 mysqladmin, ping command, small logic mistake
Submitted: 29 Jun 2006 17:47 Modified: 30 Jul 2006 13:10
Reporter: Kai Voigt Email Updates:
Status: No Feedback Impact on me:
None 
Category:MySQL Server Severity:S3 (Non-critical)
Version:5.1.7-beta-log OS:MacOS (MacOSX 10.4)
Assigned to: CPU Architecture:Any

[29 Jun 2006 17:47] Kai Voigt
Description:
When looking at the logic of how mysqladmin does the ping subcommand, it goes like this.

      mysql->reconnect=0;       /* We want to know of reconnects */
      if (!mysql_ping(mysql))
      {
        if (option_silent < 2)
          puts("mysqld is alive");
      }
      else
      {
        if (mysql_errno(mysql) == CR_SERVER_GONE_ERROR)
        {
          mysql->reconnect=1;
          if (!mysql_ping(mysql))
            puts("connection was down, but mysqld is now alive");
        }
        else
        {
          my_printf_error(0,"mysqld doesn't answer to ping, error: '%s'",
                          MYF(ME_BELL),mysql_error(mysql)); 
          return -1;
        }
      }
      mysql->reconnect=1;       /* Automatic reconnect is default */                  

I believe this is wrong, because this way the "doesn't answer" branch will never be reached. It should go like this:

      mysql->reconnect=0;       /* We want to know of reconnects */
      if (!mysql_ping(mysql))
      {
        if (option_silent < 2)
          puts("mysqld is alive");
      }
      else
      {
        if (mysql_errno(mysql) == CR_SERVER_GONE_ERROR)
        {
          mysql->reconnect=1;
          if (!mysql_ping(mysql))
            puts("connection was down, but mysqld is now alive");
          else
          {
            my_printf_error(0,"mysqld doesn't answer to ping, error: '%s'",
                            MYF(ME_BELL),mysql_error(mysql));
            return -1;
          }
        }
      }
      mysql->reconnect=1;       /* Automatic reconnect is default */                  

How to repeat:
It's actually not repeatable, because mysqladmin will not maintain a connection during subsequent invocations.

If you manage to shutdown the server between the 2. and 3. if test, it should be visible.

It's visible if you implement a PING command in mysql command line client (patch appended) and shutdown the server, restart it and try the ping command inside the mysql command line client.

Suggested fix:
Here's two patches for mysqladmin.cc to fix the problem and for mysql.cc to implement a ping command.

      mysql->reconnect=0;       /* We want to know of reconnects */
      if (!mysql_ping(mysql))
      {
        if (option_silent < 2)
          puts("mysqld is alive");
      }
      else
      {
        if (mysql_errno(mysql) == CR_SERVER_GONE_ERROR)
        {
          mysql->reconnect=1;
          if (!mysql_ping(mysql))
            puts("connection was down, but mysqld is now alive");
          else
          {
            my_printf_error(0,"mysqld doesn't answer to ping, error: '%s'",
                            MYF(ME_BELL),mysql_error(mysql));
            return -1;
          }
        }
      }
      mysql->reconnect=1;       /* Automatic reconnect is default */                  

*** mysql.cc.orig       Thu May  4 13:50:12 2006
--- mysql.cc    Thu May  4 14:17:31 2006
***************
*** 190,195 ****
--- 190,196 ----
  static int com_quit(String *str,char*),
           com_go(String *str,char*), com_ego(String *str,char*),
           com_print(String *str,char*),
+          com_ping(String *str,char*),
           com_help(String *str,char*), com_clear(String *str,char*),
           com_connect(String *str,char*), com_status(String *str,char*),
           com_use(String *str,char*), com_source(String *str, char*),
***************
*** 234,239 ****
--- 235,241 ----
  static COMMANDS commands[] = {
    { "?",      '?', com_help,   1, "Synonym for `help'." },
    { "clear",  'c', com_clear,  0, "Clear command."},
+   { "ping",  'S', com_ping,  0, "Ping server."},
    { "connect",'r', com_connect,1,
      "Reconnect to the server. Optional arguments are db and host." },
    { "delimiter", 'd', com_delimiter,    1,
***************
*** 1865,1870 ****
--- 1867,1896 ----
  }
  
  static int
+ com_ping(String *buffer __attribute__((unused)),
+        char *line __attribute__((unused)))
+ {
+   /* We want to know of redirects */
+   mysql.reconnect=0;
+   if (!mysql_ping(&mysql))
+     put_info("mysqld is alive", INFO_INFO);
+   else
+   {
+     /* Trying to reconnect */
+     if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR)
+     {
+       mysql.reconnect=1;
+       if (!mysql_ping(&mysql))
+         put_info("connection was down, but mysqld is now alive", INFO_INFO);
+       else
+         put_info("mysqld doesn't answer to ping", INFO_INFO);
+     }
+   }
+   /* Automatic reconnect is default */
+   mysql.reconnect=1;
+ }
+ 
+ static int
  com_help(String *buffer __attribute__((unused)),
         char *line __attribute__((unused)))
  {
[29 Jun 2006 18:01] Kai Voigt
Cut'n'paste mistake on my side. Here's the fix for mysqladmin.cc

*** mysqladmin.cc.orig  Thu May  4 14:14:43 2006
--- mysqladmin.cc       Thu May  4 14:15:36 2006
***************
*** 952,963 ****
          mysql->reconnect=1;
          if (!mysql_ping(mysql))
            puts("connection was down, but mysqld is now alive");
!       }
!       else
!       {
!         my_printf_error(0,"mysqld doesn't answer to ping, error: '%s'",
!                         MYF(ME_BELL),mysql_error(mysql));
!         return -1;
        }
        }
        mysql->reconnect=1;     /* Automatic reconnect is default */
--- 952,963 ----
          mysql->reconnect=1;
          if (!mysql_ping(mysql))
            puts("connection was down, but mysqld is now alive");
!         else
!           {
!           my_printf_error(0,"mysqld doesn't answer to ping, error: '%s'",
!                           MYF(ME_BELL),mysql_error(mysql));
!           return -1;
!         }
        }
        }
        mysql->reconnect=1;     /* Automatic reconnect is default */
[30 Jun 2006 13:10] Valeriy Kravchuk
Thank you for a problem report. For patches, please, use the latest -BK source (or, at least, the latest version released, 5.1.11).

I do not agree with you point, though:

> I believe this is wrong, because this way the "doesn't answer" branch will never
> be reached. It should go like this:

In this code:

      if (!mysql_ping(mysql))
      {
        if (option_silent < 2)
          puts("mysqld is alive");
      }
      else
      {
        if (mysql_errno(mysql) == CR_SERVER_GONE_ERROR)
        {
          mysql->reconnect=1;
          if (!mysql_ping(mysql))
            puts("connection was down, but mysqld is now alive");
        }
        else
        {
          my_printf_error(0,"mysqld doesn't answer to ping, error: '%s'",
                          MYF(ME_BELL),mysql_error(mysql));
          return -1;
        }
      }
      mysql->reconnect=1;       /* Automatic reconnect is default */

if mysql_ping returns CR_SERVER_GONE_ERROR, we ping it for a second time, and in case of ANY failure prints nothing. In case of any other error for the first mysql_ping, we print it. So, why do you think "mysqld doesn't answer to ping, error" wiil never be reached? There are two other possible errors, according to http://dev.mysql.com/doc/refman/5.1/en/mysql-ping.html.

With your change in place you'll never be informed about any of two other error codes (like CR_COMMANDS_OUT_OF_SYNC) for the initail connection! And this is important. So, I am not sure your patch should be applied.
[30 Jul 2006 23:00] Bugs System
No feedback was provided for this bug for over a month, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".