diff --git a/mysql-test/main/backup_server_block.result b/mysql-test/main/backup_server_block.result new file mode 100644 index 0000000000000..ce9b5582a68dd --- /dev/null +++ b/mysql-test/main/backup_server_block.result @@ -0,0 +1,32 @@ +connect con1,localhost,root,,test; +connect con2,localhost,root,,test; +connection con1; +SET DEBUG_SYNC='after_backup_server_lock_acquired SIGNAL in_progress WAIT_FOR finish'; +BACKUP SERVER TO '/some_directory'; +connection default; +SET DEBUG_SYNC='now WAIT_FOR in_progress'; +connection con2; +BACKUP SERVER TO '/other_directory'; +connection default; +SET @con2_id = ; +SELECT COMMAND, STATE, INFO FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = @con2_id; +COMMAND STATE INFO +Query Waiting for backup lock BACKUP SERVER TO '/other_directory' +SET DEBUG_SYNC='now SIGNAL finish'; +connection con1; +connection default; +connection con2; +connection default; +SET DEBUG_SYNC='RESET'; +BACKUP STAGE START; +connection con2; +BACKUP SERVER TO '/another_directory'; +connection default; +SELECT COMMAND, STATE, INFO FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = @con2_id; +COMMAND STATE INFO +Query Waiting for backup lock BACKUP SERVER TO '/another_directory' +BACKUP STAGE END; +connection con2; +connection default; +disconnect con1; +disconnect con2; diff --git a/mysql-test/main/backup_server_block.test b/mysql-test/main/backup_server_block.test new file mode 100644 index 0000000000000..8214367e0ea9e --- /dev/null +++ b/mysql-test/main/backup_server_block.test @@ -0,0 +1,86 @@ +# Check that BACKUP SERVER blocks when another BACKUP SERVER is in progress + +--source include/have_debug_sync.inc + +--connect (con1,localhost,root,,test) +--connect (con2,localhost,root,,test) + +--connection con1 +# Simulate long-running backup by blocking it on a debug sync point +SET DEBUG_SYNC='after_backup_server_lock_acquired SIGNAL in_progress WAIT_FOR finish'; +--replace_result $MYSQLTEST_VARDIR +--send_eval BACKUP SERVER TO '$MYSQLTEST_VARDIR/some_directory' + +--connection default +# Wait for the "long-running" backup to lock the system +SET DEBUG_SYNC='now WAIT_FOR in_progress'; + +--connection con2 +let $con2_id= `SELECT CONNECTION_ID()`; +# Attempt a backup while the other backup is running +--replace_result $MYSQLTEST_VARDIR +--send_eval BACKUP SERVER TO '$MYSQLTEST_VARDIR/other_directory' + +--connection default +# Check that the backup on con2 is waiting for the backup on con1 +--replace_result $con2_id +eval SET @con2_id = $con2_id; +let $wait_condition= + SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE ID = @con2_id AND State = 'Waiting for backup lock'; +--source include/wait_condition.inc +--replace_result $MYSQLTEST_VARDIR +SELECT COMMAND, STATE, INFO FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = @con2_id; + +SET DEBUG_SYNC='now SIGNAL finish'; + +--connection con1 +--reap + +--connection default +# When "long running" backup finishes, check that the backup on con2 +# is also allowed to finish +let $wait_condition= + SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE Info LIKE 'BACKUP SERVER TO %' AND State = 'Waiting for backup lock'; +--source include/wait_condition.inc + +--connection con2 +--reap + +--connection default +SET DEBUG_SYNC='RESET'; + +# Test that BACKUP SERVER blocks when a BACKUP STAGE process is in progress + +BACKUP STAGE START; + +--connection con2 +--replace_result $MYSQLTEST_VARDIR +--send_eval BACKUP SERVER TO '$MYSQLTEST_VARDIR/another_directory' + +--connection default +let $wait_condition= + SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE ID = @con2_id AND State = 'Waiting for backup lock'; +--source include/wait_condition.inc +--replace_result $MYSQLTEST_VARDIR +SELECT COMMAND, STATE, INFO FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = @con2_id; + +BACKUP STAGE END; + +# When "long running" backup finishes, check that the backup on con2 +# is also allowed to finish +let $wait_condition= + SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE Info LIKE 'BACKUP SERVER TO %' AND State = 'Waiting for backup lock'; +--source include/wait_condition.inc + +--connection con2 +--reap + +--connection default + +--disconnect con1 +--disconnect con2 + diff --git a/sql/debug_sync.h b/sql/debug_sync.h index f0897aae2ff8d..c885056637dba 100644 --- a/sql/debug_sync.h +++ b/sql/debug_sync.h @@ -22,6 +22,8 @@ Declarations for the Debug Sync Facility. See debug_sync.cc for details. */ +#include + class THD; #if defined(ENABLED_DEBUG_SYNC) diff --git a/sql/mdl.h b/sql/mdl.h index 1b01bcf3ecb7b..0c3159182cf4f 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -578,7 +578,7 @@ class MDL_request /** Set type of lock request. Can be only applied to pending locks. */ inline void set_type(enum_mdl_type type_arg) { - DBUG_ASSERT(ticket == NULL); + DBUG_ASSERT(ticket == nullptr); type= type_arg; } void move_from(MDL_request &from) @@ -589,7 +589,7 @@ class MDL_request next_in_list= from.next_in_list; prev_in_list= from.prev_in_list; key.mdl_key_init(&from.key); - from.ticket= NULL; // that's what "move" means + from.ticket= nullptr; // that's what "move" means } /** @@ -621,17 +621,17 @@ class MDL_request MDL_request& operator=(const MDL_request &) { type= MDL_NOT_INITIALIZED; - ticket= NULL; + ticket= nullptr; /* Do nothing, in particular, don't try to copy the key. */ return *this; } /* Another piece of ugliness for TABLE_LIST constructor */ - MDL_request(): type(MDL_NOT_INITIALIZED), ticket(NULL) {} + MDL_request(): type(MDL_NOT_INITIALIZED), ticket(nullptr) {} MDL_request(const MDL_request *rhs) :type(rhs->type), duration(rhs->duration), - ticket(NULL), + ticket(nullptr), key(&rhs->key) {} }; @@ -1088,7 +1088,7 @@ class MDL_context void done_waiting_for() { mysql_prlock_wrlock(&m_LOCK_waiting_for); - m_waiting_for= NULL; + m_waiting_for= nullptr; mysql_prlock_unlock(&m_LOCK_waiting_for); } void lock_deadlock_victim() @@ -1116,7 +1116,7 @@ class MDL_context The coordinator thread holds the lock for the duration of worker's purge job, or longer, possibly reusing shared MDL for different workers and jobs. */ - MDL_context *lock_warrant= NULL; + MDL_context *lock_warrant= nullptr; inline bool is_lock_warrantee(MDL_key::enum_mdl_namespace ns, const char *db, const char *name, diff --git a/sql/sql_plist.h b/sql/sql_plist.h index 0969fef07491a..b9c8ba71247e8 100644 --- a/sql/sql_plist.h +++ b/sql/sql_plist.h @@ -16,6 +16,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ +#include + template class I_P_List_iterator; class I_P_List_null_counter; @@ -72,14 +74,14 @@ class I_P_List : public C, public I is a bad idea. */ public: - I_P_List() : I(&m_first), m_first(NULL) {}; + I_P_List() : I(&m_first), m_first(nullptr) {}; /* empty() is used in many places in the code instead of a constructor, to initialize a bzero-ed I_P_List instance. */ - inline void empty() { m_first= NULL; C::reset(); I::set_last(&m_first); } - inline bool is_empty() const { return (m_first == NULL); } + inline void empty() { m_first= nullptr; C::reset(); I::set_last(&m_first); } + inline bool is_empty() const { return (m_first == nullptr); } inline void push_front(T* a) { *B::next_ptr(a)= m_first; @@ -102,7 +104,7 @@ class I_P_List : public C, public I } inline void insert_after(T *pos, T *a) { - if (pos == NULL) + if (pos == nullptr) push_front(a); else {