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