List:Commits« Previous MessageNext Message »
From:Rafal Somla Date:July 8 2008 10:18pm
Subject:bzr commit into mysql-6.0-backup branch (rsomla:2652)
View as plain text  
#At file:///ext/mysql/bzr/mysql-6.0-backup/

 2652 Rafal Somla	2008-07-08 [merge]
      Auto merge.
added:
  sql/backup/be_logical.h
modified:
  sql/backup/Makefile.am
  sql/backup/backup_kernel.h
  sql/backup/be_default.cc
  sql/backup/be_default.h
  sql/backup/be_snapshot.cc
  sql/backup/be_snapshot.h
  sql/backup/data_backup.cc
  sql/backup/image_info.h
  sql/backup/kernel.cc
  storage/myisam/myisam_backup_engine.cc

=== modified file 'sql/backup/Makefile.am'
--- a/sql/backup/Makefile.am	2008-06-26 16:20:30 +0000
+++ b/sql/backup/Makefile.am	2008-07-07 12:51:56 +0000
@@ -61,6 +61,7 @@ noinst_HEADERS = \
   backup_info.h \
   restore_info.h \
   be_native.h \
+  be_logical.h \
   be_default.h \
   be_snapshot.h \
   be_nodata.h \

=== modified file 'sql/backup/backup_kernel.h'
--- a/sql/backup/backup_kernel.h	2008-06-26 12:10:46 +0000
+++ b/sql/backup/backup_kernel.h	2008-07-07 12:51:56 +0000
@@ -115,6 +115,14 @@ class Backup_restore_ctx: public backup:
   void disable_fkey_constraints();
   int  restore_triggers_and_events();
   
+  /** 
+    Indicates if tables have been locked with @c lock_tables_for_restore()
+  */
+  bool m_tables_locked; 
+
+  int lock_tables_for_restore();
+  int unlock_tables();
+  
   friend class Backup_info;
   friend class Restore_info;
   friend int backup_init();

=== modified file 'sql/backup/be_default.cc'
--- a/sql/backup/be_default.cc	2008-07-01 20:32:27 +0000
+++ b/sql/backup/be_default.cc	2008-07-08 19:58:46 +0000
@@ -80,33 +80,6 @@ using backup::Buffer;
 
 using namespace backup;
 
-Engine::Engine(THD *t_thd)
-{
-  m_thd= t_thd;
-}
-
-/**
-  * Create a default backup backup driver.
-  *
-  * Given a list of tables to be backed-up, create instance of backup
-  * driver which will create backup image of these tables.
-  *
-  * @param  tables (in) list of tables to be backed-up.
-  * @param  eng    (out) pointer to backup driver instance.
-  *
-  * @retval  ERROR  if cannot create backup driver class.
-  * @retval  OK     on success.
-  */
-result_t Engine::get_backup(const uint32, const Table_list &tables,
-                            Backup_driver* &drv)
-{
-  DBUG_ENTER("Engine::get_backup");
-  Backup *ptr= new default_backup::Backup(tables, m_thd, TL_READ_NO_INSERT);
-  if (!ptr)
-    DBUG_RETURN(ERROR);
-  drv= ptr;
-  DBUG_RETURN(OK);
-}
 
 Backup::Backup(const Table_list &tables, THD *t_thd, thr_lock_type lock_type)
   :Backup_thread_driver(tables)
@@ -122,8 +95,28 @@ Backup::Backup(const Table_list &tables,
      Create a TABLE_LIST * list for iterating through the tables.
      Initialize the list for opening the tables in read mode.
   */
-  locking_thd->tables_in_backup= build_table_list(tables, lock_type);
-  all_tables= locking_thd->tables_in_backup;
+  all_tables= (TABLE_LIST*)my_malloc(tables.count()*sizeof(TABLE_LIST), 
+                                     MYF(MY_WME | MY_ZEROFILL));
+  DBUG_ASSERT(all_tables); // TODO: report error instead
+
+  for (uint i=0; i < tables.count(); ++i)
+  {
+    Table_ref   tbl= tables[i];
+    TABLE_LIST &tl= all_tables[i];
+
+    tl.alias= tl.table_name= const_cast<char*>(tbl.name().ptr());
+    tl.db= const_cast<char*>(tbl.db().name().ptr());
+    tl.lock_type= lock_type;
+
+    // link previous entry to this one
+    if (i > 0)
+    {
+      all_tables[i-1].next_global= all_tables[i-1].next_local=
+      all_tables[i-1].next_name_resolution_table= &tl;
+    }    
+  }
+
+  locking_thd->tables_in_backup= all_tables;
   init_phase_complete= FALSE;
   locks_acquired= FALSE;
   hdl= NULL;
@@ -368,25 +361,21 @@ result_t Backup::get_data(Buffer &buf)
   */
   case GET_NEXT_TABLE:
   {
-    mode= READ_RCD;
-    int res= next_table();
-    /*
-      If no more tables in list, tell backup algorithm we're done else
-      fall through to reading mode.
-    */
-    if (res)
+    if (tbl_num >= m_tables.count())
     {
       buf.last= TRUE;
       buf.size= 0;
       buf.table_num= 0;
-      DBUG_RETURN(OK);
-    }
-    else
-    {
-      start_tbl_read(cur_table);
-      tbl_num++;
-      buf.table_num= tbl_num;
+      DBUG_RETURN(DONE);
     }
+
+    cur_table= all_tables[tbl_num++].table;
+    DBUG_ASSERT(cur_table); // tables should be opened at that time
+    read_set=  cur_table->read_set;
+    start_tbl_read(cur_table);
+
+    buf.table_num= tbl_num;
+    mode= READ_RCD;
   }
 
   /*
@@ -579,31 +568,9 @@ result_t Backup::get_data(Buffer &buf)
   DBUG_RETURN(OK); 
 }
 
-/**
-  * Create a default backup restore driver.
-  *
-  * Given a list of tables to be restored, create instance of restore
-  * driver which will restore these tables from a backup image.
-  *
-  * @param  version  (in) version of the backup image.
-  * @param  tables   (in) list of tables to be restored.
-  * @param  eng      (out) pointer to restore driver instance.
-  *
-  * @retval ERROR  if cannot create restore driver class.
-  * @retval OK     on success.
-  */
-result_t Engine::get_restore(version_t, const uint32, 
-                             const Table_list &tables, Restore_driver* &drv)
-{
-  DBUG_ENTER("Engine::get_restore");
-  Restore *ptr= new default_backup::Restore(tables, m_thd);
-  if (!ptr)
-    DBUG_RETURN(ERROR);
-  drv= ptr;
-  DBUG_RETURN(OK);
-}
 
-Restore::Restore(const Table_list &tables, THD *t_thd) :Restore_driver(tables)
+Restore::Restore(const backup::Logical_snapshot &snap, THD *t_thd) 
+  :Restore_driver(snap.get_table_list()), m_snap(snap)
 {
   DBUG_PRINT("default_backup",("Creating restore driver"));
   m_thd= t_thd;         /* save current thread */
@@ -611,12 +578,6 @@ Restore::Restore(const Table_list &table
   tbl_num= 0;           /* set table number to 0 */
   mode= INITIALIZE;     /* initialize write */
 
-  /*
-     Create a TABLE_LIST * list for iterating through the tables.
-     Initialize the list for opening the tables in write mode.
-  */
-  tables_in_backup= build_table_list(tables, TL_WRITE);
-  all_tables= tables_in_backup;
   for (int i=0; i < MAX_FIELDS; i++)
     blob_ptrs[i]= 0;
   blob_ptr_index= 0;
@@ -651,23 +612,7 @@ result_t Restore::cleanup()
   * @retval OK     rows deleted.
   * @retval ERROR  problem with deleting rows.
   */
-result_t Restore::truncate_table(TABLE *tbl)
-{
-  int last_write_res; 
 
-  DBUG_ENTER("Default_backup::truncate_table)");
-  DBUG_ASSERT(tbl->file);
-  hdl= tbl->file;
-  last_write_res= cur_table->file->ha_delete_all_rows();
-  /*
-    Check to see if delete all rows was ok. Ignore if the handler
-    doesn't support it.
-  */
-  if ((last_write_res != 0) && (last_write_res != HA_ERR_WRONG_COMMAND))
-    DBUG_RETURN(ERROR);
-  num_rows= 0;
-  DBUG_RETURN(OK);
-}
 
 /**
   * @brief End restore process.
@@ -679,7 +624,6 @@ result_t Restore::truncate_table(TABLE *
 result_t Restore::end()
 {
   DBUG_ENTER("Restore::end");
-  close_thread_tables(m_thd);
   DBUG_RETURN(OK);
 }
 
@@ -692,42 +636,7 @@ result_t Restore::end()
   * @retval 0   no errors.
   * @retval -1  no more tables in list.
   */
-int Restore::next_table()
-{
-  DBUG_ENTER("Restore::next_table()");
-  if (cur_table == NULL)
-    cur_table= tables_in_backup->table;
-  else
-  {
-    /*
-      Restore original timestamp autoset type.
-    */
-    if (cur_table && cur_table->timestamp_field)
-      cur_table->timestamp_field_type= old_tm;
-    tables_in_backup= tables_in_backup->next_global;
-    if (tables_in_backup != NULL)
-    {
-      DBUG_ASSERT(tables_in_backup->table);
-      cur_table= tables_in_backup->table;
-    }
-    else
-    {
-      cur_table= NULL;
-      DBUG_RETURN(-1);
-    }
-  } 
-  /*
-    Save original timestamp autoset type and switch to TIMESTAMP_NO_AUTO_SET
-    so that any restored data with timestamp fields will not have their values
-    reset on write.
-  */
-  if (cur_table && cur_table->timestamp_field)
-  {
-    old_tm= cur_table->timestamp_field->get_auto_set_type();
-    cur_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
-  }
-  DBUG_RETURN(0);
-}
+
 
 /**
   * @brief Unpack the data for a row in the table.
@@ -759,7 +668,6 @@ uint Restore::unpack(byte *packed_row)
     error= unpack_row(NULL, cur_table, n_fields, packed_row, &cols, &cur_row_end,
&length);
     if (!use_bitbuf)
       bitmap_free(&cols);
-    num_rows++;
   }
   DBUG_RETURN(error);
 }
@@ -809,57 +717,11 @@ result_t Restore::send_data(Buffer &buf)
   switch (mode) {
 
   /*
-    Nothing to do in Initialize, continue to GET_NEXT_TABLE.
+    Nothing to do in Initialize, continue to WRITE_RCD.
   */
   case INITIALIZE:
 
   /*
-    If class has been initialized and we need to read the next table,
-    advance the current table pointer and initialize read process.
-  */
-  case GET_NEXT_TABLE:
-  {
-    int res;
-
-    mode= WRITE_RCD;
-    /*
-      It is possible for the backup system to send data to this
-      engine out of sequence from the table list. When a non-sequential
-      access is detected, start the table list at the beginning and
-      find the table in question. This is needed if any tables (more
-      than MAX_RETRIES are empty!
-    */
-    if ((tbl_num + 1) == buf.table_num) //do normal sequential lookup
-      res= next_table();
-    else                                //do linear search
-    {
-      uint i= 0;
-
-      cur_table= NULL;
-      tables_in_backup= all_tables;
-      do
-      {
-        i++;
-        res= next_table();
-      }
-      while ((i != buf.table_num) && !res);
-      tbl_num= i - 1;
-    }
-    if (res)
-    {
-      buf.last= TRUE;
-      buf.size= 0;
-      buf.table_num= 0;
-      DBUG_RETURN(OK);
-    }
-    else
-    {
-      truncate_table(cur_table); /* delete all rows from table */
-      tbl_num++;
-    }
-  }
-
-  /*
     Write a row to the table from the data in the buffer.
   */
   case WRITE_RCD:
@@ -867,17 +729,32 @@ result_t Restore::send_data(Buffer &buf)
     cur_blob= 0;
     max_blob_size= 0;
 
+    // We don't process any data on stream #0
+    if (buf.table_num == 0)
+      DBUG_RETURN(OK);
+
+    // We only proccess data for the tables we are restoring.
+    if (buf.table_num > m_tables.count())
+      DBUG_RETURN(OK);
+
     /*
-      If the table number is different from the stream number, we're
-      receiving data from the backup for a different table. Set the mode to
-      get the next table in the list.
+     Get the opened table instance corresponding to buf.table_num. Note that
+     tables are opened (and locked) by the kernel.
     */
-    if (tbl_num != buf.table_num)
-    {
-      mode= GET_NEXT_TABLE;
-      DBUG_RETURN(PROCESSING);
-    }
-    else
+    cur_table= m_snap.get_opened_table(buf.table_num - 1);
+    DBUG_ASSERT(cur_table); // All tables we are processing should be opened.
+
+    /*
+      Change timestamp autoset type to TIMESTAMP_NO_AUTO_SET
+      so that any restored data with timestamp fields will not have their values
+      reset on write.
+    */
+    if (cur_table->timestamp_field)
+      cur_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
+
+    hdl= cur_table->file;
+    DBUG_ASSERT(hdl); // table should be opened
+
     {
       uint32 size= buf.size - META_SIZE;
       block_type= *buf.data;

=== modified file 'sql/backup/be_default.h'
--- a/sql/backup/be_default.h	2008-06-12 19:54:19 +0000
+++ b/sql/backup/be_default.h	2008-07-07 12:51:56 +0000
@@ -3,6 +3,7 @@
 
 #include <backup_engine.h>
 #include <backup/image_info.h>  // to define default backup image class
+#include <backup/be_logical.h>
 #include <backup/buffer_iterator.h>
 #include <backup/be_thread.h>
 
@@ -31,42 +32,6 @@ const byte BLOB_FIRST= (3U<<1); // First
 const byte BLOB_DATA=  (3U<<2); // Intermediate data block for blob buffer
 const byte BLOB_LAST=  (3U<<3); // Last data block in buffer for blob buffer
 
-/**
- * @class Engine
- *
- * @brief Encapsulates default online backup/restore functionality.
- *
- * This class is used to initiate the default backup algorithm, which is used
- * by the backup kernel to create a backup image of data stored in any
- * engine that does not have a native backup driver. It may also be used as
- * an option by the user.
- *
- * Using this class, the caller can create an instance of the default backup
- * backup and restore class. The backup class is used to backup data for a
- * list of tables. The restore class is used to restore data from a
- * previously created default backup image.
- */
-class Engine: public Backup_engine
-{
-  public:
-    Engine(THD *t_thd);
-
-    /*
-      Return version of backup images created by this engine.
-    */
-    const version_t version() const { return 0; };
-    result_t get_backup(const uint32, const Table_list &tables, 
-                        Backup_driver* &drv);
-    result_t get_restore(const version_t ver, const uint32, const Table_list &tables,
-                         Restore_driver* &drv);
-
-    /*
-     Free any resources allocated by the default backup engine.
-    */
-    void free() { delete this; }
-  private:
-    THD *m_thd; ///< Pointer to the current thread.
-};
 
 /**
  * @class Backup
@@ -87,7 +52,7 @@ class Backup: public Backup_thread_drive
     virtual ~Backup() 
     { 
       cleanup();
-      backup::free_table_list(all_tables); 
+      my_free(all_tables, MYF(0)); 
     }; 
     size_t size()  { return UNKNOWN_SIZE; };
     size_t init_size() { return 0; };
@@ -134,7 +99,7 @@ class Backup: public Backup_thread_drive
     result_t start_tbl_read(TABLE *tbl);
     int next_table();
     BACKUP_MODE mode;              ///< Indicates which mode the code is in
-    int tbl_num;                   ///< The index of the current table.
+    ulong tbl_num;                   ///< The index of the current table.
     uint *cur_blob;                ///< The current blob field.
     uint *last_blob_ptr;           ///< Position of last blob field.
     MY_BITMAP *read_set;           ///< The file read set.
@@ -162,11 +127,10 @@ class Restore: public Restore_driver
 {
   public:
     enum has_data_info { YES, WAIT, EOD };
-    Restore(const Table_list &tables, THD *t_thd);
+    Restore(const backup::Logical_snapshot &info, THD *t_thd);
     virtual ~Restore()
     { 
       cleanup();
-      backup::free_table_list(all_tables); 
     }; 
     result_t  begin(const size_t) { return backup::OK; };
     result_t  end();
@@ -177,7 +141,6 @@ class Restore: public Restore_driver
       cleanup();
       return backup::OK;
     }
-    TABLE_LIST *get_table_list() { return all_tables; }
     void free() { delete this; };
 
  private:
@@ -196,8 +159,10 @@ class Restore: public Restore_driver
       WRITE_BLOB_BUFFER            ///< Buffer blobs mode
     } RESTORE_MODE;
 
-    result_t truncate_table(TABLE *tbl);
-    int next_table();
+    /**
+      Reference to the corresponding logical snapshot object.
+    */
+    const backup::Logical_snapshot &m_snap;  
     RESTORE_MODE mode;             ///< Indicates which mode the code is in
     uint tbl_num;                  ///< The index of the current table.
     uint32 max_blob_size;          ///< The total size (sum of parts) for the blob.
@@ -207,12 +172,9 @@ class Restore: public Restore_driver
     uint *last_blob_ptr;           ///< Position of last blob field.
     Buffer_iterator rec_buffer;    ///< Buffer iterator for windowing records
     Buffer_iterator blob_buffer;   ///< Buffer iterator for windowing BLOB fields
-    TABLE_LIST *tables_in_backup;  ///< List of tables used in backup.
     byte *blob_ptrs[MAX_FIELDS];   ///< List of blob pointers used
     int blob_ptr_index;            ///< Position in blob pointer list
     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
     timestamp_auto_set_type old_tm;///< Save old timestamp auto set type.
     my_bool m_cleanup;             ///< Is call to cleanup() needed?
 
@@ -232,13 +194,13 @@ namespace backup {
 
 class Logger;
 
-class Default_snapshot: public Snapshot_info
+class Default_snapshot: public Logical_snapshot
 {
  public:
 
-  Default_snapshot(Logger&) :Snapshot_info(1) // current version number is 1
+  Default_snapshot(Logger&) :Logical_snapshot(1) // current version number is 1
   {}
-  Default_snapshot(Logger&, const version_t ver) :Snapshot_info(ver)
+  Default_snapshot(Logger&, const version_t ver) :Logical_snapshot(ver)
   {}
 
   enum_snap_type type() const
@@ -268,10 +230,10 @@ class Default_snapshot: public Snapshot_
                                             TL_READ_NO_INSERT)) ? OK : ERROR; }
 
   result_t get_restore_driver(Restore_driver* &ptr)
-  { return (ptr= new default_backup::Restore(m_tables, ::current_thd)) ? OK : ERROR; }
+  { return (ptr= new default_backup::Restore(*this, ::current_thd)) ? OK : ERROR; }
 
   bool is_valid(){ return TRUE; };
-
+  
 };
 
 } // backup namespace

=== added file 'sql/backup/be_logical.h'
--- a/sql/backup/be_logical.h	1970-01-01 00:00:00 +0000
+++ b/sql/backup/be_logical.h	2008-07-07 12:51:56 +0000
@@ -0,0 +1,56 @@
+#ifndef _BE_LOGICAL_H_
+#define _BE_LOGICAL_H_
+
+/** 
+  @file
+
+  This header contains definitions needed for "logical" backup/restore 
+  drivers which access tables using handlerton interface. The built-in
+  drivers are of this type.
+*/ 
+
+#include <backup/image_info.h> // For definition of Snapshot_info
+
+class Backup_restore_ctx;
+
+namespace backup {
+
+/**
+  Extends Snapshot_info with methods for accessing tables opened in the server.
+*/
+class Logical_snapshot :public Snapshot_info
+{
+public:
+
+  Logical_snapshot(version_t ver) :Snapshot_info(ver) {}
+  TABLE*      get_opened_table(ulong pos) const;
+  const Table_list& get_table_list() const;
+};
+
+/**
+  Get opened TABLE structure for the table at position @c pos.
+
+  This method should be called only after tables have been opened and locked
+  by the backup kernel.
+*/ 
+inline
+TABLE *Logical_snapshot::get_opened_table(ulong pos) const
+{
+  Image_info::Table *t= get_table(pos);
+
+  // If we have table at pos, then the m_table pointer should be set for it.
+  DBUG_ASSERT(!t || t->m_table);
+
+  return t ? t->m_table->table : NULL;
+}
+
+inline
+const Table_list& Logical_snapshot::get_table_list() const
+{
+  return m_tables;
+}
+
+} // backup namespace
+
+
+#endif /*BE_LOGICAL_H_*/

=== modified file 'sql/backup/be_snapshot.cc'
--- a/sql/backup/be_snapshot.cc	2008-06-25 13:39:04 +0000
+++ b/sql/backup/be_snapshot.cc	2008-07-07 12:51:56 +0000
@@ -56,27 +56,6 @@ using backup::Buffer;
 using namespace backup;
 
 /**
- * Create a snapshot backup backup driver.
- *
- * Given a list of tables to be backed-up, create instance of backup
- * driver which will create backup image of these tables.
- *
- * @param  tables (in) list of tables to be backed-up.
- * @param  eng    (out) pointer to backup driver instance.
- *
- * @retval Error code or backup::OK on success.
- */
-result_t Engine::get_backup(const uint32, const Table_list &tables, Backup_driver*
&drv)
-{
-  DBUG_ENTER("Engine::get_backup");
-  Backup *ptr= new snapshot_backup::Backup(tables, m_thd);
-  if (!ptr)
-    DBUG_RETURN(ERROR);
-  drv= (backup::Backup_driver *)ptr;
-  DBUG_RETURN(OK);
-}
-
-/**
   Cleanup backup
 
   This method provides a means to stop a current backup by allowing
@@ -167,29 +146,6 @@ result_t Backup::get_data(Buffer &buf)
   return(res);
 }
 
-/**
- * Create a snapshot backup restore driver.
- *
- * Given a list of tables to be restored, create instance of restore
- * driver which will restore these tables from a backup image.
- *
- * @param  version  (in) version of the backup image.
- * @param  tables   (in) list of tables to be restored.
- * @param  eng      (out) pointer to restore driver instance.
- *
- * @retval Error code or backup::OK on success.
- */
-result_t Engine::get_restore(version_t, const uint32, const Table_list &tables,
-Restore_driver* &drv)
-{
-  DBUG_ENTER("Engine::get_restore");
-  Restore *ptr= new snapshot_backup::Restore(tables, m_thd);
-  if (!ptr)
-    DBUG_RETURN(ERROR);
-  drv= ptr;
-  DBUG_RETURN(OK);
-}
-
 } /* snapshot_backup namespace */
 
 

=== modified file 'sql/backup/be_snapshot.h'
--- a/sql/backup/be_snapshot.h	2008-06-12 17:43:47 +0000
+++ b/sql/backup/be_snapshot.h	2008-07-07 12:51:56 +0000
@@ -15,36 +15,6 @@ using backup::Table_ref;
 using backup::Buffer;
 
 /**
- * @class Engine
- *
- * @brief Encapsulates snapshot online backup/restore functionality.
- *
- * This class is used to initiate the snapshot backup algorithm, which is used
- * by the backup kernel to create a backup image of data stored in any
- * engine that does not have a native backup driver but supports consisten reads.
- * It may also be used as an option by the user.
- *
- * Using this class, the caller can create an instance of the snapshot backup
- * backup and restore class. The backup class is used to backup data for a
- * list of tables. The restore class is used to restore data from a
- * previously created snapshot backup image.
- */
-class Engine: public Backup_engine
-{
-  public:
-    Engine(THD *t_thd) { m_thd= t_thd; }
-
-    /// Return version of backup images created by this engine.
-    const version_t version() const { return 0; };
-    result_t get_backup(const uint32, const Table_list &tables, Backup_driver*
-&drv);
-    result_t get_restore(const version_t ver, const uint32, const Table_list &tables,
-                         Restore_driver* &drv);
-  private:
-    THD *m_thd;     ///< Pointer to the current thread.
-};
-
-/**
  * @class Backup
  *
  * @brief Contains the snapshot backup algorithm backup functionality.
@@ -100,8 +70,8 @@ class Backup: public default_backup::Bac
 class Restore: public default_backup::Restore
 {
   public:
-    Restore(const Table_list &tables, THD *t_thd)
-      :default_backup::Restore(tables, t_thd){};
+    Restore(const backup::Logical_snapshot &snap, THD *t_thd)
+      :default_backup::Restore(snap, t_thd){};
     virtual ~Restore(){};
     void free() { delete this; };
 };
@@ -117,13 +87,13 @@ class Restore: public default_backup::Re
 namespace backup {
 
 
-class CS_snapshot: public Snapshot_info
+class CS_snapshot: public Logical_snapshot
 {
  public:
 
-  CS_snapshot(Logger&) :Snapshot_info(1) // current version number is 1
+  CS_snapshot(Logger&) :Logical_snapshot(1) // current version number is 1
   {}
-  CS_snapshot(Logger&, version_t ver) :Snapshot_info(ver)
+  CS_snapshot(Logger&, version_t ver) :Logical_snapshot(ver)
   {}
 
   enum_snap_type type() const
@@ -143,7 +113,7 @@ class CS_snapshot: public Snapshot_info
   { return (ptr= new snapshot_backup::Backup(m_tables, ::current_thd)) ? OK : ERROR; }
 
   result_t get_restore_driver(Restore_driver* &ptr)
-  { return (ptr= new snapshot_backup::Restore(m_tables, ::current_thd)) ? OK : ERROR; }
+  { return (ptr= new snapshot_backup::Restore(*this, ::current_thd)) ? OK : ERROR; }
 
   bool is_valid(){ return TRUE; };
 

=== modified file 'sql/backup/data_backup.cc'
--- a/sql/backup/data_backup.cc	2008-07-02 07:53:34 +0000
+++ b/sql/backup/data_backup.cc	2008-07-07 12:51:56 +0000
@@ -288,58 +288,6 @@ class Scheduler::Pump: public Backup_pum
   { return start_pos + bytes_in; }
 };
 
-/*
-  Collect tables from default and snapshot for open and lock tables.
-  There should be at most only 1 of each driver.
-*/
-int get_default_snapshot_tables(backup::Backup_driver *backup_drv,
-                                backup::Restore_driver *restore_drv,
-                                TABLE_LIST **tables,
-                                TABLE_LIST **tables_last)
-{
-  TABLE_LIST *table_list= *tables;
-  TABLE_LIST *table_list_last= *tables_last;
-
-  DBUG_ENTER("backup::get_default_snapshot_tables");
-  /*
-    If the table list is defined and the last pointer is
-    defined then we are seeing a duplicate of either default
-    or snapshot drivers. There should be at most 1 of each.
-  */
-  if (table_list && table_list_last->next_global)
-  {
-    DBUG_PRINT("restore",("Duplicate default or snapshot subimage"));
-    DBUG_RETURN(ERROR);
-  }
-  /*
-    If the table list is empty, use the first one and loop
-    until the end then record the end of the first one.
-  */
-  if (!table_list)
-  {
-    if (backup_drv)
-      table_list= ((default_backup::Backup *)backup_drv)->get_table_list();
-    else if (restore_drv)
-      table_list= ((default_backup::Restore *)restore_drv)->get_table_list();
-    else
-      DBUG_RETURN(ERROR);
-    *tables= table_list;
-    table_list_last= table_list;
-    while (table_list_last->next_global != NULL)
-      table_list_last= table_list_last->next_global;
-    *tables_last= table_list_last;
-  }
-  else
-    if (backup_drv)
-     (*tables_last)->next_global=
-                      ((default_backup::Backup *)backup_drv)->get_table_list();
-    else if (restore_drv)
-     (*tables_last)->next_global=
-                    ((default_backup::Restore *)restore_drv)->get_table_list();
-    else
-      DBUG_RETURN(ERROR);
-  DBUG_RETURN(0);
-}
 
 /**
    Commit Blocker
@@ -1370,11 +1318,6 @@ int restore_table_data(THD *thd, Restore
 
   Restore_driver* drv[256];
 
-  TABLE_LIST *table_list= 0;
-  TABLE_LIST *table_list_last= 0;
-  List<obs::Obj> tables_to_lock;
-  obs::Name_locker *table_name_locker= new obs::Name_locker(thd);
-
   if (info.snap_count() > 256)
   {
     info.m_ctx.fatal_error(ER_BACKUP_TOO_MANY_IMAGES, info.snap_count(), 256);
@@ -1399,56 +1342,8 @@ int restore_table_data(THD *thd, Restore
     {
       info.m_ctx.fatal_error(ER_BACKUP_CREATE_RESTORE_DRIVER, snap->name());
       goto error;
-    };
-    
-    /*
-      Collect tables from default and snapshot for open and lock tables.
-      There should be at most only 1 of each driver.
-    */
-    if ((snap->type() == Snapshot_info::DEFAULT_SNAPSHOT) ||
-        (snap->type() == Snapshot_info::CS_SNAPSHOT))
-      get_default_snapshot_tables(NULL, (default_backup::Restore *)drv[n],
-                                  &table_list, &table_list_last);
-    /*
-      Collect tables from all drivers for name locking.
-    */
-    Image_info::Tables *snap_table_list= snap->get_table_list();
-    for (uint i= 0; i < snap_table_list->count(); i++)
-    {
-      Image_info::Table *tbl= snap_table_list->get_table(i);
-      tables_to_lock.push_front(tbl->m_obj_ptr);
-    }
-  }
-
-  /*
-    Open tables for default and snapshot drivers.
-  */
-  if (table_list)
-  {
-    table_list->lock_type= TL_WRITE;
-    query_cache.invalidate_locked_for_write(table_list);
-
-    // The lex needs to be cleaned up between consecutive calls to 
-    // open_and_lock_tables. Otherwise, open_and_lock_tables will try to open
-    // previously opened views and crash.
-    ::current_thd->lex->cleanup_after_one_table_open();
-    if (open_and_lock_tables(::current_thd, table_list))
-    {
-      info.m_ctx.fatal_error(ER_BACKUP_OPEN_TABLES, "restore");
-      DBUG_RETURN(backup::ERROR);
-    }
-    if (table_list_last)
-      table_list_last->next_global= NULL; // break lists
-  }
-
-  /*
-    Apply name locks to all tables used.
-  */
-  if (table_name_locker->get_name_locks(&tables_to_lock, TL_WRITE))
-  {
-    info.m_ctx.fatal_error(ER_BACKUP_OBTAIN_NAME_LOCK_FAILED);
-    goto error;
-  }
+    };   
+ }
 
   // Initialize the drivers.
   for (uint n=0; n < info.snap_count(); ++n)
@@ -1614,37 +1509,12 @@ int restore_table_data(THD *thd, Restore
       info.m_ctx.report_error(ER_BACKUP_STOP_RESTORE_DRIVERS, bad_drivers.c_ptr());
   }
 
-  /*
-    Release name locks on driver tables.
-  */
-  if (table_name_locker->release_name_locks())
-    info.m_ctx.fatal_error(ER_BACKUP_RELEASE_NAME_LOCK_FAILED);
-  delete table_name_locker;
-
-  /*
-    Close all tables if default or snapshot driver used.
-  */
-  if (table_list)
-    close_thread_tables(::current_thd);
-
-  { // If auto commit is turned off, be sure to commit the transaction
-    THD *thd=::current_thd;
-    if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
-    {
-      if (ha_autocommit_or_rollback(thd, 0)) state=ERROR;
-      if (end_active_trans(thd)) state=ERROR;
-    }
-  }
-
   DBUG_RETURN(state == ERROR ? backup::ERROR : 0);
 
  error:
 
   DBUG_PRINT("restore",("Cancelling restore process"));
 
-  if (table_name_locker)
-    delete table_name_locker;
-
   for (uint n=0; n < info.snap_count(); ++n)
   {
     if (!drv[n])

=== modified file 'sql/backup/image_info.h'
--- a/sql/backup/image_info.h	2008-07-01 20:32:27 +0000
+++ b/sql/backup/image_info.h	2008-07-07 12:51:56 +0000
@@ -5,6 +5,8 @@
 #include <backup_stream.h> // for st_bstream_* types
 #include <backup/backup_aux.h>  // for Map template
 
+class Backup_restore_ctx;
+
 namespace backup {
 
 /********************************************************************
@@ -13,8 +15,8 @@ namespace backup {
  
  ********************************************************************/ 
 
-
 class Snapshot_info;
+class Logical_snapshot;
 
 /**
   Describes contents of a backup image.
@@ -140,6 +142,7 @@ public: // public interface
   // friends
 
   friend class Snapshot_info;
+  friend class backup::Logical_snapshot; // needs access to Tables class
 };
 
 Image_info::Obj* find_obj(const Image_info &info, 
@@ -257,7 +260,7 @@ class Snapshot_info
 
   virtual ~Snapshot_info();
 
-  Image_info::Tables *get_table_list() { return &m_tables; }
+  Image_info::Table* get_table(ulong pos) const;
 
  protected:
  
@@ -268,8 +271,7 @@ class Snapshot_info
   // Methods for adding and accessing tables stored in the table list.
 
   int add_table(Image_info::Table &t, ulong pos);
-  Image_info::Table* get_table(ulong pos);
- 
+
   // IMPLEMENTATION
  
   Image_info::Tables m_tables; ///< List of tables stored in this image.
@@ -487,6 +489,7 @@ class Image_info::Table
 {
   const Db &m_db;     ///< The database to which this table belongs.
   Table  *next_table; ///< Used to crate a linked list of tables in a database.
+  TABLE_LIST  *m_table; ///< If not NULL, points at opened table.
 
  public:
 
@@ -498,11 +501,14 @@ class Image_info::Table
 
   friend class Db;
   friend class Dbobj_iterator;
+  friend class Logical_snapshot;     // reads m_table
+  friend class ::Backup_restore_ctx; // sets m_table
 };
 
 inline
 Image_info::Table::Table(const Db &db, const ::String &name)
-  :Table_ref(db.name(), Image_info::Obj::m_name), m_db(db), next_table(NULL)
+  :Table_ref(db.name(), Image_info::Obj::m_name), m_db(db), next_table(NULL),
+   m_table(NULL)
 {
   bzero(&base, sizeof(base));
   base.base.type= BSTREAM_IT_TABLE;
@@ -1073,7 +1079,7 @@ int Snapshot_info::add_table(Image_info:
 
 /// Get table at a given position
 inline
-Image_info::Table* Snapshot_info::get_table(ulong pos)
+Image_info::Table* Snapshot_info::get_table(ulong pos) const
 {
   return m_tables.get_table(pos);
 }

=== modified file 'sql/backup/kernel.cc'
--- a/sql/backup/kernel.cc	2008-07-01 13:34:36 +0000
+++ b/sql/backup/kernel.cc	2008-07-08 19:58:46 +0000
@@ -194,6 +194,8 @@ execute_backup_command(THD *thd, LEX *le
 
     res= context.do_restore();      
 
+    DEBUG_SYNC(thd, "restore_before_end");
+
     if (res)
       DBUG_RETURN(send_error(context, ER_BACKUP_RESTORE));
     
@@ -328,7 +330,8 @@ backup::Mem_allocator *Backup_restore_ct
 
 Backup_restore_ctx::Backup_restore_ctx(THD *thd)
  :Logger(thd), m_state(CREATED), m_thd_options(thd->options),
-  m_error(0), m_path(NULL), m_remove_loc(FALSE), m_stream(NULL), m_catalog(NULL)
+  m_error(0), m_path(NULL), m_remove_loc(FALSE), m_stream(NULL),
+  m_catalog(NULL), m_tables_locked(FALSE)
 {
   /*
     Check for progress tables.
@@ -631,6 +634,91 @@ Backup_restore_ctx::prepare_for_restore(
   return info;
 }
 
+/*
+  Lock tables being restored.
+
+  Backup kernel ensures that all tables being restored are exclusively locked.
+
+  We use open_and_lock_tables() for locking. This is a temporary solution until
+  a better mechanism is devised - open_and_lock_tables() is not good if there
+  are many tables to be processed.
+
+  The built-in restore drivers need to open tables to write rows to them. Since
+  we have opened tables here, we store pointers to opened TABLE_LIST structures
+  in the restore catalogue so that the built-in drivers can access them later.
+
+  @todo Replace open_and_lock_tables() by a lighter solution.
+  @todo Hide table locking behind the server API.
+*/ 
+int Backup_restore_ctx::lock_tables_for_restore()
+{
+  TABLE_LIST *tables= NULL;
+
+  /*
+    Iterate over all tables in all snapshots and create a linked TABLE_LIST
+    for call to open_and_lock_tables(). Store pointers to TABLE_LIST structures
+    in the restore catalogue for later access to opened tables.
+  */ 
+
+  for (uint s= 0; s < m_catalog->snap_count(); ++s)
+  {
+    backup::Snapshot_info *snap= m_catalog->m_snap[s];
+
+    for (ulong t=0; t < snap->table_count(); ++t)
+    {
+      TABLE_LIST *ptr= (TABLE_LIST*)alloc_root(m_thd->mem_root, 
+                                               sizeof(TABLE_LIST)); 
+      DBUG_ASSERT(ptr);  // FIXME: report error instead
+      bzero(ptr, sizeof(TABLE_LIST));
+
+      backup::Image_info::Table *tbl= snap->get_table(t);
+
+      ptr->alias= ptr->table_name= const_cast<char*>(tbl->name().ptr());
+      ptr->db= const_cast<char*>(tbl->db().name().ptr());
+      ptr->lock_type= TL_WRITE;
+
+      tbl->m_table= ptr;
+
+      ptr->next_global= ptr->next_local= ptr->next_name_resolution_table=
tables;
+      tables= ptr;
+    }
+  }
+
+  /*
+    Open and lock the tables.
+    
+    Note: simple_open_n_lock_tables() must be used here since we don't want
+    to do derived tables processing. Processing derived tables even leads 
+    to crashes as those reported in BUG#34758.
+  */ 
+  if (simple_open_n_lock_tables(m_thd,tables))
+  {
+    fatal_error(ER_BACKUP_OPEN_TABLES,"RESTORE");
+    return m_error;
+  }
+
+  m_tables_locked= TRUE;
+  return 0;
+}
+
+/**
+  Unlock tables which were locked by @c lock_tables_for_restore.
+ */ 
+int Backup_restore_ctx::unlock_tables()
+{
+  // Do nothing if tables are not locked.
+  if (!m_tables_locked)
+    return 0;
+
+  DBUG_PRINT("restore",("unlocking tables"));
+
+  close_thread_tables(m_thd);
+  m_tables_locked= FALSE;
+
+  return 0;
+}
+
+
 /**
   Destroy a backup/restore context.
   
@@ -652,6 +740,19 @@ int Backup_restore_ctx::close()
 
   time_t when= my_time(0);
 
+  // If auto commit is turned off, be sure to commit the transaction
+  // TODO: move it to the big switch, case: MYSQLCOM_BACKUP?
+
+  if (m_thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+  {
+    ha_autocommit_or_rollback(m_thd, 0);
+    end_active_trans(m_thd);
+  }
+
+  // unlock tables if they are still locked
+
+  unlock_tables();
+
   // unfreeze meta-data
 
   obs::ddl_blocker_disable();
@@ -889,12 +990,28 @@ int Backup_restore_ctx::do_restore()
     It should be fixed inside object services implementation and then the
     following line should be removed.
    */
+  close_thread_tables(m_thd);
   m_thd->main_da.reset_diagnostics_area();
 
+  if (lock_tables_for_restore()) // reports errors
+    DBUG_RETURN(m_error);
+
   // Here restore drivers are created to restore table data
   if (restore_table_data(m_thd, info, s)) // reports errors
     DBUG_RETURN(ER_BACKUP_RESTORE);
 
+  unlock_tables();
+
+  /* 
+   Re-create all triggers and events (it was not done in @c bcat_create_item()).
+
+   Note: it is important to do that after tables are unlocked, otherwise 
+   creation of these objects will fail.
+  */
+
+  if (restore_triggers_and_events())
+     DBUG_RETURN(ER_BACKUP_RESTORE);
+
   DBUG_PRINT("restore",("Done."));
 
   if (read_summary(info, s))
@@ -904,18 +1021,12 @@ int Backup_restore_ctx::do_restore()
   }
 
   /* 
-   Re-create all triggers and events (it was not done in @c bcat_create_item()).
-  */
-
-  if (restore_triggers_and_events())
-     DBUG_RETURN(ER_BACKUP_RESTORE);
-  
-  /* 
     FIXME: this call is here because object services doesn't clean the
     statement execution context properly, which leads to assertion failure.
     It should be fixed inside object services implementation and then the
     following line should be removed.
    */
+  close_thread_tables(m_thd);
   m_thd->main_da.reset_diagnostics_area();
 
   report_stats_post(info);

=== modified file 'storage/myisam/myisam_backup_engine.cc'
--- a/storage/myisam/myisam_backup_engine.cc	2008-07-07 10:21:31 +0000
+++ b/storage/myisam/myisam_backup_engine.cc	2008-07-08 20:18:10 +0000
@@ -1594,6 +1594,7 @@ result_t Log_restore::post_restore()
   mi_exl.max_files= open_files_limit;
   if (mi_examine_log(&mi_exl))
     SET_STATE_TO_ERROR_AND_DBUG_RETURN;
+
   DBUG_RETURN(backup::OK);
 }
 

Thread
bzr commit into mysql-6.0-backup branch (rsomla:2652) Rafal Somla8 Jul