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(session,locktype) for each table.
33
table_handler->external_lock(thd,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(session, F_UNLCK) for each table.
38
table_handler->external_lock(thd, 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(session, F_UNLOCK) on these.
46
and we never call external_lock(thd, 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(session,locktype) for each table.
52
table_handler->external_lock(thd,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(Session)
55
- For each statement, we will call table_handler->start_stmt(THD)
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(session);
61
- When statement is done, we will call ha_commit_stmt(thd);
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(session, locktype) fails, we call
67
table_handler->external_lock(session, F_UNLCK) for each table that was locked,
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,
68
68
excluding one that caused failure. That means handler must cleanup itself
69
69
in case external_lock() fails.
72
Change to use malloc() ONLY when using LOCK TABLES command or when
72
Change to use my_malloc() ONLY when using LOCK TABLES command or when
73
73
we are forced to use mysql_lock_merge.
75
75
#include <drizzled/server_includes.h>
76
#include <drizzled/error.h>
77
#include <mysys/hash.h>
78
#include <mysys/thr_lock.h>
79
#include <drizzled/session.h>
80
#include <drizzled/sql_base.h>
81
#include <drizzled/lock.h>
76
#include <drizzled/drizzled_error_messages.h>
84
79
@defgroup Locking Locking
91
86
#define GET_LOCK_UNLOCK 1
92
87
#define GET_LOCK_STORE_LOCKS 2
94
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table,
96
uint32_t flags, 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);
89
static DRIZZLE_LOCK *get_lock_data(THD *thd, Table **table,uint32_t count,
90
uint32_t flags, Table **write_locked);
91
static int lock_external(THD *thd, Table **table,uint32_t count);
92
static int unlock_external(THD *thd, Table **table,uint32_t count);
99
93
static void print_lock_error(int error, const char *);
105
99
mysql_lock_tables()
106
session The current thread.
100
thd The current thread.
107
101
tables An array of pointers to the tables to lock.
108
102
count The number of tables to lock.
110
104
DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
105
DRIZZLE_LOCK_IGNORE_GLOBAL_READ_ONLY Ignore SET GLOBAL READ_ONLY
111
106
DRIZZLE_LOCK_IGNORE_FLUSH Ignore a flush tables.
112
107
DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN Instead of reopening altered
113
108
or dropped tables by itself,
168
DRIZZLE_LOCK *mysql_lock_tables(Session *session, Table **tables, uint32_t count,
163
DRIZZLE_LOCK *mysql_lock_tables(THD *thd, Table **tables, uint32_t count,
169
164
uint32_t flags, bool *need_reopen)
171
166
DRIZZLE_LOCK *sql_lock;
179
if (! (sql_lock= get_lock_data(session, tables, count, GET_LOCK_STORE_LOCKS,
174
if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS,
180
175
&write_lock_used)))
187
182
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
188
183
Wait until the lock is gone
190
if (wait_if_global_read_lock(session, 1, 1))
185
if (wait_if_global_read_lock(thd, 1, 1))
192
187
/* Clear the lock type of all lock data to avoid reusage. */
193
188
reset_lock_data_and_free(&sql_lock);
196
if (session->version != refresh_version)
191
if (thd->version != refresh_version)
198
193
/* Clear the lock type of all lock data to avoid reusage. */
199
194
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,
199
if (!(flags & DRIZZLE_LOCK_IGNORE_GLOBAL_READ_ONLY) &&
205
Someone has issued SET GLOBAL READ_ONLY=1 and we want a write lock.
206
We do not wait for READ_ONLY=0, and fail.
208
reset_lock_data_and_free(&sql_lock);
209
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
213
thd_proc_info(thd, "System lock");
214
if (sql_lock->table_count && lock_external(thd, sql_lock->table,
206
215
sql_lock->table_count))
208
217
/* Clear the lock type of all lock data to avoid reusage. */
209
218
reset_lock_data_and_free(&sql_lock);
212
session->set_proc_info("Table lock");
221
thd_proc_info(thd, "Table lock");
213
222
/* Copy the lock data array. thr_multi_lock() reorders its contens. */
214
223
memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
215
224
sql_lock->lock_count * sizeof(*sql_lock->locks));
217
226
rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
218
227
sql_lock->lock_count,
219
228
sql_lock->lock_count,
221
230
if (rc > 1) /* a timeout or a deadlock */
223
232
if (sql_lock->table_count)
224
unlock_external(session, sql_lock->table, sql_lock->table_count);
233
unlock_external(thd, sql_lock->table, sql_lock->table_count);
225
234
reset_lock_data_and_free(&sql_lock);
226
235
my_error(rc, MYF(0));
229
238
else if (rc == 1) /* aborted */
231
session->some_tables_deleted=1; // Try again
240
thd->some_tables_deleted=1; // Try again
232
241
sql_lock->lock_count= 0; // Locks are already freed
233
242
// Fall through: unlock, reset lock data, free and retry
235
else if (!session->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
244
else if (!thd->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
238
247
Thread was killed or lock aborted. Let upper level close all
243
else if (!session->open_tables)
252
else if (!thd->open_tables)
245
254
// Only using temporary tables, no need to unlock
246
session->some_tables_deleted=0;
255
thd->some_tables_deleted=0;
249
session->set_proc_info(0);
258
thd_proc_info(thd, 0);
251
260
/* going to retry, unlock all tables */
252
261
if (sql_lock->lock_count)
253
262
thr_multi_unlock(sql_lock->locks, sql_lock->lock_count);
255
264
if (sql_lock->table_count)
256
unlock_external(session, sql_lock->table, sql_lock->table_count);
265
unlock_external(thd, sql_lock->table, sql_lock->table_count);
259
268
If thr_multi_lock fails it resets lock type for tables, which
267
276
*need_reopen= true;
270
if (wait_for_tables(session))
279
if (wait_for_tables(thd))
271
280
break; // Couldn't open tables
273
session->set_proc_info(0);
282
thd_proc_info(thd, 0);
276
session->send_kill_message();
285
thd->send_kill_message();
279
mysql_unlock_tables(session,sql_lock);
288
mysql_unlock_tables(thd,sql_lock);
284
session->set_time_after_lock();
293
thd->set_time_after_lock();
285
294
return (sql_lock);
289
static int lock_external(Session *session, Table **tables, uint32_t count)
298
static int lock_external(THD *thd, Table **tables, uint32_t count)
291
300
register uint32_t i;
292
301
int lock_type,error;
299
308
(*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
300
309
lock_type=F_RDLCK;
302
if ((error=(*tables)->file->ha_external_lock(session,lock_type)))
311
if ((error=(*tables)->file->ha_external_lock(thd,lock_type)))
304
313
print_lock_error(error, (*tables)->file->table_type());
308
(*tables)->file->ha_external_lock(session, F_UNLCK);
317
(*tables)->file->ha_external_lock(thd, F_UNLCK);
309
318
(*tables)->current_lock=F_UNLCK;
323
void mysql_unlock_tables(Session *session, DRIZZLE_LOCK *sql_lock)
332
void mysql_unlock_tables(THD *thd, DRIZZLE_LOCK *sql_lock)
325
334
if (sql_lock->lock_count)
326
335
thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
327
336
if (sql_lock->table_count)
328
unlock_external(session,sql_lock->table,sql_lock->table_count);
337
unlock_external(thd,sql_lock->table,sql_lock->table_count);
329
338
free((unsigned char*) sql_lock);
336
345
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)
348
void mysql_unlock_some_tables(THD *thd, Table **table,uint32_t count)
341
350
DRIZZLE_LOCK *sql_lock;
342
351
Table *write_lock_used;
343
if ((sql_lock= get_lock_data(session, table, count, GET_LOCK_UNLOCK,
352
if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK,
344
353
&write_lock_used)))
345
mysql_unlock_tables(session, sql_lock);
354
mysql_unlock_tables(thd, sql_lock);
388
397
/* Unlock all read locked tables */
391
unlock_external(session,table,i-found);
400
unlock_external(thd,table,i-found);
392
401
sql_lock->table_count=found;
394
403
/* Fix the lock positions in Table */
419
428
unlock_external() we call handler::external_lock(F_UNLCK) only
420
429
if table->current_lock is not F_UNLCK.
422
@param session thread context
431
@param thd thread context
423
432
@param locked list of locked tables
424
433
@param table the table to unlock
425
434
@param always_unlock specify explicitly if the legacy side
426
435
effect is desired.
429
void mysql_lock_remove(Session *session, DRIZZLE_LOCK *locked,Table *table,
438
void mysql_lock_remove(THD *thd, DRIZZLE_LOCK *locked,Table *table,
430
439
bool always_unlock)
432
441
if (always_unlock == true)
433
mysql_unlock_some_tables(session, &table, /* table count */ 1);
442
mysql_unlock_some_tables(thd, &table, /* table count */ 1);
436
445
register uint32_t i;
447
456
/* Unlock if not yet unlocked */
448
457
if (always_unlock == false)
449
mysql_unlock_some_tables(session, &table, /* table count */ 1);
458
mysql_unlock_some_tables(thd, &table, /* table count */ 1);
451
460
/* Decrement table_count in advance, making below expressions easier */
452
461
old_tables= --locked->table_count;
455
464
removed_locks= table->lock_count;
457
466
/* Move down all table pointers above 'i'. */
458
memmove((locked->table+i), (locked->table+i+1),
459
(old_tables - i) * sizeof(Table*));
467
memcpy((locked->table+i), (locked->table+i+1),
468
(old_tables - i) * sizeof(Table*));
461
470
lock_data_end= table->lock_data_start + table->lock_count;
462
471
/* Move down all lock data pointers above 'table->lock_data_end-1' */
463
memmove((locked->locks + table->lock_data_start),
464
(locked->locks + lock_data_end),
465
(locked->lock_count - lock_data_end) *
466
sizeof(THR_LOCK_DATA*));
472
memcpy((locked->locks + table->lock_data_start),
473
(locked->locks + lock_data_end),
474
(locked->lock_count - lock_data_end) *
475
sizeof(THR_LOCK_DATA*));
469
478
Fix moved table elements.
492
501
/* Downgrade all locks on a table to new WRITE level from WRITE_ONLY */
494
void mysql_lock_downgrade_write(Session *session, Table *table,
503
void mysql_lock_downgrade_write(THD *thd, Table *table,
495
504
thr_lock_type new_lock_type)
497
506
DRIZZLE_LOCK *locked;
498
507
Table *write_lock_used;
499
if ((locked = get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
508
if ((locked = get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
500
509
&write_lock_used)))
502
511
for (uint32_t i=0; i < locked->lock_count; i++)
509
518
/** Abort all other threads waiting to get lock in table. */
511
void mysql_lock_abort(Session *session, Table *table, bool upgrade_lock)
520
void mysql_lock_abort(THD *thd, Table *table, bool upgrade_lock)
513
522
DRIZZLE_LOCK *locked;
514
523
Table *write_lock_used;
516
if ((locked= get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
525
if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
517
526
&write_lock_used)))
519
528
for (uint32_t i=0; i < locked->lock_count; i++)
536
545
1 Table was locked by at least one other thread
539
bool mysql_lock_abort_for_thread(Session *session, Table *table)
548
bool mysql_lock_abort_for_thread(THD *thd, Table *table)
541
550
DRIZZLE_LOCK *locked;
542
551
Table *write_lock_used;
543
552
bool result= false;
545
if ((locked= get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
554
if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
546
555
&write_lock_used)))
548
557
for (uint32_t i=0; i < locked->lock_count; i++)
563
572
Table **table, **end_table;
565
574
if (!(sql_lock= (DRIZZLE_LOCK*)
566
malloc(sizeof(*sql_lock)+
567
sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+
568
sizeof(Table*)*(a->table_count+b->table_count))))
575
my_malloc(sizeof(*sql_lock)+
576
sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+
577
sizeof(Table*)*(a->table_count+b->table_count),MYF(MY_WME))))
569
578
return(0); // Fatal error
570
579
sql_lock->lock_count=a->lock_count+b->lock_count;
571
580
sql_lock->table_count=a->table_count+b->table_count;
605
614
get_lock_data(). If we allow two opens on temporary tables later,
606
615
both functions should be checked.
608
@param session The current thread.
617
@param thd The current thread.
609
618
@param needle The table to check for duplicate lock.
610
619
@param haystack The list of tables to search for the dup lock.
711
720
if ((*table)->current_lock != F_UNLCK)
713
722
(*table)->current_lock = F_UNLCK;
714
if ((error=(*table)->file->ha_external_lock(session, F_UNLCK)))
723
if ((error=(*table)->file->ha_external_lock(thd, F_UNLCK)))
716
725
error_code=error;
717
726
print_lock_error(error_code, (*table)->file->table_type());
734
743
@param write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE
737
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table_ptr, uint32_t count,
746
static DRIZZLE_LOCK *get_lock_data(THD *thd, Table **table_ptr, uint32_t count,
738
747
uint32_t flags, Table **write_lock_used)
740
749
uint32_t i,tables,lock_count;
763
772
from the first part immediately before calling thr_multi_lock().
765
774
if (!(sql_lock= (DRIZZLE_LOCK*)
766
malloc(sizeof(*sql_lock) +
767
sizeof(THR_LOCK_DATA*) * tables * 2 +
768
sizeof(table_ptr) * lock_count)))
775
my_malloc(sizeof(*sql_lock) +
776
sizeof(THR_LOCK_DATA*) * tables * 2 +
777
sizeof(table_ptr) * lock_count,
770
780
locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
771
781
to= table_buf= sql_lock->table= (Table**) (locks + tables * 2);
795
805
locks_start= locks;
796
locks= table->file->store_lock(session, locks,
806
locks= table->file->store_lock(thd, locks,
797
807
(flags & GET_LOCK_UNLOCK) ? TL_IGNORE :
799
809
if (flags & GET_LOCK_STORE_LOCKS)
847
int lock_and_wait_for_table_name(Session *session, TableList *table_list)
857
int lock_and_wait_for_table_name(THD *thd, TableList *table_list)
849
859
int lock_retcode;
852
if (wait_if_global_read_lock(session, 0, 1))
862
if (wait_if_global_read_lock(thd, 0, 1))
854
864
pthread_mutex_lock(&LOCK_open);
855
if ((lock_retcode = lock_table_name(session, table_list, true)) < 0)
865
if ((lock_retcode = lock_table_name(thd, table_list, true)) < 0)
857
if (lock_retcode && wait_for_locked_table_names(session, table_list))
867
if (lock_retcode && wait_for_locked_table_names(thd, table_list))
859
unlock_table_name(session, table_list);
869
unlock_table_name(thd, table_list);
865
875
pthread_mutex_unlock(&LOCK_open);
866
start_waiting_global_read_lock(session);
876
start_waiting_global_read_lock(thd);
872
882
Put a not open table with an old refresh version in the table cache.
874
@param session Thread handler
884
@param thd Thread handler
875
885
@param table_list Lock first table in this list
876
886
@param check_in_use Do we need to check if table already in use by us
895
905
> 0 table locked, but someone is using it
898
int lock_table_name(Session *session, TableList *table_list, bool check_in_use)
908
int lock_table_name(THD *thd, TableList *table_list, bool check_in_use)
901
911
char key[MAX_DBKEY_LENGTH];
904
914
bool found_locked_table= false;
905
915
HASH_SEARCH_STATE state;
907
key_length= create_table_def_key(session, key, table_list, 0);
917
key_length= create_table_def_key(thd, key, table_list, 0);
909
919
if (check_in_use)
918
928
if (table->reginfo.lock_type < TL_WRITE)
920
if (table->in_use == session)
930
if (table->in_use == thd)
921
931
found_locked_table= true;
925
if (table->in_use == session)
935
if (table->in_use == thd)
927
937
table->s->version= 0; // Ensure no one can use this
928
938
table->locked_by_name= 1;
934
if (session->locked_tables && session->locked_tables->table_count &&
935
! find_temporary_table(session, table_list->db, table_list->table_name))
944
if (thd->locked_tables && thd->locked_tables->table_count &&
945
! find_temporary_table(thd, table_list->db, table_list->table_name))
937
947
if (found_locked_table)
938
948
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_list->alias);
945
if (!(table= table_cache_insert_placeholder(session, key, key_length)))
955
if (!(table= table_cache_insert_placeholder(thd, key, key_length)))
948
958
table_list->table=table;
950
960
/* Return 1 if table is in use */
951
return(test(remove_table_from_cache(session, db, table_list->table_name,
961
return(test(remove_table_from_cache(thd, db, table_list->table_name,
952
962
check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG)));
956
void unlock_table_name(Session *,
966
void unlock_table_name(THD *thd __attribute__((unused)),
957
967
TableList *table_list)
959
969
if (table_list->table)
988
bool wait_for_locked_table_names(Session *session, TableList *table_list)
998
bool wait_for_locked_table_names(THD *thd, TableList *table_list)
992
1002
safe_mutex_assert_owner(&LOCK_open);
994
while (locked_named_table(session,table_list))
1004
while (locked_named_table(thd,table_list))
1001
wait_for_condition(session, &LOCK_open, &COND_refresh);
1011
wait_for_condition(thd, &LOCK_open, &COND_refresh);
1002
1012
pthread_mutex_lock(&LOCK_open);
1004
1014
return(result);
1032
1042
for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
1035
if ((got_lock=lock_table_name(session,lock_table, true)) < 0)
1045
if ((got_lock=lock_table_name(thd,lock_table, true)) < 0)
1036
1046
goto end; // Fatal error
1038
1048
got_all_locks=0; // Someone is using table
1041
1051
/* If some table was in use, wait until we got the lock */
1042
if (!got_all_locks && wait_for_locked_table_names(session, table_list))
1052
if (!got_all_locks && wait_for_locked_table_names(thd, table_list))
1047
unlock_table_names(session, table_list, lock_table);
1057
unlock_table_names(thd, table_list, lock_table);
1053
1063
Unlock all tables in list with a name lock.
1055
@param session Thread handle.
1065
@param thd Thread handle.
1056
1066
@param table_list Names of tables to lock.
1059
This function needs to be protected by LOCK_open. If we're
1069
This function needs to be protected by LOCK_open. If we're
1060
1070
under LOCK TABLES, this function does not work as advertised. Namely,
1061
1071
it does not exclude other threads from using this table and does not
1062
1072
put an exclusive name lock on this table into the table cache.
1068
1078
@retval FALSE Name lock successfully acquired.
1071
bool lock_table_names_exclusively(Session *session, TableList *table_list)
1081
bool lock_table_names_exclusively(THD *thd, TableList *table_list)
1073
if (lock_table_names(session, table_list))
1083
if (lock_table_names(thd, table_list))
1103
is_table_name_exclusively_locked_by_this_thread(Session *session,
1113
is_table_name_exclusively_locked_by_this_thread(THD *thd,
1104
1114
TableList *table_list)
1106
1116
char key[MAX_DBKEY_LENGTH];
1107
1117
uint32_t key_length;
1109
key_length= create_table_def_key(session, key, table_list, 0);
1119
key_length= create_table_def_key(thd, key, table_list, 0);
1111
return is_table_name_exclusively_locked_by_this_thread(session, (unsigned char *)key,
1121
return is_table_name_exclusively_locked_by_this_thread(thd, (unsigned char *)key,
1172
1182
1 Fatal error (end of memory ?)
1175
void unlock_table_names(Session *session, TableList *table_list,
1185
void unlock_table_names(THD *thd, TableList *table_list,
1176
1186
TableList *last_table)
1178
1188
for (TableList *table= table_list;
1179
1189
table != last_table;
1180
1190
table= table->next_local)
1181
unlock_table_name(session,table);
1191
unlock_table_name(thd,table);
1182
1192
broadcast_refresh();
1275
1285
If we have merged 1) and 3) into 1), we would have had this deadlock:
1276
1286
imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
1278
session1: SELECT * FROM t FOR UPDATE;
1279
session2: UPDATE t SET a=1; # blocked by row-level locks of session1
1280
session3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
1281
table instance of session2
1282
session1: COMMIT; # blocked by session3.
1283
session1 blocks session2 which blocks session3 which blocks session1: deadlock.
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.
1285
1295
Note that we need to support that one thread does
1286
1296
FLUSH TABLES WITH READ LOCK; and then COMMIT;
1298
1308
#define GOT_GLOBAL_READ_LOCK 1
1299
1309
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
1301
bool lock_global_read_lock(Session *session)
1311
bool lock_global_read_lock(THD *thd)
1303
if (!session->global_read_lock)
1313
if (!thd->global_read_lock)
1305
1315
const char *old_message;
1306
1316
(void) pthread_mutex_lock(&LOCK_global_read_lock);
1307
old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1317
old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1308
1318
"Waiting to get readlock");
1310
1320
waiting_for_read_lock++;
1311
while (protect_against_global_read_lock && !session->killed)
1321
while (protect_against_global_read_lock && !thd->killed)
1312
1322
pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1313
1323
waiting_for_read_lock--;
1314
if (session->killed)
1316
session->exit_cond(old_message);
1326
thd->exit_cond(old_message);
1319
session->global_read_lock= GOT_GLOBAL_READ_LOCK;
1329
thd->global_read_lock= GOT_GLOBAL_READ_LOCK;
1320
1330
global_read_lock++;
1321
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1331
thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1324
1334
We DON'T set global_read_lock_blocks_commit now, it will be set after
1335
void unlock_global_read_lock(Session *session)
1345
void unlock_global_read_lock(THD *thd)
1339
1349
pthread_mutex_lock(&LOCK_global_read_lock);
1340
1350
tmp= --global_read_lock;
1341
if (session->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1351
if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1342
1352
--global_read_lock_blocks_commit;
1343
1353
pthread_mutex_unlock(&LOCK_global_read_lock);
1344
1354
/* Send the signal outside the mutex to avoid a context switch */
1355
1365
(is_not_commit || \
1356
1366
global_read_lock_blocks_commit))
1358
bool wait_if_global_read_lock(Session *session, bool abort_on_refresh,
1368
bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
1359
1369
bool is_not_commit)
1361
1371
const char *old_message= NULL;
1371
1381
(void) pthread_mutex_lock(&LOCK_global_read_lock);
1372
1382
if ((need_exit_cond= must_wait))
1374
if (session->global_read_lock) // This thread had the read locks
1384
if (thd->global_read_lock) // This thread had the read locks
1376
1386
if (is_not_commit)
1377
1387
my_message(ER_CANT_UPDATE_WITH_READLOCK,
1385
1395
return(is_not_commit);
1387
old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1397
old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1388
1398
"Waiting for release of readlock");
1389
while (must_wait && ! session->killed &&
1390
(!abort_on_refresh || session->version == refresh_version))
1399
while (must_wait && ! thd->killed &&
1400
(!abort_on_refresh || thd->version == refresh_version))
1392
1402
(void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1394
if (session->killed)
1397
1407
if (!abort_on_refresh && !result)
1401
1411
and if old_message is set
1403
1413
if (unlikely(need_exit_cond))
1404
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1414
thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1406
1416
pthread_mutex_unlock(&LOCK_global_read_lock);
1407
1417
return(result);
1411
void start_waiting_global_read_lock(Session *session)
1421
void start_waiting_global_read_lock(THD *thd)
1414
if (unlikely(session->global_read_lock))
1424
if (unlikely(thd->global_read_lock))
1416
1426
(void) pthread_mutex_lock(&LOCK_global_read_lock);
1417
1427
tmp= (!--protect_against_global_read_lock &&
1431
1441
If we didn't succeed lock_global_read_lock(), or if we already suceeded
1432
1442
make_global_read_lock_block_commit(), do nothing.
1434
if (session->global_read_lock != GOT_GLOBAL_READ_LOCK)
1444
if (thd->global_read_lock != GOT_GLOBAL_READ_LOCK)
1436
1446
pthread_mutex_lock(&LOCK_global_read_lock);
1437
1447
/* increment this BEFORE waiting on cond (otherwise race cond) */
1438
1448
global_read_lock_blocks_commit++;
1439
old_message= session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1449
/* For testing we set up some blocking, to see if we can be killed */
1450
protect_against_global_read_lock++;
1451
old_message= thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1440
1452
"Waiting for all running commits to finish");
1441
while (protect_against_global_read_lock && !session->killed)
1453
while (protect_against_global_read_lock && !thd->killed)
1442
1454
pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1443
if ((error= test(session->killed)))
1455
protect_against_global_read_lock--;
1456
if ((error= test(thd->killed)))
1444
1457
global_read_lock_blocks_commit--; // undo what we did
1446
session->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1447
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1459
thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1460
thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1493
1506
-1 Error: no recovery possible.
1496
int try_transactional_lock(Session *session, TableList *table_list)
1509
int try_transactional_lock(THD *thd, TableList *table_list)
1498
1511
uint32_t dummy_counter;
1502
1515
/* Need to open the tables to be able to access engine methods. */
1503
if (open_tables(session, &table_list, &dummy_counter, 0))
1516
if (open_tables(thd, &table_list, &dummy_counter, 0))
1505
1518
/* purecov: begin tested */
1510
1523
/* Required by InnoDB. */
1511
session->in_lock_tables= true;
1524
thd->in_lock_tables= true;
1513
if ((error= set_handler_table_locks(session, table_list, true)))
1526
if ((error= set_handler_table_locks(thd, table_list, true)))
1516
1529
Not all transactional locks could be taken. If the error was
1535
1548
/* We need to explicitly commit if autocommit mode is active. */
1536
(void) ha_autocommit_or_rollback(session, 0);
1549
(void) ha_autocommit_or_rollback(thd, 0);
1537
1550
/* Close the tables. The locks (if taken) persist in the storage engines. */
1538
close_tables_for_reopen(session, &table_list);
1539
session->in_lock_tables= false;
1551
close_tables_for_reopen(thd, &table_list);
1552
thd->in_lock_tables= false;
1540
1553
return(result);
1597
1610
/* We must not convert the lock method within an active transaction. */
1598
if (session->active_transaction())
1611
if (thd->active_transaction())
1600
1613
my_error(ER_NO_AUTO_CONVERT_LOCK_TRANSACTION, MYF(0),
1601
1614
tlist->alias ? tlist->alias : tlist->table_name);
1606
1619
/* Warn about the conversion. */
1607
1620
snprintf(warn_buff, sizeof(warn_buff), ER(ER_WARN_AUTO_CONVERT_LOCK),
1608
1621
tlist->alias ? tlist->alias : tlist->table_name);
1609
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1622
push_warning(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1610
1623
ER_WARN_AUTO_CONVERT_LOCK, warn_buff);
1688
1701
if (!error || !transactional)
1690
error= tlist->table->file->lock_table(session, lock_type, lock_timeout);
1703
error= tlist->table->file->lock_table(thd, lock_type, lock_timeout);
1691
1704
if (error && transactional && (error != HA_ERR_WRONG_COMMAND))
1692
1705
tlist->table->file->print_error(error, MYF(0));