List:Commits« Previous MessageNext Message »
From:Chuck Bell Date:June 12 2008 7:44pm
Subject:bzr push into mysql-6.0 branch (cbell:2634) Bug#36323
View as plain text  
 2634 Chuck Bell	2008-06-12
      BUG#36323 : The build-in backup/restore drivers should support cancel() API call
        
      Patch changes default drivers to allow cancel operation in middle of
      operation. Also allows for better cleanup in event of an error in the
      driver.
modified:
  sql/backup/be_default.cc
  sql/backup/be_default.h
  sql/backup/be_snapshot.cc
  sql/backup/be_snapshot.h

=== modified file 'sql/backup/be_default.cc'
--- a/sql/backup/be_default.cc	2008-05-14 16:28:33 +0000
+++ b/sql/backup/be_default.cc	2008-06-12 17:43:47 +0000
@@ -127,6 +127,31 @@ Backup::Backup(const Table_list &tables,
   all_tables= locking_thd->tables_in_backup;
   init_phase_complete= FALSE;
   locks_acquired= FALSE;
+  hdl= NULL;
+  m_cleanup= TRUE;
+}
+
+/**
+  Cleanup backup
+
+  This method provides a means to stop a current backup by allowing
+  the driver to shutdown gracefully. The method call ends the current
+  table read then attempts to kill the locking thread if it is still
+  running.
+*/
+result_t Backup::cleanup()
+{
+  DBUG_ENTER("Default_backup::cleanup()");
+  DBUG_PRINT("backup",("Default driver - stop backup"));
+  if (m_cleanup)
+  {
+    m_cleanup= FALSE;
+    if (hdl)
+      end_tbl_read();
+    if (locking_thd)
+      locking_thd->kill_locking_thread();
+  }
+  DBUG_RETURN(OK);
 }
 
 /**
@@ -160,7 +185,10 @@ result_t Backup::start_tbl_read(TABLE *t
   hdl= tbl->file;
   last_read_res= hdl->ha_rnd_init(1);
   if (last_read_res != 0)
+  {
+    hdl= NULL;
     DBUG_RETURN(ERROR);
+  }
   DBUG_RETURN(OK);
 }
 
@@ -177,7 +205,12 @@ result_t Backup::end_tbl_read()
   int last_read_res;
 
   DBUG_ENTER("Default_backup::end_tbl_read)");
+
+  if (!hdl)
+    DBUG_RETURN(OK);
+
   last_read_res= hdl->ha_rnd_end();
+  hdl= NULL;
   if (last_read_res != 0)
     DBUG_RETURN(ERROR);
   DBUG_RETURN(OK);
@@ -316,6 +349,11 @@ result_t Backup::get_data(Buffer &buf)
   buf.last= FALSE;
 
   /* 
+    get_data() should not be called after cancel has been called.
+  */
+  DBUG_ASSERT(mode != CANCEL);
+
+  /* 
     Determine mode of operation and execute mode.
   */
   switch (mode) {
@@ -586,6 +624,25 @@ Restore::Restore(const Table_list &table
 }
 
 /**
+  Cleanup restore
+
+  This method provides a means to stop a current restore by allowing
+  the driver to shutdown gracefully. The method call closes the
+  table list by calling end() method.
+*/
+result_t Restore::cleanup()
+{
+  DBUG_ENTER("Default_backup::cleanup()");
+  DBUG_PRINT("backup",("Default driver - stop restore"));
+  if (m_cleanup)
+  {
+    m_cleanup= FALSE;
+    end();
+  }
+  DBUG_RETURN(OK);
+}
+
+/**
   * @brief Truncate table.
   *
   * This method saves the handler for the table and deletes all rows in
@@ -726,6 +783,11 @@ result_t Restore::send_data(Buffer &buf)
   DBUG_PRINT("default_restore",("Got packet with %lu bytes from stream %u",
                                 (unsigned long)buf.size, buf.table_num));
   
+  /* 
+    get_data() should not be called after cancel has been called.
+  */
+  DBUG_ASSERT(mode != CANCEL);
+
   /* 
     Determine mode of operation and execute mode.
   */

=== modified file 'sql/backup/be_default.h'
--- a/sql/backup/be_default.h	2008-05-14 00:24:06 +0000
+++ b/sql/backup/be_default.h	2008-06-12 17:43:47 +0000
@@ -84,7 +84,11 @@ class Backup: public Backup_thread_drive
   public:
     enum has_data_info { YES, WAIT, EOD };
     Backup(const Table_list &tables, THD *t_thd, thr_lock_type lock_type);
-    virtual ~Backup() { backup::free_table_list(all_tables); }; 
+    virtual ~Backup() 
+    { 
+      cleanup();
+      backup::free_table_list(all_tables); 
+    }; 
     size_t size()  { return UNKNOWN_SIZE; };
     size_t init_size() { return 0; };
     result_t  begin(const size_t) { return backup::OK; };
@@ -92,7 +96,12 @@ class Backup: public Backup_thread_drive
     result_t get_data(Buffer &buf);
     result_t lock() { return backup::OK; };
     result_t unlock() { return backup::OK; };
-    result_t cancel() { return backup::OK; };
+    result_t cancel() 
+    { 
+      mode= CANCEL;
+      cleanup();
+      return backup::OK;
+    }
     TABLE_LIST *get_table_list() { return all_tables; }
     void free() { delete this; };
     result_t prelock(); 
@@ -101,6 +110,9 @@ class Backup: public Backup_thread_drive
     TABLE *cur_table;              ///< The table currently being read.
     my_bool init_phase_complete;   ///< Used to identify end of init phase.
     my_bool locks_acquired;        ///< Used to help kernel synchronize drivers.
+    handler *hdl;                  ///< Pointer to table handler.
+    my_bool m_cleanup;             ///< Is call to cleanup() needed?
+    result_t end_tbl_read(); 
 
   private:
     /*
@@ -110,6 +122,7 @@ class Backup: public Backup_thread_drive
     */
     typedef enum {
       INITIALIZE,                  ///< Indicates time to initialize read
+      CANCEL,                      ///< Indicates time to cancel operation
       GET_NEXT_TABLE,              ///< Open next table in the list
       READ_RCD,                    ///< Reading rows from table mode
       READ_RCD_BUFFER,             ///< Buffer records mode
@@ -119,11 +132,9 @@ class Backup: public Backup_thread_drive
     } BACKUP_MODE;
 
     result_t start_tbl_read(TABLE *tbl);
-    result_t end_tbl_read();
     int next_table();
     BACKUP_MODE mode;              ///< Indicates which mode the code is in
     int tbl_num;                   ///< The index of the current table.
-    handler *hdl;                  ///< Pointer to table handler.
     uint *cur_blob;                ///< The current blob field.
     uint *last_blob_ptr;           ///< Position of last blob field.
     MY_BITMAP *read_set;           ///< The file read set.
@@ -132,6 +143,7 @@ class Backup: public Backup_thread_drive
     byte *ptr;                     ///< Pointer to blob data from record.
     TABLE_LIST *all_tables;        ///< Reference to list of tables used.
 
+    result_t cleanup();
     uint pack(byte *rcd, byte *packed_row);
 };
 
@@ -151,11 +163,20 @@ class Restore: public Restore_driver
   public:
     enum has_data_info { YES, WAIT, EOD };
     Restore(const Table_list &tables, THD *t_thd);
-    virtual ~Restore() { backup::free_table_list(all_tables); };
+    virtual ~Restore()
+    { 
+      cleanup();
+      backup::free_table_list(all_tables); 
+    }; 
     result_t  begin(const size_t) { return backup::OK; };
     result_t  end();
     result_t  send_data(Buffer &buf);
-    result_t  cancel() { return backup::OK; };
+    result_t  cancel()
+    { 
+      mode= CANCEL;
+      cleanup();
+      return backup::OK;
+    }
     TABLE_LIST *get_table_list() { return all_tables; }
     void free() { delete this; };
 
@@ -167,6 +188,7 @@ class Restore: public Restore_driver
     */
     typedef enum {
       INITIALIZE,                  ///< Indicates time to initialize read
+      CANCEL,                      ///< Indicates time to cancel operation
       GET_NEXT_TABLE,              ///< Open next table in the list
       WRITE_RCD,                   ///< Writing rows from table mode
       CHECK_BLOBS,                 ///< See if record has blobs
@@ -191,7 +213,9 @@ class Restore: public Restore_driver
     THD *m_thd;                    ///< Pointer to current thread struct.
     TABLE_LIST *all_tables;        ///< Reference to list of tables used.
     ulonglong num_rows;            ///< Number of rows in table
+    my_bool m_cleanup;             ///< Is call to cleanup() needed?
 
+    result_t cleanup();
     uint unpack(byte *packed_row);
 };
 } // default_backup namespace

=== modified file 'sql/backup/be_snapshot.cc'
--- a/sql/backup/be_snapshot.cc	2008-06-04 14:41:39 +0000
+++ b/sql/backup/be_snapshot.cc	2008-06-12 17:43:47 +0000
@@ -77,6 +77,44 @@ result_t Engine::get_backup(const uint32
   DBUG_RETURN(OK);
 }
 
+/**
+  Cleanup backup
+
+  This method provides a means to stop a current backup by allowing
+  the driver to shutdown gracefully. The method call ends the current
+  transaction and closes the tables.
+*/
+result_t Backup::cleanup()
+{
+  DBUG_ENTER("Default_backup::cleanup()");
+  DBUG_PRINT("backup",("Snapshot driver - stop backup"));
+  if (m_cleanup)
+  {
+    m_cleanup= FALSE;
+    locking_thd->lock_state= LOCK_DONE; // set lock done so destructor won't wait
+    if (m_trans_start)
+    {
+      ha_autocommit_or_rollback(locking_thd->m_thd, 0);
+      end_active_trans(locking_thd->m_thd);
+      m_trans_start= FALSE;
+    }
+    if (tables_open)
+    {
+      if (hdl)
+        default_backup::Backup::end_tbl_read();
+      close_thread_tables(locking_thd->m_thd);
+      tables_open= FALSE;
+    }
+  }
+  DBUG_RETURN(OK);
+}
+
+/**
+  Lock the tables
+
+  This method creates the consistent read transaction and acquires the read
+  lock.
+*/
 result_t Backup::lock()
 {
   DBUG_ENTER("Snapshot_backup::lock()");
@@ -91,6 +129,7 @@ result_t Backup::lock()
   int res= begin_trans(locking_thd->m_thd);
   if (res)
     DBUG_RETURN(ERROR);
+  m_trans_start= TRUE;
   locking_thd->lock_state= LOCK_ACQUIRED;
   BACKUP_BREAKPOINT("backup_cs_locked");
   DBUG_RETURN(OK);
@@ -123,13 +162,8 @@ result_t Backup::get_data(Buffer &buf)
     being set to LOCK_SIGNAL from parent::get_data(). This is set
     after the last table is finished reading.
   */
-  if (locking_thd->lock_state == LOCK_SIGNAL)
-  {
-    locking_thd->lock_state= LOCK_DONE; // set lock done so destructor won't wait
-    ha_autocommit_or_rollback(locking_thd->m_thd, 0);
-    end_active_trans(locking_thd->m_thd);
-    close_thread_tables(locking_thd->m_thd);
-  }
+  if ((locking_thd->lock_state == LOCK_SIGNAL) || m_cancel)
+    cleanup();
   return(res);
 }
 

=== modified file 'sql/backup/be_snapshot.h'
--- a/sql/backup/be_snapshot.h	2008-03-04 16:06:28 +0000
+++ b/sql/backup/be_snapshot.h	2008-06-12 17:43:47 +0000
@@ -59,24 +59,31 @@ class Backup: public default_backup::Bac
 {
   public:
     Backup(const Table_list &tables, THD *t_thd) 
-      :default_backup::Backup(tables, t_thd, TL_READ) { tables_open= FALSE; };
-    virtual ~Backup()
-    {
-      if (locking_thd->lock_state == LOCK_ACQUIRED)
-      {
-        end_active_trans(locking_thd->m_thd);
-        close_thread_tables(locking_thd->m_thd);
-      }
+      :default_backup::Backup(tables, t_thd, TL_READ) 
+    { 
+      tables_open= FALSE;
+      m_cancel= FALSE;
+      m_trans_start= FALSE;
     };
+    virtual ~Backup() { cleanup(); };
     result_t begin(const size_t) { return backup::OK; };
     result_t end() { return backup::OK; };
     result_t get_data(Buffer &buf);
     result_t prelock() { return backup::READY; }
     result_t lock();
     result_t unlock() { return backup::OK; };
-    result_t cancel() { return backup::OK; };
+    result_t cancel() 
+    { 
+      m_cancel= TRUE;
+      cleanup();
+      return backup::OK;
+    }
   private:
     my_bool tables_open;   ///< Indicates if tables are open
+    my_bool m_cancel;      ///< Cancel backup
+    my_bool m_trans_start; ///< Is transaction stated?
+
+   result_t cleanup();
 };
 
 /**

Thread
bzr push into mysql-6.0 branch (cbell:2634) Bug#36323Chuck Bell12 Jun