List:Commits« Previous MessageNext Message »
From:Andrei Elkin Date:March 17 2008 4:04pm
Subject:bk commit into 5.0 tree (aelkin:1.2598) BUG#18199
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of aelkin.  When aelkin does a push these changes
will be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2008-03-17 18:03:47+02:00, aelkin@mysql1000.(none) +5 -0
  Bug #18199  PURGE BINARY LOGS fails silently with missing logs;
  Bug #18453  Warning/error message if there is a mismatch between ...
   
  There were three problems:
   
   1. the reported lack of warnings for the BEFORE syntax of PURGE;
   2. the similar lack of warnings for the TO syntax;
   3. incompatible behaviour between the two in that the latter blanked out
      regardlessly of presence or lack the actual file corresponding to
      an index record; the former version gave up at the first mismatch.
  
  fixed with deploying the warning's generation and synronizing logics of 
  purge_logs() and purge_logs_before_date().
  my_stat() is called in either of two branches of purge_logs() (responsible
  for the TO syntax of PURGE) similarly to how it has behaved in the BEFORE syntax.
  If there is no actual binlog file, my_stat returns NULL and my_delete is
  not invoked.
  A critical error is reported to the user if a file from the index
  could not be retrieved info about or deleted with a system error code
  different than ENOENT.

  mysql-test/include/show_binary_logs.inc@stripped, 2008-03-17 18:03:45+02:00, aelkin@mysql1000.(none) +3 -0
    a new macro - shortcut of show binary logs

  mysql-test/include/show_binary_logs.inc@stripped, 2008-03-17 18:03:45+02:00, aelkin@mysql1000.(none) +0 -0

  mysql-test/r/binlog_index.result@stripped, 2008-03-17 18:03:45+02:00, aelkin@mysql1000.(none) +39 -0
    new results

  mysql-test/r/binlog_index.result@stripped, 2008-03-17 18:03:45+02:00, aelkin@mysql1000.(none) +0 -0

  mysql-test/t/binlog_index.test@stripped, 2008-03-17 18:03:45+02:00, aelkin@mysql1000.(none) +69 -0
    a regression test for the bugs

  mysql-test/t/binlog_index.test@stripped, 2008-03-17 18:03:45+02:00, aelkin@mysql1000.(none) +0 -0

  sql/log.cc@stripped, 2008-03-17 18:03:45+02:00, aelkin@mysql1000.(none) +132 -23
    generating warning in two functions.
    refining logics to call my_stat() by purge_logs() as it happens
    in purge_logs_before_date().
    my_delete() is called only if my_stat() ensured existance of the file.
    A critical error is reported to the user if a file from the index
    could not be my_stat():ed or my_delete():d with an error different
    than ENOENT.

  sql/share/errmsg.txt@stripped, 2008-03-17 18:03:45+02:00, aelkin@mysql1000.(none) +2 -0
    new error message

diff -Nrup a/mysql-test/include/show_binary_logs.inc b/mysql-test/include/show_binary_logs.inc
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/mysql-test/include/show_binary_logs.inc	2008-03-17 18:03:45 +02:00
@@ -0,0 +1,3 @@
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--replace_column 2 #
+show binary logs;
diff -Nrup a/mysql-test/r/binlog_index.result b/mysql-test/r/binlog_index.result
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/mysql-test/r/binlog_index.result	2008-03-17 18:03:45 +02:00
@@ -0,0 +1,39 @@
+flush logs;
+flush logs;
+flush logs;
+show binary logs;
+Log_name	File_size
+master-bin.000001	#
+master-bin.000002	#
+master-bin.000003	#
+master-bin.000004	#
+purge binary logs TO 'master-bin.000004';
+Warnings:
+Warning	1476	Being purged log MYSQLTEST_VARDIR/log/master-bin.000001 was not found
+*** must show a list starting from the 'TO' argument of PURGE ***
+show binary logs;
+Log_name	File_size
+master-bin.000004	#
+reset master;
+flush logs;
+flush logs;
+flush logs;
+*** must be a warning master-bin.000001 was not found ***
+Warnings:
+Warning	1476	Being purged log MYSQLTEST_VARDIR/log/master-bin.000001 was not found
+*** must show one record, of the active binlog, left in the index file after PURGE ***
+show binary logs;
+Log_name	File_size
+master-bin.000004	#
+reset master;
+flush logs;
+flush logs;
+flush logs;
+purge binary logs TO 'master-bin.000002';
+ERROR HY000: Fatal error during log purge
+show warnings;
+Level	Code	Message
+Error	1377	a problem with deleting MYSQLTEST_VARDIR/log/master-bin.000001; consider examining correspondence of your binlog index file to the actual binlog files
+Error	1377	Fatal error during log purge
+reset master;
+End of tests
diff -Nrup a/mysql-test/t/binlog_index.test b/mysql-test/t/binlog_index.test
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/mysql-test/t/binlog_index.test	2008-03-17 18:03:45 +02:00
@@ -0,0 +1,69 @@
+#
+# testing of purging of binary log files bug#18199/Bug#18453
+#
+source include/have_log_bin.inc;
+source include/not_embedded.inc;
+
+#
+# testing purge binary logs TO
+#
+
+flush logs;
+flush logs;
+flush logs;
+
+source include/show_binary_logs.inc;
+
+remove_file $MYSQLTEST_VARDIR/log/master-bin.000001;
+
+# there must be a warning with file names
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+purge binary logs TO 'master-bin.000004';
+
+--echo *** must show a list starting from the 'TO' argument of PURGE ***
+source include/show_binary_logs.inc;
+
+#
+# testing purge binary logs BEFORE
+#
+
+reset master;
+
+flush logs;
+flush logs;
+flush logs;
+remove_file $MYSQLTEST_VARDIR/log/master-bin.000001;
+
+--echo *** must be a warning master-bin.000001 was not found ***
+let $date=`select NOW()  +  INTERVAL 1 MINUTE`;
+--disable_query_log
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval purge binary logs BEFORE '$date';
+--enable_query_log
+
+--echo *** must show one record, of the active binlog, left in the index file after PURGE ***
+source include/show_binary_logs.inc;
+
+#
+# testing a fatal error
+# Turning a binlog file into a directory must be a portable setup
+# 
+
+reset master;
+
+flush logs;
+flush logs;
+flush logs;
+
+remove_file $MYSQLTEST_VARDIR/log/master-bin.000001;
+mkdir $MYSQLTEST_VARDIR/log/master-bin.000001;
+
+--error ER_BINLOG_PURGE_FATAL_ERR
+purge binary logs TO 'master-bin.000002';
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+show warnings;
+rmdir $MYSQLTEST_VARDIR/log/master-bin.000001;
+--disable_warnings
+reset master;
+--enable_warnings
+--echo End of tests
diff -Nrup a/sql/log.cc b/sql/log.cc
--- a/sql/log.cc	2008-01-31 17:15:35 +02:00
+++ b/sql/log.cc	2008-03-17 18:03:45 +02:00
@@ -1180,6 +1180,8 @@ int MYSQL_LOG::update_log_index(LOG_INFO
   RETURN VALUES
     0				ok
     LOG_INFO_EOF		to_log not found
+    LOG_INFO_FATAL              if any other than ENOENT error from
+                                my_stat() or my_delete()
 */
 
 int MYSQL_LOG::purge_logs(const char *to_log, 
@@ -1209,28 +1211,78 @@ int MYSQL_LOG::purge_logs(const char *to
          !log_in_use(log_info.log_file_name))
   {
     ulong file_size= 0;
-    if (decrease_log_space) //stat the file we want to delete
+    MY_STAT s, *lstat= my_stat(log_info.log_file_name, &s, MYF(0));
+    if (!lstat)
     {
-      MY_STAT s;
-
-      /* 
-         If we could not stat, we can't know the amount
-         of space that deletion will free. In most cases,
-         deletion won't work either, so it's not a problem.
-      */
-      if (my_stat(log_info.log_file_name,&s,MYF(0)))
-        file_size= s.st_size;
-      else
-	sql_print_information("Failed to execute my_stat on file '%s'",
+      if (my_errno == ENOENT) 
+      {
+        /*
+          It's not fatal if we can't stat a log file that does not exist;
+          If we could not stat, we can't know the amount
+          of space that deletion will free. In most cases,
+          deletion won't work either, so it's not a problem.
+        */     
+        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                            ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
+                            log_info.log_file_name);
+        sql_print_information("Failed to execute my_stat on file '%s'",
 			      log_info.log_file_name);
+        my_errno= 0;
+      }
+      else
+      {
+        /*
+          Other than ENOENT are fatal
+        */
+        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+                            ER_BINLOG_PURGE_FATAL_ERR,
+                            "a problem with getting info on being purged %s; "
+                            "consider examining correspondence "
+                            "of your binlog index file "
+                            "to the actual binlog files",
+                            log_info.log_file_name);
+        error= LOG_INFO_FATAL;
+        goto err;
+      }
     }
-    /*
-      It's not fatal if we can't delete a log file ;
-      if we could delete it, take its size into account
-    */
+    else if (decrease_log_space)
+    {
+      file_size= s.st_size;
+    }
+
     DBUG_PRINT("info",("purging %s",log_info.log_file_name));
-    if (!my_delete(log_info.log_file_name, MYF(0)) && decrease_log_space)
-      *decrease_log_space-= file_size;
+    if (lstat)
+    {
+      if (!my_delete(log_info.log_file_name, MYF(0)))
+      {
+        if (decrease_log_space)
+          *decrease_log_space-= file_size;
+      }
+      else
+      {
+        if (my_errno == ENOENT) 
+        {
+          push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                              ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
+                              log_info.log_file_name);
+          sql_print_information("Failed to delete file '%s'",
+                                log_info.log_file_name);
+          my_errno= 0;
+        }
+        else
+        {
+          push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+                              ER_BINLOG_PURGE_FATAL_ERR,
+                              "a problem with deleting %s; "
+                              "consider examining correspondence "
+                              "of your binlog index file "
+                              "to the actual binlog files",
+                              log_info.log_file_name);
+          error= LOG_INFO_FATAL;
+          goto err;
+        }
+      }
+    }
     if (find_next_log(&log_info, 0) || exit_loop)
       break;
   }
@@ -1263,6 +1315,8 @@ err:
   RETURN VALUES
     0				ok
     LOG_INFO_PURGE_NO_ROTATE	Binary file that can't be rotated
+    LOG_INFO_FATAL              if any other than ENOENT error from
+                                my_stat() or my_delete()
 */
 
 int MYSQL_LOG::purge_logs_before_date(time_t purge_time)
@@ -1286,11 +1340,66 @@ int MYSQL_LOG::purge_logs_before_date(ti
   while (strcmp(log_file_name, log_info.log_file_name) &&
 	 !log_in_use(log_info.log_file_name))
   {
-    /* It's not fatal even if we can't delete a log file */
-    if (!my_stat(log_info.log_file_name, &stat_area, MYF(0)) ||
-	stat_area.st_mtime >= purge_time)
-      break;
-    my_delete(log_info.log_file_name, MYF(0));
+    if (!my_stat(log_info.log_file_name, &stat_area, MYF(0)))
+    {
+      if (my_errno == ENOENT) 
+      {
+        /*
+          It's not fatal if we can't stat a log file that does not exist.
+        */     
+        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                            ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
+                            log_info.log_file_name);
+	sql_print_information("Failed to execute my_stat on file '%s'",
+			      log_info.log_file_name);
+        my_errno= 0;
+      }
+      else
+      {
+        /*
+          Other than ENOENT are fatal
+        */
+        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+                            ER_BINLOG_PURGE_FATAL_ERR,
+                            "a problem with getting info on being purged %s; "
+                            "consider examining correspondence "
+                            "of your binlog index file "
+                            "to the actual binlog files",
+                            log_info.log_file_name);
+        error= LOG_INFO_FATAL;
+        goto err;
+      }
+    }
+    else
+    {
+      if (stat_area.st_mtime >= purge_time)
+        break;
+      if (my_delete(log_info.log_file_name, MYF(0)))
+      {
+        if (my_errno == ENOENT) 
+        {
+          /* It's not fatal even if we can't delete a log file */
+          push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                              ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
+                              log_info.log_file_name);
+          sql_print_information("Failed to delete file '%s'",
+                                log_info.log_file_name);
+          my_errno= 0;
+        }
+        else
+        {
+          push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+                              ER_BINLOG_PURGE_FATAL_ERR,
+                              "a problem with deleting %s; "
+                              "consider examining correspondence "
+                              "of your binlog index file "
+                              "to the actual binlog files",
+                              log_info.log_file_name);
+          error= LOG_INFO_FATAL;
+          goto err;
+        }
+      }
+    }
     if (find_next_log(&log_info, 0))
       break;
   }
diff -Nrup a/sql/share/errmsg.txt b/sql/share/errmsg.txt
--- a/sql/share/errmsg.txt	2007-10-23 14:15:27 +03:00
+++ b/sql/share/errmsg.txt	2008-03-17 18:03:45 +02:00
@@ -5641,3 +5641,5 @@ ER_NAME_BECOMES_EMPTY
         eng "Name '%-.64s' has become ''"
 ER_AMBIGUOUS_FIELD_TERM
 	eng "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY"
+ER_LOG_PURGE_NO_FILE  
+	eng "Being purged log %s was not found"
Thread
bk commit into 5.0 tree (aelkin:1.2598) BUG#18199Andrei Elkin17 Mar