30
30
- For each SQL statement mysql_lock_tables() is called for all involved
32
32
- mysql_lock_tables() will call
33
table_handler->external_lock(thd,locktype) for each table.
33
table_handler->external_lock(session,locktype) for each table.
34
34
This is followed by a call to thr_multi_lock() for all tables.
36
36
- When statement is done, we call mysql_unlock_tables().
37
37
This will call thr_multi_unlock() followed by
38
table_handler->external_lock(thd, F_UNLCK) for each table.
38
table_handler->external_lock(session, F_UNLCK) for each table.
40
40
- Note that mysql_unlock_tables() may be called several times as
41
41
MySQL in some cases can free some tables earlier than others.
43
43
- The above is true both for normal and temporary tables.
45
45
- Temporary non transactional tables are never passed to thr_multi_lock()
46
and we never call external_lock(thd, F_UNLOCK) on these.
46
and we never call external_lock(session, F_UNLOCK) on these.
48
48
When using LOCK TABLES:
50
50
- LOCK Table will call mysql_lock_tables() for all tables.
51
51
mysql_lock_tables() will call
52
table_handler->external_lock(thd,locktype) for each table.
52
table_handler->external_lock(session,locktype) for each table.
53
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(THD)
55
- For each statement, we will call table_handler->start_stmt(Session)
56
56
to inform the table handler that we are using the table.
58
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(thd);
61
- When statement is done, we will call ha_commit_stmt(session);
63
63
- When calling UNLOCK TABLES we call mysql_unlock_tables() for all
64
64
tables used in LOCK TABLES
66
If table_handler->external_lock(thd, locktype) fails, we call
67
table_handler->external_lock(thd, F_UNLCK) for each table that was locked,
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
68
excluding one that caused failure. That means handler must cleanup itself
69
69
in case external_lock() fails.
73
73
we are forced to use mysql_lock_merge.
75
75
#include <drizzled/server_includes.h>
76
#include <drizzled/drizzled_error_messages.h>
76
#include <drizzled/error.h>
79
79
@defgroup Locking Locking
86
86
#define GET_LOCK_UNLOCK 1
87
87
#define GET_LOCK_STORE_LOCKS 2
89
static DRIZZLE_LOCK *get_lock_data(THD *thd, Table **table,uint count,
90
uint flags, Table **write_locked);
91
static int lock_external(THD *thd, Table **table,uint count);
92
static int unlock_external(THD *thd, Table **table,uint count);
89
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table,uint32_t count,
90
uint32_t flags, Table **write_locked);
91
static int lock_external(Session *session, Table **table,uint32_t count);
92
static int unlock_external(Session *session, Table **table,uint32_t count);
93
93
static void print_lock_error(int error, const char *);
155
155
/* Reset lock type. */
156
156
(*ldata)->type= TL_UNLOCK;
158
my_free((uchar*) sql_lock, MYF(0));
158
free((unsigned char*) sql_lock);
163
DRIZZLE_LOCK *mysql_lock_tables(THD *thd, Table **tables, uint count,
164
uint flags, bool *need_reopen)
163
DRIZZLE_LOCK *mysql_lock_tables(Session *session, Table **tables, uint32_t count,
164
uint32_t flags, bool *need_reopen)
166
166
DRIZZLE_LOCK *sql_lock;
167
167
Table *write_lock_used;
174
if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS,
174
if (! (sql_lock= get_lock_data(session, tables, count, GET_LOCK_STORE_LOCKS,
175
175
&write_lock_used)))
182
182
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
183
183
Wait until the lock is gone
185
if (wait_if_global_read_lock(thd, 1, 1))
185
if (wait_if_global_read_lock(session, 1, 1))
187
187
/* Clear the lock type of all lock data to avoid reusage. */
188
188
reset_lock_data_and_free(&sql_lock);
191
if (thd->version != refresh_version)
191
if (session->version != refresh_version)
193
193
/* Clear the lock type of all lock data to avoid reusage. */
194
194
reset_lock_data_and_free(&sql_lock);
213
thd_proc_info(thd, "System lock");
214
if (sql_lock->table_count && lock_external(thd, sql_lock->table,
213
session->set_proc_info("System lock");
214
if (sql_lock->table_count && lock_external(session, sql_lock->table,
215
215
sql_lock->table_count))
217
217
/* Clear the lock type of all lock data to avoid reusage. */
218
218
reset_lock_data_and_free(&sql_lock);
221
thd_proc_info(thd, "Table lock");
221
session->set_proc_info("Table lock");
222
222
/* Copy the lock data array. thr_multi_lock() reorders its contens. */
223
223
memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
224
224
sql_lock->lock_count * sizeof(*sql_lock->locks));
226
226
rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
227
227
sql_lock->lock_count,
228
228
sql_lock->lock_count,
230
230
if (rc > 1) /* a timeout or a deadlock */
232
232
if (sql_lock->table_count)
233
VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
233
unlock_external(session, sql_lock->table, sql_lock->table_count);
234
234
reset_lock_data_and_free(&sql_lock);
235
235
my_error(rc, MYF(0));
238
238
else if (rc == 1) /* aborted */
240
thd->some_tables_deleted=1; // Try again
240
session->some_tables_deleted=1; // Try again
241
241
sql_lock->lock_count= 0; // Locks are already freed
242
242
// Fall through: unlock, reset lock data, free and retry
244
else if (!thd->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
244
else if (!session->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
247
247
Thread was killed or lock aborted. Let upper level close all
252
else if (!thd->open_tables)
252
else if (!session->open_tables)
254
254
// Only using temporary tables, no need to unlock
255
thd->some_tables_deleted=0;
255
session->some_tables_deleted=0;
258
thd_proc_info(thd, 0);
258
session->set_proc_info(0);
260
260
/* going to retry, unlock all tables */
261
261
if (sql_lock->lock_count)
262
262
thr_multi_unlock(sql_lock->locks, sql_lock->lock_count);
264
264
if (sql_lock->table_count)
265
VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
265
unlock_external(session, sql_lock->table, sql_lock->table_count);
268
268
If thr_multi_lock fails it resets lock type for tables, which
276
276
*need_reopen= true;
279
if (wait_for_tables(thd))
279
if (wait_for_tables(session))
280
280
break; // Couldn't open tables
282
thd_proc_info(thd, 0);
282
session->set_proc_info(0);
285
thd->send_kill_message();
285
session->send_kill_message();
288
mysql_unlock_tables(thd,sql_lock);
288
mysql_unlock_tables(session,sql_lock);
293
thd->set_time_after_lock();
293
session->set_time_after_lock();
294
294
return (sql_lock);
298
static int lock_external(THD *thd, Table **tables, uint count)
298
static int lock_external(Session *session, Table **tables, uint32_t count)
301
301
int lock_type,error;
302
302
for (i=1 ; i <= count ; i++, tables++)
308
308
(*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
309
309
lock_type=F_RDLCK;
311
if ((error=(*tables)->file->ha_external_lock(thd,lock_type)))
311
if ((error=(*tables)->file->ha_external_lock(session,lock_type)))
313
313
print_lock_error(error, (*tables)->file->table_type());
317
(*tables)->file->ha_external_lock(thd, F_UNLCK);
317
(*tables)->file->ha_external_lock(session, F_UNLCK);
318
318
(*tables)->current_lock=F_UNLCK;
332
void mysql_unlock_tables(THD *thd, DRIZZLE_LOCK *sql_lock)
332
void mysql_unlock_tables(Session *session, DRIZZLE_LOCK *sql_lock)
334
334
if (sql_lock->lock_count)
335
335
thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
336
336
if (sql_lock->table_count)
337
VOID(unlock_external(thd,sql_lock->table,sql_lock->table_count));
338
my_free((uchar*) sql_lock,MYF(0));
337
unlock_external(session,sql_lock->table,sql_lock->table_count);
338
free((unsigned char*) sql_lock);
345
345
This will work even if get_lock_data fails (next unlock will free all)
348
void mysql_unlock_some_tables(THD *thd, Table **table,uint count)
348
void mysql_unlock_some_tables(Session *session, Table **table,uint32_t count)
350
350
DRIZZLE_LOCK *sql_lock;
351
351
Table *write_lock_used;
352
if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK,
352
if ((sql_lock= get_lock_data(session, table, count, GET_LOCK_UNLOCK,
353
353
&write_lock_used)))
354
mysql_unlock_tables(thd, sql_lock);
354
mysql_unlock_tables(session, sql_lock);
359
359
unlock all tables locked for read.
362
void mysql_unlock_read_tables(THD *thd, DRIZZLE_LOCK *sql_lock)
362
void mysql_unlock_read_tables(Session *session, DRIZZLE_LOCK *sql_lock)
366
366
/* Move all write locks first */
367
367
THR_LOCK_DATA **lock=sql_lock->locks;
397
397
/* Unlock all read locked tables */
400
VOID(unlock_external(thd,table,i-found));
400
unlock_external(session,table,i-found);
401
401
sql_lock->table_count=found;
403
403
/* Fix the lock positions in Table */
428
428
unlock_external() we call handler::external_lock(F_UNLCK) only
429
429
if table->current_lock is not F_UNLCK.
431
@param thd thread context
431
@param session thread context
432
432
@param locked list of locked tables
433
433
@param table the table to unlock
434
434
@param always_unlock specify explicitly if the legacy side
435
435
effect is desired.
438
void mysql_lock_remove(THD *thd, DRIZZLE_LOCK *locked,Table *table,
438
void mysql_lock_remove(Session *session, DRIZZLE_LOCK *locked,Table *table,
439
439
bool always_unlock)
441
441
if (always_unlock == true)
442
mysql_unlock_some_tables(thd, &table, /* table count */ 1);
442
mysql_unlock_some_tables(session, &table, /* table count */ 1);
446
446
for (i=0; i < locked->table_count; i++)
448
448
if (locked->table[i] == table)
450
uint j, removed_locks, old_tables;
450
uint32_t j, removed_locks, old_tables;
452
uint32_t lock_data_end;
454
454
assert(table->lock_position == i);
456
456
/* Unlock if not yet unlocked */
457
457
if (always_unlock == false)
458
mysql_unlock_some_tables(thd, &table, /* table count */ 1);
458
mysql_unlock_some_tables(session, &table, /* table count */ 1);
460
460
/* Decrement table_count in advance, making below expressions easier */
461
461
old_tables= --locked->table_count;
501
501
/* Downgrade all locks on a table to new WRITE level from WRITE_ONLY */
503
void mysql_lock_downgrade_write(THD *thd, Table *table,
503
void mysql_lock_downgrade_write(Session *session, Table *table,
504
504
thr_lock_type new_lock_type)
506
506
DRIZZLE_LOCK *locked;
507
507
Table *write_lock_used;
508
if ((locked = get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
508
if ((locked = get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
509
509
&write_lock_used)))
511
for (uint i=0; i < locked->lock_count; i++)
511
for (uint32_t i=0; i < locked->lock_count; i++)
512
512
thr_downgrade_write_lock(locked->locks[i], new_lock_type);
513
my_free((uchar*) locked,MYF(0));
513
free((unsigned char*) locked);
518
518
/** Abort all other threads waiting to get lock in table. */
520
void mysql_lock_abort(THD *thd, Table *table, bool upgrade_lock)
520
void mysql_lock_abort(Session *session, Table *table, bool upgrade_lock)
522
522
DRIZZLE_LOCK *locked;
523
523
Table *write_lock_used;
525
if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
525
if ((locked= get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
526
526
&write_lock_used)))
528
for (uint i=0; i < locked->lock_count; i++)
528
for (uint32_t i=0; i < locked->lock_count; i++)
529
529
thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
530
my_free((uchar*) locked,MYF(0));
530
free((unsigned char*) locked);
545
545
1 Table was locked by at least one other thread
548
bool mysql_lock_abort_for_thread(THD *thd, Table *table)
548
bool mysql_lock_abort_for_thread(Session *session, Table *table)
550
550
DRIZZLE_LOCK *locked;
551
551
Table *write_lock_used;
552
552
bool result= false;
554
if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
554
if ((locked= get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
555
555
&write_lock_used)))
557
for (uint i=0; i < locked->lock_count; i++)
557
for (uint32_t i=0; i < locked->lock_count; i++)
559
559
if (thr_abort_locks_for_thread(locked->locks[i]->lock,
560
560
table->in_use->thread_id))
563
my_free((uchar*) locked,MYF(0));
563
free((unsigned char*) locked);
603
603
/* Delete old, not needed locks */
604
my_free((uchar*) a,MYF(0));
605
my_free((uchar*) b,MYF(0));
604
free((unsigned char*) a);
605
free((unsigned char*) b);
606
606
return(sql_lock);
614
614
get_lock_data(). If we allow two opens on temporary tables later,
615
615
both functions should be checked.
617
@param thd The current thread.
617
@param session The current thread.
618
618
@param needle The table to check for duplicate lock.
619
619
@param haystack The list of tables to search for the dup lock.
630
630
!NULL First table from 'haystack' that matches a lock on 'needle'.
633
TableList *mysql_lock_have_duplicate(THD *thd, TableList *needle,
633
TableList *mysql_lock_have_duplicate(Session *session, TableList *needle,
634
634
TableList *haystack)
636
636
DRIZZLE_LOCK *mylock;
657
657
/* Get command lock or LOCK TABLES lock. Maybe empty for INSERT DELAYED. */
658
if (! (mylock= thd->lock ? thd->lock : thd->locked_tables))
658
if (! (mylock= session->lock ? session->lock : session->locked_tables))
661
661
/* If we have less than two tables, we cannot have duplicates. */
711
711
/** Unlock a set of external. */
713
static int unlock_external(THD *thd, Table **table,uint count)
713
static int unlock_external(Session *session, Table **table,uint32_t count)
715
715
int error,error_code;
720
720
if ((*table)->current_lock != F_UNLCK)
722
722
(*table)->current_lock = F_UNLCK;
723
if ((error=(*table)->file->ha_external_lock(thd, F_UNLCK)))
723
if ((error=(*table)->file->ha_external_lock(session, F_UNLCK)))
725
725
error_code=error;
726
726
print_lock_error(error_code, (*table)->file->table_type());
736
736
Get lock structures from table structs and initialize locks.
738
@param thd Thread handler
738
@param session Thread handler
739
739
@param table_ptr Pointer to tables that should be locks
740
740
@param flags One of:
741
741
- GET_LOCK_UNLOCK : If we should send TL_IGNORE to store lock
743
743
@param write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE
746
static DRIZZLE_LOCK *get_lock_data(THD *thd, Table **table_ptr, uint count,
747
uint flags, Table **write_lock_used)
746
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table_ptr, uint32_t count,
747
uint32_t flags, Table **write_lock_used)
749
uint i,tables,lock_count;
749
uint32_t i,tables,lock_count;
750
750
DRIZZLE_LOCK *sql_lock;
751
751
THR_LOCK_DATA **locks, **locks_buf, **locks_start;
752
752
Table **to, **table_buf;
805
805
locks_start= locks;
806
locks= table->file->store_lock(thd, locks,
806
locks= table->file->store_lock(session, locks,
807
807
(flags & GET_LOCK_UNLOCK) ? TL_IGNORE :
809
809
if (flags & GET_LOCK_STORE_LOCKS)
857
int lock_and_wait_for_table_name(THD *thd, TableList *table_list)
857
int lock_and_wait_for_table_name(Session *session, TableList *table_list)
859
859
int lock_retcode;
862
if (wait_if_global_read_lock(thd, 0, 1))
862
if (wait_if_global_read_lock(session, 0, 1))
864
VOID(pthread_mutex_lock(&LOCK_open));
865
if ((lock_retcode = lock_table_name(thd, table_list, true)) < 0)
864
pthread_mutex_lock(&LOCK_open);
865
if ((lock_retcode = lock_table_name(session, table_list, true)) < 0)
867
if (lock_retcode && wait_for_locked_table_names(thd, table_list))
867
if (lock_retcode && wait_for_locked_table_names(session, table_list))
869
unlock_table_name(thd, table_list);
869
unlock_table_name(session, table_list);
875
875
pthread_mutex_unlock(&LOCK_open);
876
start_waiting_global_read_lock(thd);
876
start_waiting_global_read_lock(session);
882
882
Put a not open table with an old refresh version in the table cache.
884
@param thd Thread handler
884
@param session Thread handler
885
885
@param table_list Lock first table in this list
886
886
@param check_in_use Do we need to check if table already in use by us
905
905
> 0 table locked, but someone is using it
908
int lock_table_name(THD *thd, TableList *table_list, bool check_in_use)
908
int lock_table_name(Session *session, TableList *table_list, bool check_in_use)
911
911
char key[MAX_DBKEY_LENGTH];
912
912
char *db= table_list->db;
914
914
bool found_locked_table= false;
915
915
HASH_SEARCH_STATE state;
917
key_length= create_table_def_key(thd, key, table_list, 0);
917
key_length= create_table_def_key(session, key, table_list, 0);
919
919
if (check_in_use)
921
921
/* Only insert the table if we haven't insert it already */
922
for (table=(Table*) hash_first(&open_cache, (uchar*)key,
922
for (table=(Table*) hash_first(&open_cache, (unsigned char*)key,
923
923
key_length, &state);
925
table = (Table*) hash_next(&open_cache,(uchar*) key,
925
table = (Table*) hash_next(&open_cache,(unsigned char*) key,
926
926
key_length, &state))
928
928
if (table->reginfo.lock_type < TL_WRITE)
930
if (table->in_use == thd)
930
if (table->in_use == session)
931
931
found_locked_table= true;
935
if (table->in_use == thd)
935
if (table->in_use == session)
937
937
table->s->version= 0; // Ensure no one can use this
938
938
table->locked_by_name= 1;
944
if (thd->locked_tables && thd->locked_tables->table_count &&
945
! find_temporary_table(thd, table_list->db, table_list->table_name))
944
if (session->locked_tables && session->locked_tables->table_count &&
945
! find_temporary_table(session, table_list->db, table_list->table_name))
947
947
if (found_locked_table)
948
948
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_list->alias);
955
if (!(table= table_cache_insert_placeholder(thd, key, key_length)))
955
if (!(table= table_cache_insert_placeholder(session, key, key_length)))
958
958
table_list->table=table;
960
960
/* Return 1 if table is in use */
961
return(test(remove_table_from_cache(thd, db, table_list->table_name,
961
return(test(remove_table_from_cache(session, db, table_list->table_name,
962
962
check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG)));
966
void unlock_table_name(THD *thd __attribute__((unused)),
966
void unlock_table_name(Session *session __attribute__((unused)),
967
967
TableList *table_list)
969
969
if (table_list->table)
971
hash_delete(&open_cache, (uchar*) table_list->table);
971
hash_delete(&open_cache, (unsigned char*) table_list->table);
972
972
broadcast_refresh();
977
static bool locked_named_table(THD *thd __attribute__((unused)),
977
static bool locked_named_table(Session *session __attribute__((unused)),
978
978
TableList *table_list)
980
980
for (; table_list ; table_list=table_list->next_local)
998
bool wait_for_locked_table_names(THD *thd, TableList *table_list)
998
bool wait_for_locked_table_names(Session *session, TableList *table_list)
1002
1002
safe_mutex_assert_owner(&LOCK_open);
1004
while (locked_named_table(thd,table_list))
1004
while (locked_named_table(session,table_list))
1006
if (session->killed)
1011
wait_for_condition(thd, &LOCK_open, &COND_refresh);
1011
wait_for_condition(session, &LOCK_open, &COND_refresh);
1012
1012
pthread_mutex_lock(&LOCK_open);
1014
1014
return(result);
1042
1042
for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
1045
if ((got_lock=lock_table_name(thd,lock_table, true)) < 0)
1045
if ((got_lock=lock_table_name(session,lock_table, true)) < 0)
1046
1046
goto end; // Fatal error
1048
1048
got_all_locks=0; // Someone is using table
1051
1051
/* If some table was in use, wait until we got the lock */
1052
if (!got_all_locks && wait_for_locked_table_names(thd, table_list))
1052
if (!got_all_locks && wait_for_locked_table_names(session, table_list))
1057
unlock_table_names(thd, table_list, lock_table);
1057
unlock_table_names(session, table_list, lock_table);
1078
1078
@retval FALSE Name lock successfully acquired.
1081
bool lock_table_names_exclusively(THD *thd, TableList *table_list)
1081
bool lock_table_names_exclusively(Session *session, TableList *table_list)
1083
if (lock_table_names(thd, table_list))
1083
if (lock_table_names(session, table_list))
1099
1099
Test is 'table' is protected by an exclusive name lock.
1101
@param[in] thd The current thread handler
1101
@param[in] session The current thread handler
1102
1102
@param[in] table_list Table container containing the single table to be
1113
is_table_name_exclusively_locked_by_this_thread(THD *thd,
1113
is_table_name_exclusively_locked_by_this_thread(Session *session,
1114
1114
TableList *table_list)
1116
1116
char key[MAX_DBKEY_LENGTH];
1119
key_length= create_table_def_key(thd, key, table_list, 0);
1121
return is_table_name_exclusively_locked_by_this_thread(thd, (uchar *)key,
1117
uint32_t key_length;
1119
key_length= create_table_def_key(session, key, table_list, 0);
1121
return is_table_name_exclusively_locked_by_this_thread(session, (unsigned char *)key,
1149
1149
table= (Table*) hash_next(&open_cache, key,
1150
1150
key_length, &state))
1152
if (table->in_use == thd &&
1152
if (table->in_use == session &&
1153
1153
table->open_placeholder == 1 &&
1154
1154
table->s->version == 0)
1182
1182
1 Fatal error (end of memory ?)
1185
void unlock_table_names(THD *thd, TableList *table_list,
1185
void unlock_table_names(Session *session, TableList *table_list,
1186
1186
TableList *last_table)
1188
1188
for (TableList *table= table_list;
1189
1189
table != last_table;
1190
1190
table= table->next_local)
1191
unlock_table_name(thd,table);
1191
unlock_table_name(session,table);
1192
1192
broadcast_refresh();
1285
1285
If we have merged 1) and 3) into 1), we would have had this deadlock:
1286
1286
imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
1288
thd1: SELECT * FROM t FOR UPDATE;
1289
thd2: UPDATE t SET a=1; # blocked by row-level locks of thd1
1290
thd3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
1291
table instance of thd2
1292
thd1: COMMIT; # blocked by thd3.
1293
thd1 blocks thd2 which blocks thd3 which blocks thd1: deadlock.
1288
session1: SELECT * FROM t FOR UPDATE;
1289
session2: UPDATE t SET a=1; # blocked by row-level locks of session1
1290
session3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
1291
table instance of session2
1292
session1: COMMIT; # blocked by session3.
1293
session1 blocks session2 which blocks session3 which blocks session1: deadlock.
1295
1295
Note that we need to support that one thread does
1296
1296
FLUSH TABLES WITH READ LOCK; and then COMMIT;
1301
1301
****************************************************************************/
1303
volatile uint global_read_lock=0;
1304
volatile uint global_read_lock_blocks_commit=0;
1305
static volatile uint protect_against_global_read_lock=0;
1306
static volatile uint waiting_for_read_lock=0;
1303
volatile uint32_t global_read_lock=0;
1304
volatile uint32_t global_read_lock_blocks_commit=0;
1305
static volatile uint32_t protect_against_global_read_lock=0;
1306
static volatile uint32_t waiting_for_read_lock=0;
1308
1308
#define GOT_GLOBAL_READ_LOCK 1
1309
1309
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
1311
bool lock_global_read_lock(THD *thd)
1311
bool lock_global_read_lock(Session *session)
1313
if (!thd->global_read_lock)
1313
if (!session->global_read_lock)
1315
1315
const char *old_message;
1316
1316
(void) pthread_mutex_lock(&LOCK_global_read_lock);
1317
old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1317
old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1318
1318
"Waiting to get readlock");
1320
1320
waiting_for_read_lock++;
1321
while (protect_against_global_read_lock && !thd->killed)
1321
while (protect_against_global_read_lock && !session->killed)
1322
1322
pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1323
1323
waiting_for_read_lock--;
1324
if (session->killed)
1326
thd->exit_cond(old_message);
1326
session->exit_cond(old_message);
1329
thd->global_read_lock= GOT_GLOBAL_READ_LOCK;
1329
session->global_read_lock= GOT_GLOBAL_READ_LOCK;
1330
1330
global_read_lock++;
1331
thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1331
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1334
1334
We DON'T set global_read_lock_blocks_commit now, it will be set after
1345
void unlock_global_read_lock(THD *thd)
1345
void unlock_global_read_lock(Session *session)
1349
1349
pthread_mutex_lock(&LOCK_global_read_lock);
1350
1350
tmp= --global_read_lock;
1351
if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1351
if (session->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1352
1352
--global_read_lock_blocks_commit;
1353
1353
pthread_mutex_unlock(&LOCK_global_read_lock);
1354
1354
/* Send the signal outside the mutex to avoid a context switch */
1365
1365
(is_not_commit || \
1366
1366
global_read_lock_blocks_commit))
1368
bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
1368
bool wait_if_global_read_lock(Session *session, bool abort_on_refresh,
1369
1369
bool is_not_commit)
1371
1371
const char *old_message= NULL;
1381
1381
(void) pthread_mutex_lock(&LOCK_global_read_lock);
1382
1382
if ((need_exit_cond= must_wait))
1384
if (thd->global_read_lock) // This thread had the read locks
1384
if (session->global_read_lock) // This thread had the read locks
1386
1386
if (is_not_commit)
1387
1387
my_message(ER_CANT_UPDATE_WITH_READLOCK,
1395
1395
return(is_not_commit);
1397
old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1397
old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1398
1398
"Waiting for release of readlock");
1399
while (must_wait && ! thd->killed &&
1400
(!abort_on_refresh || thd->version == refresh_version))
1399
while (must_wait && ! session->killed &&
1400
(!abort_on_refresh || session->version == refresh_version))
1402
1402
(void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1404
if (session->killed)
1407
1407
if (!abort_on_refresh && !result)
1411
1411
and if old_message is set
1413
1413
if (unlikely(need_exit_cond))
1414
thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1414
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1416
1416
pthread_mutex_unlock(&LOCK_global_read_lock);
1417
1417
return(result);
1421
void start_waiting_global_read_lock(THD *thd)
1421
void start_waiting_global_read_lock(Session *session)
1424
if (unlikely(thd->global_read_lock))
1424
if (unlikely(session->global_read_lock))
1426
1426
(void) pthread_mutex_lock(&LOCK_global_read_lock);
1427
1427
tmp= (!--protect_against_global_read_lock &&
1441
1441
If we didn't succeed lock_global_read_lock(), or if we already suceeded
1442
1442
make_global_read_lock_block_commit(), do nothing.
1444
if (thd->global_read_lock != GOT_GLOBAL_READ_LOCK)
1444
if (session->global_read_lock != GOT_GLOBAL_READ_LOCK)
1446
1446
pthread_mutex_lock(&LOCK_global_read_lock);
1447
1447
/* increment this BEFORE waiting on cond (otherwise race cond) */
1448
1448
global_read_lock_blocks_commit++;
1449
1449
/* For testing we set up some blocking, to see if we can be killed */
1450
1450
protect_against_global_read_lock++;
1451
old_message= thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1451
old_message= session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1452
1452
"Waiting for all running commits to finish");
1453
while (protect_against_global_read_lock && !thd->killed)
1453
while (protect_against_global_read_lock && !session->killed)
1454
1454
pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1455
1455
protect_against_global_read_lock--;
1456
if ((error= test(thd->killed)))
1456
if ((error= test(session->killed)))
1457
1457
global_read_lock_blocks_commit--; // undo what we did
1459
thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1460
thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1459
session->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1460
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1484
1484
void broadcast_refresh(void)
1486
VOID(pthread_cond_broadcast(&COND_refresh));
1487
VOID(pthread_cond_broadcast(&COND_global_read_lock));
1486
pthread_cond_broadcast(&COND_refresh);
1487
pthread_cond_broadcast(&COND_global_read_lock);
1506
1506
-1 Error: no recovery possible.
1509
int try_transactional_lock(THD *thd, TableList *table_list)
1509
int try_transactional_lock(Session *session, TableList *table_list)
1511
uint32_t dummy_counter;
1515
1515
/* Need to open the tables to be able to access engine methods. */
1516
if (open_tables(thd, &table_list, &dummy_counter, 0))
1516
if (open_tables(session, &table_list, &dummy_counter, 0))
1518
1518
/* purecov: begin tested */
1523
1523
/* Required by InnoDB. */
1524
thd->in_lock_tables= true;
1524
session->in_lock_tables= true;
1526
if ((error= set_handler_table_locks(thd, table_list, true)))
1526
if ((error= set_handler_table_locks(session, table_list, true)))
1529
1529
Not all transactional locks could be taken. If the error was
1548
1548
/* We need to explicitly commit if autocommit mode is active. */
1549
(void) ha_autocommit_or_rollback(thd, 0);
1549
(void) ha_autocommit_or_rollback(session, 0);
1550
1550
/* Close the tables. The locks (if taken) persist in the storage engines. */
1551
close_tables_for_reopen(thd, &table_list);
1552
thd->in_lock_tables= false;
1551
close_tables_for_reopen(session, &table_list);
1552
session->in_lock_tables= false;
1553
1553
return(result);
1610
1610
/* We must not convert the lock method within an active transaction. */
1611
if (thd->active_transaction())
1611
if (session->active_transaction())
1613
1613
my_error(ER_NO_AUTO_CONVERT_LOCK_TRANSACTION, MYF(0),
1614
1614
tlist->alias ? tlist->alias : tlist->table_name);
1619
1619
/* Warn about the conversion. */
1620
1620
snprintf(warn_buff, sizeof(warn_buff), ER(ER_WARN_AUTO_CONVERT_LOCK),
1621
1621
tlist->alias ? tlist->alias : tlist->table_name);
1622
push_warning(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1622
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1623
1623
ER_WARN_AUTO_CONVERT_LOCK, warn_buff);
1641
1641
!= 0 Error code from handler::lock_table().
1644
int set_handler_table_locks(THD *thd, TableList *table_list,
1644
int set_handler_table_locks(Session *session, TableList *table_list,
1645
1645
bool transactional)
1647
1647
TableList *tlist;
1701
1701
if (!error || !transactional)
1703
error= tlist->table->file->lock_table(thd, lock_type, lock_timeout);
1703
error= tlist->table->file->lock_table(session, lock_type, lock_timeout);
1704
1704
if (error && transactional && (error != HA_ERR_WRONG_COMMAND))
1705
1705
tlist->table->file->print_error(error, MYF(0));