1
/* Copyright (C) 2000-2006 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
20
Locking functions for mysql.
22
Because of the new concurrent inserts, we must first get external locks
23
before getting internal locks. If we do it in the other order, the status
24
information is not up to date when called from the lock handler.
26
GENERAL DESCRIPTION OF LOCKING
28
When not using LOCK TABLES:
30
- For each SQL statement mysql_lock_tables() is called for all involved
32
- mysql_lock_tables() will call
33
table_handler->external_lock(session,locktype) for each table.
34
This is followed by a call to thr_multi_lock() for all tables.
36
- When statement is done, we call mysql_unlock_tables().
37
This will call thr_multi_unlock() followed by
38
table_handler->external_lock(session, F_UNLCK) for each table.
40
- Note that mysql_unlock_tables() may be called several times as
41
MySQL in some cases can free some tables earlier than others.
43
- The above is true both for normal and temporary tables.
45
- Temporary non transactional tables are never passed to thr_multi_lock()
46
and we never call external_lock(session, F_UNLOCK) on these.
48
When using LOCK TABLES:
50
- LOCK Table will call mysql_lock_tables() for all tables.
51
mysql_lock_tables() will call
52
table_handler->external_lock(session,locktype) for each table.
53
This is followed by a call to thr_multi_lock() for all tables.
55
- For each statement, we will call table_handler->start_stmt(Session)
56
to inform the table handler that we are using the table.
58
The tables used can only be tables used in LOCK TABLES or a
61
- When statement is done, we will call ha_commit_stmt(session);
63
- When calling UNLOCK TABLES we call mysql_unlock_tables() for all
64
tables used in LOCK TABLES
66
If table_handler->external_lock(session, locktype) fails, we call
67
table_handler->external_lock(session, F_UNLCK) for each table that was locked,
68
excluding one that caused failure. That means handler must cleanup itself
69
in case external_lock() fails.
72
Change to use malloc() ONLY when using LOCK TABLES command or when
73
we are forced to use mysql_lock_merge.
77
#include <drizzled/error.h>
78
#include <drizzled/my_hash.h>
79
#include <drizzled/thr_lock.h>
80
#include <drizzled/session.h>
81
#include <drizzled/sql_base.h>
82
#include <drizzled/lock.h>
83
#include "drizzled/pthread_globals.h"
84
#include "drizzled/internal/my_sys.h"
88
@defgroup Locking Locking
92
extern HASH open_cache;
94
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table,
96
bool should_lock, Table **write_locked);
97
static int lock_external(Session *session, Table **table,uint32_t count);
98
static int unlock_external(Session *session, Table **table,uint32_t count);
99
static void print_lock_error(int error, const char *);
106
session The current thread.
107
tables An array of pointers to the tables to lock.
108
count The number of tables to lock.
110
DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
111
DRIZZLE_LOCK_IGNORE_FLUSH Ignore a flush tables.
112
DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN Instead of reopening altered
113
or dropped tables by itself,
114
mysql_lock_tables() should
115
notify upper level and rely
116
on caller doing this.
117
need_reopen Out parameter, TRUE if some tables were altered
118
or deleted and should be reopened by caller.
121
A lock structure pointer on success.
122
NULL on error or if some tables should be reopen.
125
/* Map the return value of thr_lock to an error from errmsg.txt */
126
static int thr_lock_errno_to_mysql[]=
127
{ 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };
131
Reset lock type in lock data and free.
133
@param mysql_lock Lock structures to reset.
135
@note After a locking error we want to quit the locking of the table(s).
136
The test case in the bug report for Bug #18544 has the following
137
cases: 1. Locking error in lock_external() due to InnoDB timeout.
138
2. Locking error in get_lock_data() due to missing write permission.
139
3. Locking error in wait_if_global_read_lock() due to lock conflict.
141
@note In all these cases we have already set the lock type into the lock
142
data of the open table(s). If the table(s) are in the open table
143
cache, they could be reused with the non-zero lock type set. This
144
could lead to ignoring a different lock type with the next lock.
146
@note Clear the lock type of all lock data. This ensures that the next
147
lock request will set its lock type properly.
150
static void reset_lock_data_and_free(DRIZZLE_LOCK **mysql_lock)
152
DRIZZLE_LOCK *sql_lock= *mysql_lock;
153
THR_LOCK_DATA **ldata, **ldata_end;
155
/* Clear the lock type of all lock data to avoid reusage. */
156
for (ldata= sql_lock->locks, ldata_end= ldata + sql_lock->lock_count;
160
/* Reset lock type. */
161
(*ldata)->type= TL_UNLOCK;
163
free((unsigned char*) sql_lock);
168
DRIZZLE_LOCK *mysql_lock_tables(Session *session, Table **tables, uint32_t count,
169
uint32_t flags, bool *need_reopen)
171
DRIZZLE_LOCK *sql_lock;
172
Table *write_lock_used;
179
if (! (sql_lock= get_lock_data(session, tables, count, true,
183
if (global_read_lock && write_lock_used &&
184
! (flags & DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK))
187
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
188
Wait until the lock is gone
190
if (wait_if_global_read_lock(session, 1, 1))
192
/* Clear the lock type of all lock data to avoid reusage. */
193
reset_lock_data_and_free(&sql_lock);
196
if (session->version != refresh_version)
198
/* Clear the lock type of all lock data to avoid reusage. */
199
reset_lock_data_and_free(&sql_lock);
204
session->set_proc_info("System lock");
205
if (sql_lock->table_count && lock_external(session, sql_lock->table,
206
sql_lock->table_count))
208
/* Clear the lock type of all lock data to avoid reusage. */
209
reset_lock_data_and_free(&sql_lock);
212
session->set_proc_info("Table lock");
213
/* Copy the lock data array. thr_multi_lock() reorders its contens. */
214
memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
215
sql_lock->lock_count * sizeof(*sql_lock->locks));
216
/* Lock on the copied half of the lock data array. */
217
rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
218
sql_lock->lock_count,
219
sql_lock->lock_count,
221
if (rc > 1) /* a timeout or a deadlock */
223
if (sql_lock->table_count)
224
unlock_external(session, sql_lock->table, sql_lock->table_count);
225
reset_lock_data_and_free(&sql_lock);
226
my_error(rc, MYF(0));
229
else if (rc == 1) /* aborted */
231
session->some_tables_deleted=1; // Try again
232
sql_lock->lock_count= 0; // Locks are already freed
233
// Fall through: unlock, reset lock data, free and retry
235
else if (!session->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
238
Thread was killed or lock aborted. Let upper level close all
239
used tables and retry or give error.
243
else if (!session->open_tables)
245
// Only using temporary tables, no need to unlock
246
session->some_tables_deleted= 0;
249
session->set_proc_info(0);
251
/* going to retry, unlock all tables */
252
if (sql_lock->lock_count)
253
thr_multi_unlock(sql_lock->locks, sql_lock->lock_count);
255
if (sql_lock->table_count)
256
unlock_external(session, sql_lock->table, sql_lock->table_count);
259
If thr_multi_lock fails it resets lock type for tables, which
260
were locked before (and including) one that caused error. Lock
261
type for other tables preserved.
263
reset_lock_data_and_free(&sql_lock);
265
if (flags & DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN)
270
if (wait_for_tables(session))
271
break; // Couldn't open tables
273
session->set_proc_info(0);
276
session->send_kill_message();
279
mysql_unlock_tables(session,sql_lock);
284
session->set_time_after_lock();
289
static int lock_external(Session *session, Table **tables, uint32_t count)
293
for (i=1 ; i <= count ; i++, tables++)
295
assert((*tables)->reginfo.lock_type >= TL_READ);
296
lock_type=F_WRLCK; /* Lock exclusive */
297
if ((*tables)->db_stat & HA_READ_ONLY ||
298
((*tables)->reginfo.lock_type >= TL_READ &&
299
(*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
302
if ((error=(*tables)->cursor->ha_external_lock(session,lock_type)))
304
print_lock_error(error, (*tables)->cursor->engine->getName().c_str());
308
(*tables)->cursor->ha_external_lock(session, F_UNLCK);
309
(*tables)->current_lock=F_UNLCK;
315
(*tables)->db_stat &= ~ HA_BLOCK_LOCK;
316
(*tables)->current_lock= lock_type;
323
void mysql_unlock_tables(Session *session, DRIZZLE_LOCK *sql_lock)
325
if (sql_lock->lock_count)
326
thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
327
if (sql_lock->table_count)
328
unlock_external(session,sql_lock->table,sql_lock->table_count);
329
free((unsigned char*) sql_lock);
334
Unlock some of the tables locked by mysql_lock_tables.
336
This will work even if get_lock_data fails (next unlock will free all)
339
void mysql_unlock_some_tables(Session *session, Table **table, uint32_t count)
341
DRIZZLE_LOCK *sql_lock;
342
Table *write_lock_used;
343
if ((sql_lock= get_lock_data(session, table, count, false,
345
mysql_unlock_tables(session, sql_lock);
350
unlock all tables locked for read.
353
void mysql_unlock_read_tables(Session *session, DRIZZLE_LOCK *sql_lock)
357
/* Move all write locks first */
358
THR_LOCK_DATA **lock=sql_lock->locks;
359
for (i=found=0 ; i < sql_lock->lock_count ; i++)
361
if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_READ)
363
std::swap(*lock, sql_lock->locks[i]);
368
/* unlock the read locked tables */
371
thr_multi_unlock(lock,i-found);
372
sql_lock->lock_count= found;
375
/* Then do the same for the external locks */
376
/* Move all write locked tables first */
377
Table **table=sql_lock->table;
378
for (i=found=0 ; i < sql_lock->table_count ; i++)
380
assert(sql_lock->table[i]->lock_position == i);
381
if ((uint32_t) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
383
std::swap(*table, sql_lock->table[i]);
388
/* Unlock all read locked tables */
391
unlock_external(session,table,i-found);
392
sql_lock->table_count=found;
394
/* Fix the lock positions in Table */
395
table= sql_lock->table;
397
for (i= 0; i < sql_lock->table_count; i++)
400
tbl->lock_position= table - sql_lock->table;
401
tbl->lock_data_start= found;
402
found+= tbl->lock_count;
410
Try to find the table in the list of locked tables.
411
In case of success, unlock the table and remove it from this list.
413
@note This function has a legacy side effect: the table is
414
unlocked even if it is not found in the locked list.
415
It's not clear if this side effect is intentional or still
416
desirable. It might lead to unmatched calls to
417
unlock_external(). Moreover, a discrepancy can be left
418
unnoticed by the storage engine, because in
419
unlock_external() we call handler::external_lock(F_UNLCK) only
420
if table->current_lock is not F_UNLCK.
422
@param session thread context
423
@param locked list of locked tables
424
@param table the table to unlock
425
@param always_unlock specify explicitly if the legacy side
429
void mysql_lock_remove(Session *session, Table *table)
431
mysql_unlock_some_tables(session, &table, /* table count */ 1);
435
/** Abort all other threads waiting to get lock in table. */
437
void mysql_lock_abort(Session *session, Table *table)
439
DRIZZLE_LOCK *locked;
440
Table *write_lock_used;
442
if ((locked= get_lock_data(session, &table, 1, false,
445
for (uint32_t x= 0; x < locked->lock_count; x++)
446
thr_abort_locks(locked->locks[x]->lock);
447
free((unsigned char*) locked);
453
Abort one thread / table combination.
455
@param session Thread handler
456
@param table Table that should be removed from lock queue
459
0 Table was not locked by another thread
461
1 Table was locked by at least one other thread
464
bool mysql_lock_abort_for_thread(Session *session, Table *table)
466
DRIZZLE_LOCK *locked;
467
Table *write_lock_used;
470
if ((locked= get_lock_data(session, &table, 1, false,
473
for (uint32_t i=0; i < locked->lock_count; i++)
475
if (thr_abort_locks_for_thread(locked->locks[i]->lock,
476
table->in_use->thread_id))
479
free((unsigned char*) locked);
485
/** Unlock a set of external. */
487
static int unlock_external(Session *session, Table **table,uint32_t count)
489
int error,error_code;
494
if ((*table)->current_lock != F_UNLCK)
496
(*table)->current_lock = F_UNLCK;
497
if ((error=(*table)->cursor->ha_external_lock(session, F_UNLCK)))
500
print_lock_error(error_code, (*table)->cursor->engine->getName().c_str());
510
Get lock structures from table structs and initialize locks.
512
@param session Thread handler
513
@param table_ptr Pointer to tables that should be locks
514
@param should_lock One of:
515
- false : If we should send TL_IGNORE to store lock
516
- true : Store lock info in Table
517
@param write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE
520
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table_ptr, uint32_t count,
521
bool should_lock, Table **write_lock_used)
523
uint32_t i,tables,lock_count;
524
DRIZZLE_LOCK *sql_lock;
525
THR_LOCK_DATA **locks, **locks_buf, **locks_start;
526
Table **to, **table_buf;
529
for (i= tables= lock_count= 0 ; i < count ; i++)
531
Table *t= table_ptr[i];
533
if (! (t->getEngine()->check_flag(HTON_BIT_SKIP_STORE_LOCK)))
541
Allocating twice the number of pointers for lock data for use in
542
thr_mulit_lock(). This function reorders the lock data, but cannot
543
update the table values. So the second part of the array is copied
544
from the first part immediately before calling thr_multi_lock().
546
if (!(sql_lock= (DRIZZLE_LOCK*)
547
malloc(sizeof(*sql_lock) +
548
sizeof(THR_LOCK_DATA*) * tables * 2 +
549
sizeof(table_ptr) * lock_count)))
551
locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
552
to= table_buf= sql_lock->table= (Table**) (locks + tables * 2);
553
sql_lock->table_count= lock_count;
555
for (i=0 ; i < count ; i++)
558
enum thr_lock_type lock_type;
560
if (table_ptr[i]->getEngine()->check_flag(HTON_BIT_SKIP_STORE_LOCK))
564
lock_type= table->reginfo.lock_type;
565
assert (lock_type != TL_WRITE_DEFAULT);
566
if (lock_type >= TL_WRITE_ALLOW_WRITE)
568
*write_lock_used=table;
569
if (table->db_stat & HA_READ_ONLY)
571
my_error(ER_OPEN_AS_READONLY,MYF(0),table->alias);
572
/* Clear the lock type of the lock data that are stored already. */
573
sql_lock->lock_count= locks - sql_lock->locks;
574
reset_lock_data_and_free(&sql_lock);
579
locks= table->cursor->store_lock(session, locks,
580
should_lock == false ? TL_IGNORE : lock_type);
583
table->lock_position= (uint32_t) (to - table_buf);
584
table->lock_data_start= (uint32_t) (locks_start - locks_buf);
585
table->lock_count= (uint32_t) (locks - locks_start);
586
assert(table->lock_count == 1);
591
We do not use 'tables', because there are cases where store_lock()
592
returns less locks than lock_count() claimed. This can happen when
593
a FLUSH TABLES tries to abort locks from a MERGE table of another
594
thread. When that thread has just opened the table, but not yet
595
attached its children, it cannot return the locks. lock_count()
596
always returns the number of locks that an attached table has.
597
This is done to avoid the reverse situation: If lock_count() would
598
return 0 for a non-attached MERGE table, and that table becomes
599
attached between the calls to lock_count() and store_lock(), then
600
we would have allocated too little memory for the lock data. Now
601
we may allocate too much, but better safe than memory overrun.
602
And in the FLUSH case, the memory is released quickly anyway.
604
sql_lock->lock_count= locks - locks_buf;
611
Put a not open table with an old refresh version in the table cache.
613
@param session Thread handler
614
@param table_list Lock first table in this list
615
@param check_in_use Do we need to check if table already in use by us
618
One must have a lock on LOCK_open!
621
If you are going to update the table, you should use
622
lock_and_wait_for_table_name(removed) instead of this function as this works
623
together with 'FLUSH TABLES WITH READ LOCK'
626
This will force any other threads that uses the table to release it
634
> 0 table locked, but someone is using it
637
int lock_table_name(Session *session, TableList *table_list, bool check_in_use)
640
char key[MAX_DBKEY_LENGTH];
641
char *db= table_list->db;
643
bool found_locked_table= false;
644
HASH_SEARCH_STATE state;
646
key_length= table_list->create_table_def_key(key);
650
/* Only insert the table if we haven't insert it already */
651
for (table=(Table*) hash_first(&open_cache, (unsigned char*)key,
654
table = (Table*) hash_next(&open_cache,(unsigned char*) key,
657
if (table->reginfo.lock_type < TL_WRITE)
659
if (table->in_use == session)
660
found_locked_table= true;
664
if (table->in_use == session)
666
table->s->version= 0; // Ensure no one can use this
667
table->locked_by_name= 1;
673
if (!(table= session->table_cache_insert_placeholder(key, key_length)))
676
table_list->table=table;
678
/* Return 1 if table is in use */
679
return(test(remove_table_from_cache(session, db, table_list->table_name,
680
check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG)));
684
void unlock_table_name(TableList *table_list)
686
if (table_list->table)
688
hash_delete(&open_cache, (unsigned char*) table_list->table);
694
static bool locked_named_table(TableList *table_list)
696
for (; table_list ; table_list=table_list->next_local)
698
Table *table= table_list->table;
701
Table *save_next= table->next;
704
result= table_is_used(table_list->table, 0);
705
table->next= save_next;
710
return 0; // All tables are locked
714
bool wait_for_locked_table_names(Session *session, TableList *table_list)
718
safe_mutex_assert_owner(&LOCK_open);
720
while (locked_named_table(table_list))
727
session->wait_for_condition(&LOCK_open, &COND_refresh);
728
pthread_mutex_lock(&LOCK_open); /* Wait for a table to unlock and then lock it */
735
Lock all tables in list with a name lock.
738
- One must have a lock on LOCK_open when calling this
740
@param table_list Names of tables to lock
745
1 Fatal error (end of memory ?)
748
bool lock_table_names(Session *session, TableList *table_list)
750
bool got_all_locks=1;
751
TableList *lock_table;
753
for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
756
if ((got_lock= lock_table_name(session,lock_table, true)) < 0)
757
goto end; // Fatal error
759
got_all_locks=0; // Someone is using table
762
/* If some table was in use, wait until we got the lock */
763
if (!got_all_locks && wait_for_locked_table_names(session, table_list))
768
unlock_table_names(table_list, lock_table);
775
Unlock all tables in list with a name lock.
777
@param session Thread handle.
778
@param table_list Names of tables to lock.
781
This function needs to be protected by LOCK_open. If we're
782
under LOCK TABLES, this function does not work as advertised. Namely,
783
it does not exclude other threads from using this table and does not
784
put an exclusive name lock on this table into the table cache.
786
@see lock_table_names
787
@see unlock_table_names
789
@retval TRUE An error occured.
790
@retval FALSE Name lock successfully acquired.
793
bool lock_table_names_exclusively(Session *session, TableList *table_list)
795
if (lock_table_names(session, table_list))
799
Upgrade the table name locks from semi-exclusive to exclusive locks.
801
for (TableList *table= table_list; table; table= table->next_global)
804
table->table->open_placeholder= 1;
811
Unlock all tables in list with a name lock.
814
table_list Names of tables to unlock
816
last_table Don't unlock any tables after this one.
817
(default 0, which will unlock all tables)
820
One must have a lock on LOCK_open when calling this.
823
This function will broadcast refresh signals to inform other threads
824
that the name locks are removed.
829
1 Fatal error (end of memory ?)
832
void unlock_table_names(TableList *table_list, TableList *last_table)
834
for (TableList *table= table_list;
836
table= table->next_local)
837
unlock_table_name(table);
842
static void print_lock_error(int error, const char *table)
847
case HA_ERR_LOCK_WAIT_TIMEOUT:
848
textno=ER_LOCK_WAIT_TIMEOUT;
850
case HA_ERR_READ_ONLY_TRANSACTION:
851
textno=ER_READ_ONLY_TRANSACTION;
853
case HA_ERR_LOCK_DEADLOCK:
854
textno=ER_LOCK_DEADLOCK;
856
case HA_ERR_WRONG_COMMAND:
857
textno=ER_ILLEGAL_HA;
864
if ( textno == ER_ILLEGAL_HA )
865
my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), table);
867
my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error);
871
/****************************************************************************
872
Handling of global read locks
874
Taking the global read lock is TWO steps (2nd step is optional; without
875
it, COMMIT of existing transactions will be allowed):
876
lock_global_read_lock() THEN make_global_read_lock_block_commit().
878
The global locks are handled through the global variables:
880
count of threads which have the global read lock (i.e. have completed at
881
least the first step above)
882
global_read_lock_blocks_commit
883
count of threads which have the global read lock and block
884
commits (i.e. are in or have completed the second step above)
885
waiting_for_read_lock
886
count of threads which want to take a global read lock but cannot
887
protect_against_global_read_lock
888
count of threads which have set protection against global read lock.
890
access to them is protected with a mutex LOCK_global_read_lock
892
(XXX: one should never take LOCK_open if LOCK_global_read_lock is
893
taken, otherwise a deadlock may occur. Other mutexes could be a
894
problem too - grep the code for global_read_lock if you want to use
895
any other mutex here) Also one must not hold LOCK_open when calling
896
wait_if_global_read_lock(). When the thread with the global read lock
897
tries to close its tables, it needs to take LOCK_open in
898
close_thread_table().
900
How blocking of threads by global read lock is achieved: that's
901
advisory. Any piece of code which should be blocked by global read lock must
902
be designed like this:
903
- call to wait_if_global_read_lock(). When this returns 0, no global read
904
lock is owned; if argument abort_on_refresh was 0, none can be obtained.
906
- if abort_on_refresh was 0, call to start_waiting_global_read_lock() to
907
allow other threads to get the global read lock. I.e. removal of the
909
(Note: it's a bit like an implementation of rwlock).
911
[ I am sorry to mention some SQL syntaxes below I know I shouldn't but found
912
no better descriptive way ]
914
Why does FLUSH TABLES WITH READ LOCK need to block COMMIT: because it's used
915
to read a non-moving SHOW MASTER STATUS, and a COMMIT writes to the binary
918
Why getting the global read lock is two steps and not one. Because FLUSH
919
TABLES WITH READ LOCK needs to insert one other step between the two:
920
flushing tables. So the order is
921
1) lock_global_read_lock() (prevents any new table write locks, i.e. stalls
923
2) close_cached_tables() (the FLUSH TABLES), which will wait for tables
924
currently opened and being updated to close (so it's possible that there is
925
a moment where all new updates of server are stalled *and* FLUSH TABLES WITH
927
3) make_global_read_lock_block_commit().
928
If we have merged 1) and 3) into 1), we would have had this deadlock:
929
imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
931
session1: SELECT * FROM t FOR UPDATE;
932
session2: UPDATE t SET a=1; # blocked by row-level locks of session1
933
session3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
934
table instance of session2
935
session1: COMMIT; # blocked by session3.
936
session1 blocks session2 which blocks session3 which blocks session1: deadlock.
938
Note that we need to support that one thread does
939
FLUSH TABLES WITH READ LOCK; and then COMMIT;
940
(that's what innobackup does, for some good reason).
941
So in this exceptional case the COMMIT should not be blocked by the FLUSH
942
TABLES WITH READ LOCK.
944
****************************************************************************/
946
volatile uint32_t global_read_lock=0;
947
volatile uint32_t global_read_lock_blocks_commit=0;
948
static volatile uint32_t protect_against_global_read_lock=0;
949
static volatile uint32_t waiting_for_read_lock=0;
951
#define GOT_GLOBAL_READ_LOCK 1
952
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
954
bool lock_global_read_lock(Session *session)
956
if (!session->global_read_lock)
958
const char *old_message;
959
(void) pthread_mutex_lock(&LOCK_global_read_lock);
960
old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
961
"Waiting to get readlock");
963
waiting_for_read_lock++;
964
while (protect_against_global_read_lock && !session->killed)
965
pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
966
waiting_for_read_lock--;
969
session->exit_cond(old_message);
972
session->global_read_lock= GOT_GLOBAL_READ_LOCK;
974
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
977
We DON'T set global_read_lock_blocks_commit now, it will be set after
978
tables are flushed (as the present function serves for FLUSH TABLES WITH
979
READ LOCK only). Doing things in this order is necessary to avoid
980
deadlocks (we must allow COMMIT until all tables are closed; we should not
981
forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
982
UPDATE and one does FLUSH TABLES WITH READ LOCK).
988
void unlock_global_read_lock(Session *session)
992
pthread_mutex_lock(&LOCK_global_read_lock);
993
tmp= --global_read_lock;
994
if (session->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
995
--global_read_lock_blocks_commit;
996
pthread_mutex_unlock(&LOCK_global_read_lock);
997
/* Send the signal outside the mutex to avoid a context switch */
1000
pthread_cond_broadcast(&COND_global_read_lock);
1002
session->global_read_lock= 0;
1005
#define must_wait (global_read_lock && \
1007
global_read_lock_blocks_commit))
1009
bool wait_if_global_read_lock(Session *session, bool abort_on_refresh,
1012
const char *old_message= NULL;
1013
bool result= 0, need_exit_cond;
1016
Assert that we do not own LOCK_open. If we would own it, other
1017
threads could not close their tables. This would make a pretty
1020
safe_mutex_assert_not_owner(&LOCK_open);
1022
(void) pthread_mutex_lock(&LOCK_global_read_lock);
1023
if ((need_exit_cond= must_wait))
1025
if (session->global_read_lock) // This thread had the read locks
1028
my_message(ER_CANT_UPDATE_WITH_READLOCK,
1029
ER(ER_CANT_UPDATE_WITH_READLOCK), MYF(0));
1030
(void) pthread_mutex_unlock(&LOCK_global_read_lock);
1032
We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
1033
This allowance is needed to not break existing versions of innobackup
1034
which do a BEGIN; INSERT; FLUSH TABLES WITH READ LOCK; COMMIT.
1036
return is_not_commit;
1038
old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1039
"Waiting for release of readlock");
1040
while (must_wait && ! session->killed &&
1041
(!abort_on_refresh || session->version == refresh_version))
1043
(void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1045
if (session->killed)
1048
if (!abort_on_refresh && !result)
1049
protect_against_global_read_lock++;
1051
The following is only true in case of a global read locks (which is rare)
1052
and if old_message is set
1054
if (unlikely(need_exit_cond))
1055
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1057
pthread_mutex_unlock(&LOCK_global_read_lock);
1062
void start_waiting_global_read_lock(Session *session)
1065
if (unlikely(session->global_read_lock))
1067
(void) pthread_mutex_lock(&LOCK_global_read_lock);
1068
tmp= (!--protect_against_global_read_lock &&
1069
(waiting_for_read_lock || global_read_lock_blocks_commit));
1070
(void) pthread_mutex_unlock(&LOCK_global_read_lock);
1072
pthread_cond_broadcast(&COND_global_read_lock);
1077
bool make_global_read_lock_block_commit(Session *session)
1080
const char *old_message;
1082
If we didn't succeed lock_global_read_lock(), or if we already suceeded
1083
make_global_read_lock_block_commit(), do nothing.
1085
if (session->global_read_lock != GOT_GLOBAL_READ_LOCK)
1087
pthread_mutex_lock(&LOCK_global_read_lock);
1088
/* increment this BEFORE waiting on cond (otherwise race cond) */
1089
global_read_lock_blocks_commit++;
1090
old_message= session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1091
"Waiting for all running commits to finish");
1092
while (protect_against_global_read_lock && !session->killed)
1093
pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1094
if ((error= test(session->killed)))
1095
global_read_lock_blocks_commit--; // undo what we did
1097
session->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1098
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1104
Broadcast COND_refresh and COND_global_read_lock.
1106
Due to a bug in a threading library it could happen that a signal
1107
did not reach its target. A condition for this was that the same
1108
condition variable was used with different mutexes in
1109
pthread_cond_wait(). Some time ago we changed LOCK_open to
1110
LOCK_global_read_lock in global read lock handling. So COND_refresh
1111
was used with LOCK_open and LOCK_global_read_lock.
1113
We did now also change from COND_refresh to COND_global_read_lock
1114
in global read lock handling. But now it is necessary to signal
1115
both conditions at the same time.
1118
When signalling COND_global_read_lock within the global read lock
1119
handling, it is not necessary to also signal COND_refresh.
1122
void broadcast_refresh(void)
1124
pthread_cond_broadcast(&COND_refresh);
1125
pthread_cond_broadcast(&COND_global_read_lock);
1130
@} (end of group Locking)