summaryrefslogtreecommitdiff
path: root/sql/lock.cc
diff options
context:
space:
mode:
authorunknown <serg@serg.mylan>2004-08-20 21:56:29 +0200
committerunknown <serg@serg.mylan>2004-08-20 21:56:29 +0200
commitadf4e7a82284e5cbacff5c38e02064e73533b997 (patch)
treed3bc4a6cf5270e88d92f8b8cc86572fd34a9405c /sql/lock.cc
parent91df160829a7e7699f2665716d860da069cd0f95 (diff)
parent4f0e2da3169968b826f0b180dfe5de0ca99b40b9 (diff)
downloadmariadb-git-adf4e7a82284e5cbacff5c38e02064e73533b997.tar.gz
merged
sql/lock.cc: Auto merged sql/mysql_priv.h: Auto merged sql/sql_db.cc: Auto merged
Diffstat (limited to 'sql/lock.cc')
-rw-r--r--sql/lock.cc54
1 files changed, 47 insertions, 7 deletions
diff --git a/sql/lock.cc b/sql/lock.cc
index 0917c143a8a..fa199ce7454 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -99,7 +99,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
Wait until the lock is gone
*/
- if (wait_if_global_read_lock(thd, 1))
+ if (wait_if_global_read_lock(thd, 1, 1))
{
my_free((gptr) sql_lock,MYF(0));
sql_lock=0;
@@ -474,7 +474,7 @@ int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list)
int error= -1;
DBUG_ENTER("lock_and_wait_for_table_name");
- if (wait_if_global_read_lock(thd,0))
+ if (wait_if_global_read_lock(thd, 0, 1))
DBUG_RETURN(1);
VOID(pthread_mutex_lock(&LOCK_open));
if ((lock_retcode = lock_table_name(thd, table_list)) < 0)
@@ -707,14 +707,23 @@ static void print_lock_error(int error)
The global locks are handled through the global variables:
global_read_lock
+ global_read_lock_blocks_commit
waiting_for_read_lock
protect_against_global_read_lock
+
+ Taking the global read lock is TWO steps (2nd step is optional; without
+ it, COMMIT of existing transactions will be allowed):
+ lock_global_read_lock() THEN make_global_read_lock_block_commit().
****************************************************************************/
volatile uint global_read_lock=0;
+volatile uint global_read_lock_blocks_commit=0;
static volatile uint protect_against_global_read_lock=0;
static volatile uint waiting_for_read_lock=0;
+#define GOT_GLOBAL_READ_LOCK 1
+#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
+
bool lock_global_read_lock(THD *thd)
{
DBUG_ENTER("lock_global_read_lock");
@@ -737,27 +746,40 @@ bool lock_global_read_lock(THD *thd)
thd->exit_cond(old_message);
DBUG_RETURN(1);
}
- thd->global_read_lock=1;
+ thd->global_read_lock= GOT_GLOBAL_READ_LOCK;
global_read_lock++;
thd->exit_cond(old_message);
}
+ /*
+ We DON'T set global_read_lock_blocks_commit now, it will be set after
+ tables are flushed (as the present function serves for FLUSH TABLES WITH
+ READ LOCK only). Doing things in this order is necessary to avoid
+ deadlocks (we must allow COMMIT until all tables are closed; we should not
+ forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
+ UPDATE and one does FLUSH TABLES WITH READ LOCK).
+ */
DBUG_RETURN(0);
}
void unlock_global_read_lock(THD *thd)
{
uint tmp;
- thd->global_read_lock=0;
pthread_mutex_lock(&LOCK_open);
tmp= --global_read_lock;
+ if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
+ --global_read_lock_blocks_commit;
pthread_mutex_unlock(&LOCK_open);
/* Send the signal outside the mutex to avoid a context switch */
if (!tmp)
pthread_cond_broadcast(&COND_refresh);
+ thd->global_read_lock= 0;
}
+#define must_wait (global_read_lock && \
+ (is_not_commit || \
+ global_read_lock_blocks_commit))
-bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh)
+bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, bool is_not_commit)
{
const char *old_message;
bool result= 0, need_exit_cond;
@@ -765,7 +787,7 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh)
LINT_INIT(old_message);
(void) pthread_mutex_lock(&LOCK_open);
- if (need_exit_cond= (bool)global_read_lock)
+ if (need_exit_cond= must_wait)
{
if (thd->global_read_lock) // This thread had the read locks
{
@@ -775,7 +797,7 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh)
}
old_message=thd->enter_cond(&COND_refresh, &LOCK_open,
"Waiting for release of readlock");
- while (global_read_lock && ! thd->killed &&
+ while (must_wait && ! thd->killed &&
(!abort_on_refresh || thd->version == refresh_version))
(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
if (thd->killed)
@@ -802,3 +824,21 @@ void start_waiting_global_read_lock(THD *thd)
pthread_cond_broadcast(&COND_refresh);
DBUG_VOID_RETURN;
}
+
+
+void make_global_read_lock_block_commit(THD *thd)
+{
+ /*
+ If we didn't succeed lock_global_read_lock(), or if we already suceeded
+ make_global_read_lock_block_commit(), do nothing.
+ */
+ if (thd->global_read_lock != GOT_GLOBAL_READ_LOCK)
+ return;
+ pthread_mutex_lock(&LOCK_open);
+ /* increment this BEFORE waiting on cond (otherwise race cond) */
+ global_read_lock_blocks_commit++;
+ while (protect_against_global_read_lock)
+ pthread_cond_wait(&COND_refresh, &LOCK_open);
+ pthread_mutex_unlock(&LOCK_open);
+ thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
+}