Below is the list of changes that have just been committed into a local
6.0 repository of cbell. When cbell 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, 2007-11-28 22:13:14-05:00, cbell@mysql_cab_desk. +7 -0
WL#4116 : Online Backup: Record Online Backup Progress
Patch 1 of 3
This patch contains a refactored locking thread class and struct.
sql/backup/be_default.cc@stripped, 2007-11-28 22:13:05-05:00, cbell@mysql_cab_desk. +17 -13
WL#4116 : Online Backup: Record Online Backup Progress
This patch modifies the default driver to use the refactored
locking thread.
It also adds calls to report progress as the tables are read
or written.
sql/backup/be_default.h@stripped, 2007-11-28 22:13:05-05:00, cbell@mysql_cab_desk. +3 -0
WL#4116 : Online Backup: Record Online Backup Progress
Adds variables to record start and stop times for table access
plus a row counter to record number of rows processed.
sql/backup/be_snapshot.cc@stripped, 2007-11-28 22:13:06-05:00, cbell@mysql_cab_desk. +13 -13
WL#4116 : Online Backup: Record Online Backup Progress
Modifications needed to use of refactored locking thread.
sql/backup/be_snapshot.h@stripped, 2007-11-28 22:13:07-05:00, cbell@mysql_cab_desk. +3 -3
WL#4116 : Online Backup: Record Online Backup Progress
Modifications needed to use of refactored locking thread.
sql/backup/be_thread.cc@stripped, 2007-11-28 22:13:08-05:00, cbell@mysql_cab_desk. +51 -50
WL#4116 : Online Backup: Record Online Backup Progress
Modifies locking thread to be a structure instead of a class.
This allows any class to use the locking thread and is required
for the online backup progress code.
sql/backup/be_thread.h@stripped, 2007-11-28 22:13:08-05:00, cbell@mysql_cab_desk. +35 -14
WL#4116 : Online Backup: Record Online Backup Progress
Modifies locking thread to be a structure instead of a class.
sql/backup/debug.h@stripped, 2007-11-28 22:13:09-05:00, cbell@mysql_cab_desk. +8 -1
WL#4116 : Online Backup: Record Online Backup Progress
Comments changed for breakpoint code.
diff -Nrup a/sql/backup/be_default.cc b/sql/backup/be_default.cc
--- a/sql/backup/be_default.cc 2007-11-14 15:15:12 -05:00
+++ b/sql/backup/be_default.cc 2007-11-28 22:13:05 -05:00
@@ -112,20 +112,21 @@ Backup::Backup(const Table_list &tables,
Backup_thread_driver(tables)
{
DBUG_PRINT("default_backup",("Creating backup driver"));
- m_thd= t_thd; /* save current thread */
+ locking_thd->m_thd= t_thd; /* save current thread */
cur_table= NULL; /* flag current table as null */
tbl_num= 0; /* set table number to 0 */
mode= INITIALIZE; /* initialize read */
- lock_thd= NULL; /* set lock thread to 0 */
+ locking_thd->lock_thd= NULL; /* set lock thread to 0 */
/*
Create a TABLE_LIST * list for iterating through the tables.
Initialize the list for opening the tables in read mode.
*/
- tables_in_backup= build_table_list(tables, lock_type);
- all_tables= tables_in_backup;
+ locking_thd->tables_in_backup= build_table_list(tables, lock_type);
+ all_tables= locking_thd->tables_in_backup;
init_phase_complete= FALSE;
locks_acquired= FALSE;
+ backup_prog_id= 0;
}
/**
@@ -138,7 +139,7 @@ Backup::Backup(const Table_list &tables,
result_t Backup::prelock()
{
DBUG_ENTER("Default_backup::prelock()");
- DBUG_RETURN(start_locking_thread());
+ DBUG_RETURN(locking_thd->start_locking_thread());
}
/**
@@ -173,7 +174,7 @@ result_t Backup::start_tbl_read(TABLE *t
*/
result_t Backup::end_tbl_read()
{
- int last_read_res;
+ int last_read_res;
DBUG_ENTER("Default_backup::end_tbl_read)");
last_read_res= hdl->ha_rnd_end();
@@ -196,15 +197,15 @@ int Backup::next_table()
DBUG_ENTER("Backup::next_table()");
if (cur_table == NULL)
{
- cur_table= tables_in_backup->table;
+ cur_table= locking_thd->tables_in_backup->table;
read_set= cur_table->read_set;
}
else
{
- tables_in_backup= tables_in_backup->next_global;
- if (tables_in_backup != NULL)
+ locking_thd->tables_in_backup= locking_thd->tables_in_backup->next_global;
+ if (locking_thd->tables_in_backup != NULL)
{
- cur_table= tables_in_backup->table;
+ cur_table= locking_thd->tables_in_backup->table;
read_set= cur_table->read_set;
}
else
@@ -291,7 +292,7 @@ result_t Backup::get_data(Buffer &buf)
buf.size= 0;
buf.table_no= 0;
buf.last= TRUE;
- switch (lock_state) {
+ switch (locking_thd->lock_state) {
case LOCK_ERROR: // Something ugly happened in locking
DBUG_RETURN(ERROR);
case LOCK_ACQUIRED: // First time lock ready for validity point
@@ -377,8 +378,8 @@ result_t Backup::get_data(Buffer &buf)
Optimization: If this is the last table to read, close the tables and
kill the lock thread. This only applies iff we are using the thread.
*/
- if (tables_in_backup->next_global == NULL)
- kill_locking_thread();
+ if (locking_thd->tables_in_backup->next_global == NULL)
+ locking_thd->kill_locking_thread();
}
else if (last_read_res != 0)
DBUG_RETURN(ERROR);
@@ -601,6 +602,8 @@ result_t Restore::truncate_table(TABLE *
*/
if ((last_write_res != 0) && (last_write_res != HA_ERR_WRONG_COMMAND))
DBUG_RETURN(ERROR);
+ table_access_start= (my_time_t)my_time(0);
+ num_rows= 0;
DBUG_RETURN(OK);
}
@@ -677,6 +680,7 @@ 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);
}
diff -Nrup a/sql/backup/be_default.h b/sql/backup/be_default.h
--- a/sql/backup/be_default.h 2007-11-14 15:15:13 -05:00
+++ b/sql/backup/be_default.h 2007-11-28 22:13:05 -05:00
@@ -193,6 +193,9 @@ class Restore: public Restore_driver
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.
+ my_time_t table_access_start; ///< Start of current table access
+ my_time_t table_access_stop; ///< End of current table access
+ ulonglong num_rows; ///< Number of rows in table
uint unpack(byte *packed_row);
};
diff -Nrup a/sql/backup/be_snapshot.cc b/sql/backup/be_snapshot.cc
--- a/sql/backup/be_snapshot.cc 2007-11-14 15:15:14 -05:00
+++ b/sql/backup/be_snapshot.cc 2007-11-28 22:13:06 -05:00
@@ -66,8 +66,7 @@ using namespace backup;
*
* @retval Error code or backup::OK on success.
*/
-result_t Engine::get_backup(const uint32, const Table_list &tables, Backup_driver*
-&drv)
+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);
@@ -85,12 +84,13 @@ result_t Backup::lock()
any other command type places the engine in a non-consistent read
state.
*/
- m_thd->lex->sql_command= SQLCOM_SELECT;
- m_thd->lex->start_transaction_opt|= MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT;
- int res= begin_trans(m_thd);
+ locking_thd->m_thd->lex->sql_command= SQLCOM_SELECT;
+ locking_thd->m_thd->lex->start_transaction_opt|=
+ MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT;
+ int res= begin_trans(locking_thd->m_thd);
if (res)
DBUG_RETURN(ERROR);
- lock_state= LOCK_ACQUIRED;
+ locking_thd->lock_state= LOCK_ACQUIRED;
BACKUP_BREAKPOINT("backup_cs_locked");
DBUG_RETURN(OK);
}
@@ -99,13 +99,13 @@ result_t Backup::get_data(Buffer &buf)
{
result_t res;
- if (!tables_open && (lock_state == LOCK_ACQUIRED))
+ if (!tables_open && (locking_thd->lock_state == LOCK_ACQUIRED))
{
BACKUP_BREAKPOINT("backup_cs_open_tables");
- open_and_lock_tables(m_thd, tables_in_backup);
+ open_and_lock_tables(locking_thd->m_thd, locking_thd->tables_in_backup);
tables_open= TRUE;
}
- if (lock_state == LOCK_ACQUIRED)
+ if (locking_thd->lock_state == LOCK_ACQUIRED)
BACKUP_BREAKPOINT("backup_cs_reading");
res= default_backup::Backup::get_data(buf);
@@ -116,11 +116,11 @@ 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 (lock_state == LOCK_SIGNAL)
+ if (locking_thd->lock_state == LOCK_SIGNAL)
{
- lock_state= LOCK_DONE; // set lock done so destructor won't wait
- end_active_trans(m_thd);
- close_thread_tables(m_thd);
+ locking_thd->lock_state= LOCK_DONE; // set lock done so destructor won't wait
+ end_active_trans(locking_thd->m_thd);
+ close_thread_tables(locking_thd->m_thd);
}
return(res);
}
diff -Nrup a/sql/backup/be_snapshot.h b/sql/backup/be_snapshot.h
--- a/sql/backup/be_snapshot.h 2007-11-14 15:15:14 -05:00
+++ b/sql/backup/be_snapshot.h 2007-11-28 22:13:07 -05:00
@@ -62,10 +62,10 @@ class Backup: public default_backup::Bac
default_backup::Backup(tables, t_thd, TL_READ) { tables_open= FALSE; };
virtual ~Backup()
{
- if (lock_state == LOCK_ACQUIRED)
+ if (locking_thd->lock_state == LOCK_ACQUIRED)
{
- end_active_trans(m_thd);
- close_thread_tables(m_thd);
+ end_active_trans(locking_thd->m_thd);
+ close_thread_tables(locking_thd->m_thd);
}
};
result_t begin(const size_t) { return backup::OK; };
diff -Nrup a/sql/backup/be_thread.cc b/sql/backup/be_thread.cc
--- a/sql/backup/be_thread.cc 2007-11-14 15:15:17 -05:00
+++ b/sql/backup/be_thread.cc 2007-11-28 22:13:08 -05:00
@@ -96,14 +96,14 @@ THD *create_new_thd()
*/
pthread_handler_t backup_thread_for_locking(void *arg)
{
- Backup_thread_driver *drv= static_cast<Backup_thread_driver *>(arg);
+ Locking_thread_st *locking_thd= static_cast<Locking_thread_st *>(arg);
DBUG_PRINT("info", ("Default_backup - lock_tables_in_separate_thread"));
/*
Turn off condition variable check for lock.
*/
- drv->lock_state= LOCK_NOT_STARTED;
+ locking_thd->lock_state= LOCK_NOT_STARTED;
#if !defined( __WIN__) /* Win32 calls this in pthread_create */
my_thread_init();
@@ -116,16 +116,16 @@ pthread_handler_t backup_thread_for_lock
*/
DBUG_PRINT("info",("Online backup creating THD struct for thread"));
THD *thd= create_new_thd();
- drv->lock_thd= thd;
+ locking_thd->lock_thd= thd;
if (thd == 0)
{
- drv->lock_state= LOCK_ERROR;
+ locking_thd->lock_state= LOCK_ERROR;
goto end2;
}
if (thd->killed)
{
- drv->lock_state= LOCK_ERROR;
+ locking_thd->lock_state= LOCK_ERROR;
goto end2;
}
@@ -133,10 +133,10 @@ pthread_handler_t backup_thread_for_lock
Now open and lock the tables.
*/
DBUG_PRINT("info",("Online backup open tables in thread"));
- if (!drv->tables_in_backup)
+ if (!locking_thd->tables_in_backup)
{
DBUG_PRINT("info",("Online backup locking error no tables to lock"));
- drv->lock_state= LOCK_ERROR;
+ locking_thd->lock_state= LOCK_ERROR;
goto end2;
}
@@ -145,16 +145,16 @@ pthread_handler_t backup_thread_for_lock
killing the thread. In this case, we need to close the tables
and exit.
*/
- if (!thd->killed && open_and_lock_tables(thd, drv->tables_in_backup))
+ if (!thd->killed && open_and_lock_tables(thd, locking_thd->tables_in_backup))
{
DBUG_PRINT("info",("Online backup locking thread dying"));
- drv->lock_state= LOCK_ERROR;
+ locking_thd->lock_state= LOCK_ERROR;
goto end;
}
if (thd->killed)
{
- drv->lock_state= LOCK_ERROR;
+ locking_thd->lock_state= LOCK_ERROR;
goto end;
}
@@ -162,15 +162,17 @@ pthread_handler_t backup_thread_for_lock
Part of work is done. Rest until woken up.
We wait if the thread is not killed and the driver has not signaled us.
*/
- pthread_mutex_lock(&drv->THR_LOCK_driver_thread);
- drv->lock_state= LOCK_ACQUIRED;
- thd->enter_cond(&drv->COND_driver_thread_wait, &drv->THR_LOCK_driver_thread,
- "Online backup driver thread: holding table locks");
- while (!thd->killed && (drv->lock_state != LOCK_SIGNAL))
- pthread_cond_wait(&drv->COND_driver_thread_wait, &drv->THR_LOCK_driver_thread);
- thd->exit_cond("Online backup driver thread: terminating");
+ pthread_mutex_lock(&locking_thd->THR_LOCK_thread);
+ locking_thd->lock_state= LOCK_ACQUIRED;
+ thd->enter_cond(&locking_thd->COND_thread_wait,
+ &locking_thd->THR_LOCK_thread,
+ "Locking thread: holding table locks");
+ while (!thd->killed && (locking_thd->lock_state != LOCK_SIGNAL))
+ pthread_cond_wait(&locking_thd->COND_thread_wait,
+ &locking_thd->THR_LOCK_thread);
+ thd->exit_cond("Locking thread: terminating");
- DBUG_PRINT("info",("Online backup driver thread locking thread terminating"));
+ DBUG_PRINT("info",("Locking thread locking thread terminating"));
/*
Cleanup and return.
@@ -179,44 +181,43 @@ end:
close_thread_tables(thd);
end2:
- pthread_mutex_lock(&drv->THR_LOCK_driver);
+ pthread_mutex_lock(&locking_thd->THR_LOCK_caller);
net_end(&thd->net);
my_thread_end();
delete thd;
- drv->lock_thd= NULL;
- if (drv->lock_state != LOCK_ERROR)
- drv->lock_state= LOCK_DONE;
+ locking_thd->lock_thd= NULL;
+ if (locking_thd->lock_state != LOCK_ERROR)
+ locking_thd->lock_state= LOCK_DONE;
/*
Signal the driver thread that it's ok to proceed with destructor.
*/
- pthread_cond_signal(&drv->COND_driver_wait);
- pthread_mutex_unlock(&drv->THR_LOCK_driver);
+ pthread_cond_signal(&locking_thd->COND_caller_wait);
+ pthread_mutex_unlock(&locking_thd->THR_LOCK_caller);
pthread_exit(0);
return (0);
}
/*
- Constructor for backup_thread_driver class.
+ Constructor for Locking_thread_st structure.
*/
-Backup_thread_driver::Backup_thread_driver(const Table_list &tables):
- Backup_driver(tables)
+Locking_thread_st::Locking_thread_st()
{
/*
Initialize the thread mutex and cond variable.
*/
- pthread_mutex_init(&THR_LOCK_driver_thread, MY_MUTEX_INIT_FAST);
- pthread_cond_init(&COND_driver_thread_wait, NULL);
- pthread_mutex_init(&THR_LOCK_driver, MY_MUTEX_INIT_FAST);
- pthread_cond_init(&COND_driver_wait, NULL);
+ pthread_mutex_init(&THR_LOCK_thread, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&COND_thread_wait, NULL);
+ pthread_mutex_init(&THR_LOCK_caller, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&COND_caller_wait, NULL);
lock_state= LOCK_NOT_STARTED;
lock_thd= NULL; // set to 0 as precaution for get_data being called too soon
};
/*
- Destructor for backup_thread_driver class.
+ Destructor for Locking_thread_st structure.
*/
-Backup_thread_driver::~Backup_thread_driver()
+Locking_thread_st::~Locking_thread_st()
{
/*
If the locking thread is not finished, we need to wait until
@@ -226,23 +227,23 @@ Backup_thread_driver::~Backup_thread_dri
if (lock_state != LOCK_DONE)
{
kill_locking_thread();
- pthread_mutex_lock(&THR_LOCK_driver);
- m_thd->enter_cond(&COND_driver_wait, &THR_LOCK_driver,
- "Online backup driver: waiting until locking thread is done");
+ pthread_mutex_lock(&THR_LOCK_caller);
+ m_thd->enter_cond(&COND_caller_wait, &THR_LOCK_caller,
+ "Locking thread: waiting until locking thread is done");
while (lock_state != LOCK_DONE)
- pthread_cond_wait(&COND_driver_wait, &THR_LOCK_driver);
- m_thd->exit_cond("Online backup driver: terminating");
+ pthread_cond_wait(&COND_caller_wait, &THR_LOCK_caller);
+ m_thd->exit_cond("Locking thread: terminating");
- DBUG_PRINT("info",("Online backup driver's locking thread terminated"));
+ DBUG_PRINT("info",("Locking thread's locking thread terminated"));
}
/*
Destroy the thread mutexes and cond variables.
*/
- pthread_mutex_destroy(&THR_LOCK_driver_thread);
- pthread_cond_destroy(&COND_driver_thread_wait);
- pthread_mutex_destroy(&THR_LOCK_driver);
- pthread_cond_destroy(&COND_driver_wait);
+ pthread_mutex_destroy(&THR_LOCK_thread);
+ pthread_cond_destroy(&COND_thread_wait);
+ pthread_mutex_destroy(&THR_LOCK_caller);
+ pthread_cond_destroy(&COND_caller_wait);
}
/**
@@ -251,9 +252,9 @@ Backup_thread_driver::~Backup_thread_dri
Launches a separate thread ("locking thread") which will lock
tables.
*/
-result_t Backup_thread_driver::start_locking_thread()
+result_t Locking_thread_st::start_locking_thread()
{
- DBUG_ENTER("Backup_thread_driver::start_locking_thread");
+ DBUG_ENTER("Locking_thread_st::start_locking_thread");
pthread_t th;
if (pthread_create(&th, &connection_attrib,
backup_thread_for_locking, this))
@@ -268,19 +269,19 @@ result_t Backup_thread_driver::start_loc
A mutex is used to prevent the locking thread from deleting the THD
structure until this operation is complete.
*/
-void Backup_thread_driver::kill_locking_thread()
+void Locking_thread_st::kill_locking_thread()
{
- DBUG_ENTER("Backup_thread_driver::kill_locking_thread");
- pthread_mutex_lock(&THR_LOCK_driver);
+ DBUG_ENTER("Locking_thread_st::kill_locking_thread");
+ pthread_mutex_lock(&THR_LOCK_caller);
if (lock_thd && (lock_state != LOCK_DONE) && (lock_state != LOCK_SIGNAL))
{
lock_state= LOCK_SIGNAL;
pthread_mutex_lock(&lock_thd->LOCK_delete);
lock_thd->awake(THD::KILL_CONNECTION);
pthread_mutex_unlock(&lock_thd->LOCK_delete);
- pthread_cond_signal(&COND_driver_thread_wait);
+ pthread_cond_signal(&COND_thread_wait);
}
- pthread_mutex_unlock(&THR_LOCK_driver);
+ pthread_mutex_unlock(&THR_LOCK_caller);
/*
This tells the CS driver that we're finished with the tables.
diff -Nrup a/sql/backup/be_thread.h b/sql/backup/be_thread.h
--- a/sql/backup/be_thread.h 2007-11-14 15:15:17 -05:00
+++ b/sql/backup/be_thread.h 2007-11-28 22:13:08 -05:00
@@ -44,6 +44,36 @@ THD *create_new_thd();
pthread_handler_t backup_thread_for_locking(void *arg);
/**
+ * @struct Locking_thread
+ *
+ * @brief Adds variables for using a locking thread for opening tables.
+ *
+ * The Backup_thread structure contains a mutex and condition variable
+ * for using a thread to open and lock the tables. This is meant to be a
+ * generic class that can be used elsewhere for opening and locking tables.
+ */
+struct Locking_thread_st
+{
+public:
+ Locking_thread_st();
+ ~Locking_thread_st();
+
+ pthread_mutex_t THR_LOCK_thread; ///< mutex for thread variables
+ pthread_cond_t COND_thread_wait; ///< condition variable for wait
+ pthread_mutex_t THR_LOCK_caller; ///< mutex for thread variables
+ pthread_cond_t COND_caller_wait; ///< condition variable for wait
+
+ TABLE_LIST *tables_in_backup; ///< List of tables used in backup
+ THD *lock_thd; ///< Locking thread pointer
+ LOCK_STATE lock_state; ///< Current state of the lock call
+ THD *m_thd; ///< Pointer to current thread struct.
+
+ result_t start_locking_thread();
+ void kill_locking_thread();
+
+}; // Locking_thread_st
+
+/**
* @class Backup_thread_driver
*
* @brief Adds variables for using a locking thread for opening tables.
@@ -58,22 +88,13 @@ class Backup_thread_driver : public Back
{
public:
- Backup_thread_driver(const backup::Table_list &tables);
- ~Backup_thread_driver();
-
- pthread_mutex_t THR_LOCK_driver_thread; ///< mutex for thread variables
- pthread_cond_t COND_driver_thread_wait; ///< condition variable for wait
- pthread_mutex_t THR_LOCK_driver; ///< mutex for thread variables
- pthread_cond_t COND_driver_wait; ///< condition variable for wait
- TABLE_LIST *tables_in_backup; ///< List of tables used in backup
- THD *lock_thd; ///< Locking thread pointer
- LOCK_STATE lock_state; ///< Current state of the lock call
- THD *m_thd; ///< Pointer to current thread struct.
-
- backup::result_t start_locking_thread();
- void kill_locking_thread();
+ Backup_thread_driver(const backup::Table_list &tables):
+ Backup_driver(tables) { locking_thd = new Locking_thread_st(); }
+ ~Backup_thread_driver() { delete locking_thd; }
+ Locking_thread_st *locking_thd;
}; // Backup_thread_driver class
+
#endif
diff -Nrup a/sql/backup/debug.h b/sql/backup/debug.h
--- a/sql/backup/debug.h 2007-11-09 16:13:07 -05:00
+++ b/sql/backup/debug.h 2007-11-28 22:13:09 -05:00
@@ -73,7 +73,8 @@ namespace backup {
text string that must be unique among the breakpoints. It is used in
the macro as a means of tagging the code for pausing and resuming
execution. Once the code is compiled, you can use a client connection
- to set and release the breakpoint.
+ to set and release the breakpoint. Be sure to use a separate connection
+ for getting, checking, and releasing locks.
<b><c>BACKUP_BREAKPOINT("<breakpoint_name>");</c></b>
@@ -241,6 +242,12 @@ namespace backup {
- When adding breakpoints, you must add a list item for each breakpoint
to the documentation for breakpoints. See the code for the macro
definition in @ref debug.h for details.
+ - You must use a dedicated connection for getting and releasing locks. Do
+ not issue a get_lock() or release_lock() in the same connection (thread) as
+ code that calls BACKUP_BREAKPOINT(). Using the same connection to get/release
+ locks and run code that issues BACKUP_BREAKPOINTs will result in an
+ assertion using DEBUG_ASSERT(thd->ull == NULL) from debug_sync_point() in
+ item_func.cc.
*/