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
- LOCK Table will call mysql_lock_tables() for all tables.
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.
86
88
#define GET_LOCK_UNLOCK 1
87
89
#define GET_LOCK_STORE_LOCKS 2
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);
91
static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
92
uint flags, TABLE **write_locked);
93
static int lock_external(THD *thd, TABLE **table,uint count);
94
static int unlock_external(THD *thd, TABLE **table,uint count);
93
95
static void print_lock_error(int error, const char *);
99
101
mysql_lock_tables()
100
session The current thread.
102
thd The current thread.
101
103
tables An array of pointers to the tables to lock.
102
104
count The number of tables to lock.
104
DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
105
DRIZZLE_LOCK_IGNORE_GLOBAL_READ_ONLY Ignore SET GLOBAL READ_ONLY
106
DRIZZLE_LOCK_IGNORE_FLUSH Ignore a flush tables.
107
DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN Instead of reopening altered
106
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
107
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY Ignore SET GLOBAL READ_ONLY
108
MYSQL_LOCK_IGNORE_FLUSH Ignore a flush tables.
109
MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN Instead of reopening altered
108
110
or dropped tables by itself,
109
111
mysql_lock_tables() should
110
112
notify upper level and rely
121
123
static int thr_lock_errno_to_mysql[]=
122
124
{ 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };
127
Perform semantic checks for mysql_lock_tables.
128
@param thd The current thread
129
@param tables The tables to lock
130
@param count The number of tables to lock
131
@param flags Lock flags
132
@return 0 if all the check passed, non zero if a check failed.
134
int mysql_lock_tables_check(THD *thd __attribute__((unused)),
135
TABLE **tables, uint count,
136
uint flags __attribute__((unused)))
143
for (i=0 ; i<count; i++)
147
/* Protect against 'fake' partially initialized TABLE_SHARE */
148
assert(t->s->table_category != TABLE_UNKNOWN_CATEGORY);
150
if ((t->s->table_category == TABLE_CATEGORY_SYSTEM) &&
151
(t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE))
158
Locking of system tables is restricted:
159
locking a mix of system and non-system tables in the same lock
160
is prohibited, to prevent contention.
162
if ((system_count > 0) && (system_count < count))
164
my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0));
126
173
Reset lock type in lock data and free.
142
189
lock request will set its lock type properly.
145
static void reset_lock_data_and_free(DRIZZLE_LOCK **mysql_lock)
192
static void reset_lock_data_and_free(MYSQL_LOCK **mysql_lock)
147
DRIZZLE_LOCK *sql_lock= *mysql_lock;
194
MYSQL_LOCK *sql_lock= *mysql_lock;
148
195
THR_LOCK_DATA **ldata, **ldata_end;
150
197
/* Clear the lock type of all lock data to avoid reusage. */
155
202
/* Reset lock type. */
156
203
(*ldata)->type= TL_UNLOCK;
158
free((unsigned char*) sql_lock);
205
my_free((uchar*) sql_lock, MYF(0));
163
DRIZZLE_LOCK *mysql_lock_tables(Session *session, Table **tables, uint32_t count,
164
uint32_t flags, bool *need_reopen)
210
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
211
uint flags, bool *need_reopen)
166
DRIZZLE_LOCK *sql_lock;
167
Table *write_lock_used;
213
MYSQL_LOCK *sql_lock;
214
TABLE *write_lock_used;
170
217
*need_reopen= false;
219
if (mysql_lock_tables_check(thd, tables, count, flags))
174
if (! (sql_lock= get_lock_data(session, tables, count, GET_LOCK_STORE_LOCKS,
224
if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS,
175
225
&write_lock_used)))
178
228
if (global_read_lock && write_lock_used &&
179
! (flags & DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK))
229
! (flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK))
182
232
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
183
233
Wait until the lock is gone
185
if (wait_if_global_read_lock(session, 1, 1))
235
if (wait_if_global_read_lock(thd, 1, 1))
187
237
/* Clear the lock type of all lock data to avoid reusage. */
188
238
reset_lock_data_and_free(&sql_lock);
191
if (session->version != refresh_version)
241
if (thd->version != refresh_version)
193
243
/* Clear the lock type of all lock data to avoid reusage. */
194
244
reset_lock_data_and_free(&sql_lock);
213
session->set_proc_info("System lock");
214
if (sql_lock->table_count && lock_external(session, sql_lock->table,
263
thd_proc_info(thd, "System lock");
264
if (sql_lock->table_count && lock_external(thd, sql_lock->table,
215
265
sql_lock->table_count))
217
267
/* Clear the lock type of all lock data to avoid reusage. */
218
268
reset_lock_data_and_free(&sql_lock);
221
session->set_proc_info("Table lock");
271
thd_proc_info(thd, "Table lock");
222
272
/* Copy the lock data array. thr_multi_lock() reorders its contens. */
223
273
memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
224
274
sql_lock->lock_count * sizeof(*sql_lock->locks));
226
276
rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
227
277
sql_lock->lock_count,
228
278
sql_lock->lock_count,
230
280
if (rc > 1) /* a timeout or a deadlock */
232
282
if (sql_lock->table_count)
233
unlock_external(session, sql_lock->table, sql_lock->table_count);
283
VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
234
284
reset_lock_data_and_free(&sql_lock);
235
285
my_error(rc, MYF(0));
238
288
else if (rc == 1) /* aborted */
240
session->some_tables_deleted=1; // Try again
290
thd->some_tables_deleted=1; // Try again
241
291
sql_lock->lock_count= 0; // Locks are already freed
242
292
// Fall through: unlock, reset lock data, free and retry
244
else if (!session->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
294
else if (!thd->some_tables_deleted || (flags & MYSQL_LOCK_IGNORE_FLUSH))
247
297
Thread was killed or lock aborted. Let upper level close all
252
else if (!session->open_tables)
302
else if (!thd->open_tables)
254
304
// Only using temporary tables, no need to unlock
255
session->some_tables_deleted=0;
305
thd->some_tables_deleted=0;
258
session->set_proc_info(0);
308
thd_proc_info(thd, 0);
260
310
/* going to retry, unlock all tables */
261
311
if (sql_lock->lock_count)
262
312
thr_multi_unlock(sql_lock->locks, sql_lock->lock_count);
264
314
if (sql_lock->table_count)
265
unlock_external(session, sql_lock->table, sql_lock->table_count);
315
VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
268
318
If thr_multi_lock fails it resets lock type for tables, which
272
322
reset_lock_data_and_free(&sql_lock);
274
if (flags & DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN)
324
if (flags & MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN)
276
326
*need_reopen= true;
279
if (wait_for_tables(session))
329
if (wait_for_tables(thd))
280
330
break; // Couldn't open tables
282
session->set_proc_info(0);
332
thd_proc_info(thd, 0);
285
session->send_kill_message();
335
thd->send_kill_message();
288
mysql_unlock_tables(session,sql_lock);
338
mysql_unlock_tables(thd,sql_lock);
293
session->set_time_after_lock();
343
thd->set_time_after_lock();
294
344
return (sql_lock);
298
static int lock_external(Session *session, Table **tables, uint32_t count)
348
static int lock_external(THD *thd, TABLE **tables, uint count)
301
351
int lock_type,error;
302
352
for (i=1 ; i <= count ; i++, tables++)
308
358
(*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
309
359
lock_type=F_RDLCK;
311
if ((error=(*tables)->file->ha_external_lock(session,lock_type)))
361
if ((error=(*tables)->file->ha_external_lock(thd,lock_type)))
313
363
print_lock_error(error, (*tables)->file->table_type());
317
(*tables)->file->ha_external_lock(session, F_UNLCK);
367
(*tables)->file->ha_external_lock(thd, F_UNLCK);
318
368
(*tables)->current_lock=F_UNLCK;
332
void mysql_unlock_tables(Session *session, DRIZZLE_LOCK *sql_lock)
382
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
334
384
if (sql_lock->lock_count)
335
385
thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
336
386
if (sql_lock->table_count)
337
unlock_external(session,sql_lock->table,sql_lock->table_count);
338
free((unsigned char*) sql_lock);
387
VOID(unlock_external(thd,sql_lock->table,sql_lock->table_count));
388
my_free((uchar*) sql_lock,MYF(0));
345
395
This will work even if get_lock_data fails (next unlock will free all)
348
void mysql_unlock_some_tables(Session *session, Table **table,uint32_t count)
398
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count)
350
DRIZZLE_LOCK *sql_lock;
351
Table *write_lock_used;
352
if ((sql_lock= get_lock_data(session, table, count, GET_LOCK_UNLOCK,
400
MYSQL_LOCK *sql_lock;
401
TABLE *write_lock_used;
402
if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK,
353
403
&write_lock_used)))
354
mysql_unlock_tables(session, sql_lock);
404
mysql_unlock_tables(thd, sql_lock);
384
434
/* Then do the same for the external locks */
385
435
/* Move all write locked tables first */
386
Table **table=sql_lock->table;
436
TABLE **table=sql_lock->table;
387
437
for (i=found=0 ; i < sql_lock->table_count ; i++)
389
439
assert(sql_lock->table[i]->lock_position == i);
390
440
if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
392
std::swap(*table, sql_lock->table[i]);
442
swap_variables(TABLE *, *table, sql_lock->table[i]);
397
447
/* Unlock all read locked tables */
400
unlock_external(session,table,i-found);
450
VOID(unlock_external(thd,table,i-found));
401
451
sql_lock->table_count=found;
403
/* Fix the lock positions in Table */
453
/* Fix the lock positions in TABLE */
404
454
table= sql_lock->table;
406
456
for (i= 0; i < sql_lock->table_count; i++)
409
459
tbl->lock_position= table - sql_lock->table;
410
460
tbl->lock_data_start= found;
411
461
found+= tbl->lock_count;
428
478
unlock_external() we call handler::external_lock(F_UNLCK) only
429
479
if table->current_lock is not F_UNLCK.
431
@param session thread context
481
@param thd thread context
432
482
@param locked list of locked tables
433
483
@param table the table to unlock
434
484
@param always_unlock specify explicitly if the legacy side
435
485
effect is desired.
438
void mysql_lock_remove(Session *session, DRIZZLE_LOCK *locked,Table *table,
488
void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table,
439
489
bool always_unlock)
441
491
if (always_unlock == true)
442
mysql_unlock_some_tables(session, &table, /* table count */ 1);
492
mysql_unlock_some_tables(thd, &table, /* table count */ 1);
446
496
for (i=0; i < locked->table_count; i++)
448
498
if (locked->table[i] == table)
450
uint32_t j, removed_locks, old_tables;
452
uint32_t lock_data_end;
500
uint j, removed_locks, old_tables;
454
504
assert(table->lock_position == i);
456
506
/* Unlock if not yet unlocked */
457
507
if (always_unlock == false)
458
mysql_unlock_some_tables(session, &table, /* table count */ 1);
508
mysql_unlock_some_tables(thd, &table, /* table count */ 1);
460
510
/* Decrement table_count in advance, making below expressions easier */
461
511
old_tables= --locked->table_count;
464
514
removed_locks= table->lock_count;
466
516
/* Move down all table pointers above 'i'. */
467
memcpy((locked->table+i), (locked->table+i+1),
468
(old_tables - i) * sizeof(Table*));
517
memcpy((char*) (locked->table+i),
518
(char*) (locked->table+i+1),
519
(old_tables - i) * sizeof(TABLE*));
470
521
lock_data_end= table->lock_data_start + table->lock_count;
471
522
/* 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),
523
memcpy((char*) (locked->locks + table->lock_data_start),
524
(char*) (locked->locks + lock_data_end),
474
525
(locked->lock_count - lock_data_end) *
475
526
sizeof(THR_LOCK_DATA*));
501
552
/* Downgrade all locks on a table to new WRITE level from WRITE_ONLY */
503
void mysql_lock_downgrade_write(Session *session, Table *table,
554
void mysql_lock_downgrade_write(THD *thd, TABLE *table,
504
555
thr_lock_type new_lock_type)
506
DRIZZLE_LOCK *locked;
507
Table *write_lock_used;
508
if ((locked = get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
558
TABLE *write_lock_used;
559
if ((locked = get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
509
560
&write_lock_used)))
511
for (uint32_t i=0; i < locked->lock_count; i++)
562
for (uint i=0; i < locked->lock_count; i++)
512
563
thr_downgrade_write_lock(locked->locks[i], new_lock_type);
513
free((unsigned char*) locked);
564
my_free((uchar*) locked,MYF(0));
518
569
/** Abort all other threads waiting to get lock in table. */
520
void mysql_lock_abort(Session *session, Table *table, bool upgrade_lock)
571
void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock)
522
DRIZZLE_LOCK *locked;
523
Table *write_lock_used;
574
TABLE *write_lock_used;
525
if ((locked= get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
576
if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
526
577
&write_lock_used)))
528
for (uint32_t i=0; i < locked->lock_count; i++)
579
for (uint i=0; i < locked->lock_count; i++)
529
580
thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
530
free((unsigned char*) locked);
581
my_free((uchar*) locked,MYF(0));
545
596
1 Table was locked by at least one other thread
548
bool mysql_lock_abort_for_thread(Session *session, Table *table)
599
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
550
DRIZZLE_LOCK *locked;
551
Table *write_lock_used;
602
TABLE *write_lock_used;
552
603
bool result= false;
554
if ((locked= get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
605
if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
555
606
&write_lock_used)))
557
for (uint32_t i=0; i < locked->lock_count; i++)
608
for (uint i=0; i < locked->lock_count; i++)
559
610
if (thr_abort_locks_for_thread(locked->locks[i]->lock,
560
611
table->in_use->thread_id))
563
free((unsigned char*) locked);
614
my_free((uchar*) locked,MYF(0));
569
DRIZZLE_LOCK *mysql_lock_merge(DRIZZLE_LOCK *a,DRIZZLE_LOCK *b)
620
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
571
DRIZZLE_LOCK *sql_lock;
572
Table **table, **end_table;
622
MYSQL_LOCK *sql_lock;
623
TABLE **table, **end_table;
574
if (!(sql_lock= (DRIZZLE_LOCK*)
625
if (!(sql_lock= (MYSQL_LOCK*)
575
626
my_malloc(sizeof(*sql_lock)+
576
627
sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+
577
sizeof(Table*)*(a->table_count+b->table_count),MYF(MY_WME))))
628
sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME))))
578
629
return(0); // Fatal error
579
630
sql_lock->lock_count=a->lock_count+b->lock_count;
580
631
sql_lock->table_count=a->table_count+b->table_count;
581
632
sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
582
sql_lock->table=(Table**) (sql_lock->locks+sql_lock->lock_count);
633
sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count);
583
634
memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
584
635
memcpy(sql_lock->locks+a->lock_count,b->locks,
585
636
b->lock_count*sizeof(*b->locks));
586
637
memcpy(sql_lock->table,a->table,a->table_count*sizeof(*a->table));
587
638
memcpy(sql_lock->table+a->table_count,b->table,
588
b->table_count*sizeof(*b->table));
639
b->table_count*sizeof(*b->table));
591
642
Now adjust lock_position and lock_data_start for all objects that was
614
665
get_lock_data(). If we allow two opens on temporary tables later,
615
666
both functions should be checked.
617
@param session The current thread.
668
@param thd The current thread.
618
669
@param needle The table to check for duplicate lock.
619
670
@param haystack The list of tables to search for the dup lock.
630
681
!NULL First table from 'haystack' that matches a lock on 'needle'.
633
TableList *mysql_lock_have_duplicate(Session *session, TableList *needle,
684
TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
685
TABLE_LIST *haystack)
636
DRIZZLE_LOCK *mylock;
640
691
THR_LOCK_DATA **lock_locks;
641
692
THR_LOCK_DATA **table_lock_data;
642
693
THR_LOCK_DATA **end_data;
720
771
if ((*table)->current_lock != F_UNLCK)
722
773
(*table)->current_lock = F_UNLCK;
723
if ((error=(*table)->file->ha_external_lock(session, F_UNLCK)))
774
if ((error=(*table)->file->ha_external_lock(thd, F_UNLCK)))
725
776
error_code=error;
726
777
print_lock_error(error_code, (*table)->file->table_type());
736
787
Get lock structures from table structs and initialize locks.
738
@param session Thread handler
789
@param thd Thread handler
739
790
@param table_ptr Pointer to tables that should be locks
740
791
@param flags One of:
741
792
- GET_LOCK_UNLOCK : If we should send TL_IGNORE to store lock
742
- GET_LOCK_STORE_LOCKS : Store lock info in Table
793
- GET_LOCK_STORE_LOCKS : Store lock info in TABLE
743
794
@param write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE
746
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table_ptr, uint32_t count,
747
uint32_t flags, Table **write_lock_used)
797
static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
798
uint flags, TABLE **write_lock_used)
749
uint32_t i,tables,lock_count;
750
DRIZZLE_LOCK *sql_lock;
800
uint i,tables,lock_count;
801
MYSQL_LOCK *sql_lock;
751
802
THR_LOCK_DATA **locks, **locks_buf, **locks_start;
752
Table **to, **table_buf;
803
TABLE **to, **table_buf;
754
805
assert((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS));
756
807
*write_lock_used=0;
757
808
for (i=tables=lock_count=0 ; i < count ; i++)
759
Table *t= table_ptr[i];
810
TABLE *t= table_ptr[i];
761
812
if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE)
771
822
update the table values. So the second part of the array is copied
772
823
from the first part immediately before calling thr_multi_lock().
774
if (!(sql_lock= (DRIZZLE_LOCK*)
825
if (!(sql_lock= (MYSQL_LOCK*)
775
826
my_malloc(sizeof(*sql_lock) +
776
827
sizeof(THR_LOCK_DATA*) * tables * 2 +
777
828
sizeof(table_ptr) * lock_count,
780
831
locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
781
to= table_buf= sql_lock->table= (Table**) (locks + tables * 2);
832
to= table_buf= sql_lock->table= (TABLE**) (locks + tables * 2);
782
833
sql_lock->table_count=lock_count;
784
835
for (i=0 ; i < count ; i++)
787
838
enum thr_lock_type lock_type;
789
840
if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
857
int lock_and_wait_for_table_name(Session *session, TableList *table_list)
908
int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list)
859
910
int lock_retcode;
862
if (wait_if_global_read_lock(session, 0, 1))
913
if (wait_if_global_read_lock(thd, 0, 1))
864
pthread_mutex_lock(&LOCK_open);
865
if ((lock_retcode = lock_table_name(session, table_list, true)) < 0)
915
VOID(pthread_mutex_lock(&LOCK_open));
916
if ((lock_retcode = lock_table_name(thd, table_list, true)) < 0)
867
if (lock_retcode && wait_for_locked_table_names(session, table_list))
918
if (lock_retcode && wait_for_locked_table_names(thd, table_list))
869
unlock_table_name(session, table_list);
920
unlock_table_name(thd, table_list);
875
926
pthread_mutex_unlock(&LOCK_open);
876
start_waiting_global_read_lock(session);
927
start_waiting_global_read_lock(thd);
905
956
> 0 table locked, but someone is using it
908
int lock_table_name(Session *session, TableList *table_list, bool check_in_use)
959
int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use)
911
962
char key[MAX_DBKEY_LENGTH];
912
963
char *db= table_list->db;
914
965
bool found_locked_table= false;
915
966
HASH_SEARCH_STATE state;
917
key_length= create_table_def_key(session, key, table_list, 0);
968
key_length= create_table_def_key(thd, key, table_list, 0);
919
970
if (check_in_use)
921
972
/* Only insert the table if we haven't insert it already */
922
for (table=(Table*) hash_first(&open_cache, (unsigned char*)key,
973
for (table=(TABLE*) hash_first(&open_cache, (uchar*)key,
923
974
key_length, &state);
925
table = (Table*) hash_next(&open_cache,(unsigned char*) key,
976
table = (TABLE*) hash_next(&open_cache,(uchar*) key,
926
977
key_length, &state))
928
979
if (table->reginfo.lock_type < TL_WRITE)
930
if (table->in_use == session)
981
if (table->in_use == thd)
931
982
found_locked_table= true;
935
if (table->in_use == session)
986
if (table->in_use == thd)
937
988
table->s->version= 0; // Ensure no one can use this
938
989
table->locked_by_name= 1;
944
if (session->locked_tables && session->locked_tables->table_count &&
945
! find_temporary_table(session, table_list->db, table_list->table_name))
995
if (thd->locked_tables && thd->locked_tables->table_count &&
996
! find_temporary_table(thd, table_list->db, table_list->table_name))
947
998
if (found_locked_table)
948
999
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_list->alias);
955
if (!(table= table_cache_insert_placeholder(session, key, key_length)))
1006
if (!(table= table_cache_insert_placeholder(thd, key, key_length)))
958
1009
table_list->table=table;
960
1011
/* Return 1 if table is in use */
961
return(test(remove_table_from_cache(session, db, table_list->table_name,
1012
return(test(remove_table_from_cache(thd, db, table_list->table_name,
962
1013
check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG)));
966
void unlock_table_name(Session *session __attribute__((unused)),
967
TableList *table_list)
1017
void unlock_table_name(THD *thd __attribute__((unused)),
1018
TABLE_LIST *table_list)
969
1020
if (table_list->table)
971
hash_delete(&open_cache, (unsigned char*) table_list->table);
1022
hash_delete(&open_cache, (uchar*) table_list->table);
972
1023
broadcast_refresh();
977
static bool locked_named_table(Session *session __attribute__((unused)),
978
TableList *table_list)
1028
static bool locked_named_table(THD *thd __attribute__((unused)),
1029
TABLE_LIST *table_list)
980
1031
for (; table_list ; table_list=table_list->next_local)
982
Table *table= table_list->table;
1033
TABLE *table= table_list->table;
985
Table *save_next= table->next;
1036
TABLE *save_next= table->next;
988
1039
result= table_is_used(table_list->table, 0);
998
bool wait_for_locked_table_names(Session *session, TableList *table_list)
1049
bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list)
1002
1053
safe_mutex_assert_owner(&LOCK_open);
1004
while (locked_named_table(session,table_list))
1055
while (locked_named_table(thd,table_list))
1006
if (session->killed)
1011
wait_for_condition(session, &LOCK_open, &COND_refresh);
1062
wait_for_condition(thd, &LOCK_open, &COND_refresh);
1012
1063
pthread_mutex_lock(&LOCK_open);
1014
1065
return(result);
1034
1085
1 Fatal error (end of memory ?)
1037
bool lock_table_names(Session *session, TableList *table_list)
1088
bool lock_table_names(THD *thd, TABLE_LIST *table_list)
1039
1090
bool got_all_locks=1;
1040
TableList *lock_table;
1091
TABLE_LIST *lock_table;
1042
1093
for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
1045
if ((got_lock=lock_table_name(session,lock_table, true)) < 0)
1096
if ((got_lock=lock_table_name(thd,lock_table, true)) < 0)
1046
1097
goto end; // Fatal error
1048
1099
got_all_locks=0; // Someone is using table
1051
1102
/* If some table was in use, wait until we got the lock */
1052
if (!got_all_locks && wait_for_locked_table_names(session, table_list))
1103
if (!got_all_locks && wait_for_locked_table_names(thd, table_list))
1057
unlock_table_names(session, table_list, lock_table);
1108
unlock_table_names(thd, table_list, lock_table);
1078
1129
@retval FALSE Name lock successfully acquired.
1081
bool lock_table_names_exclusively(Session *session, TableList *table_list)
1132
bool lock_table_names_exclusively(THD *thd, TABLE_LIST *table_list)
1083
if (lock_table_names(session, table_list))
1134
if (lock_table_names(thd, table_list))
1087
1138
Upgrade the table name locks from semi-exclusive to exclusive locks.
1089
for (TableList *table= table_list; table; table= table->next_global)
1140
for (TABLE_LIST *table= table_list; table; table= table->next_global)
1091
1142
if (table->table)
1092
1143
table->table->open_placeholder= 1;
1113
is_table_name_exclusively_locked_by_this_thread(Session *session,
1114
TableList *table_list)
1164
is_table_name_exclusively_locked_by_this_thread(THD *thd,
1165
TABLE_LIST *table_list)
1116
1167
char key[MAX_DBKEY_LENGTH];
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,
1170
key_length= create_table_def_key(thd, key, table_list, 0);
1172
return is_table_name_exclusively_locked_by_this_thread(thd, (uchar *)key,
1140
is_table_name_exclusively_locked_by_this_thread(Session *session, unsigned char *key,
1191
is_table_name_exclusively_locked_by_this_thread(THD *thd, uchar *key,
1141
1192
int key_length)
1143
1194
HASH_SEARCH_STATE state;
1146
for (table= (Table*) hash_first(&open_cache, key,
1197
for (table= (TABLE*) hash_first(&open_cache, key,
1147
1198
key_length, &state);
1149
table= (Table*) hash_next(&open_cache, key,
1200
table= (TABLE*) hash_next(&open_cache, key,
1150
1201
key_length, &state))
1152
if (table->in_use == session &&
1203
if (table->in_use == thd &&
1153
1204
table->open_placeholder == 1 &&
1154
1205
table->s->version == 0)
1182
1233
1 Fatal error (end of memory ?)
1185
void unlock_table_names(Session *session, TableList *table_list,
1186
TableList *last_table)
1236
void unlock_table_names(THD *thd, TABLE_LIST *table_list,
1237
TABLE_LIST *last_table)
1188
for (TableList *table= table_list;
1239
for (TABLE_LIST *table= table_list;
1189
1240
table != last_table;
1190
1241
table= table->next_local)
1191
unlock_table_name(session,table);
1242
unlock_table_name(thd,table);
1192
1243
broadcast_refresh();
1285
1336
If we have merged 1) and 3) into 1), we would have had this deadlock:
1286
1337
imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
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.
1339
thd1: SELECT * FROM t FOR UPDATE;
1340
thd2: UPDATE t SET a=1; # blocked by row-level locks of thd1
1341
thd3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
1342
table instance of thd2
1343
thd1: COMMIT; # blocked by thd3.
1344
thd1 blocks thd2 which blocks thd3 which blocks thd1: deadlock.
1295
1346
Note that we need to support that one thread does
1296
1347
FLUSH TABLES WITH READ LOCK; and then COMMIT;
1301
1352
****************************************************************************/
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;
1354
volatile uint global_read_lock=0;
1355
volatile uint global_read_lock_blocks_commit=0;
1356
static volatile uint protect_against_global_read_lock=0;
1357
static volatile uint waiting_for_read_lock=0;
1308
1359
#define GOT_GLOBAL_READ_LOCK 1
1309
1360
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
1311
bool lock_global_read_lock(Session *session)
1362
bool lock_global_read_lock(THD *thd)
1313
if (!session->global_read_lock)
1364
if (!thd->global_read_lock)
1315
1366
const char *old_message;
1316
1367
(void) pthread_mutex_lock(&LOCK_global_read_lock);
1317
old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1368
old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1318
1369
"Waiting to get readlock");
1320
1371
waiting_for_read_lock++;
1321
while (protect_against_global_read_lock && !session->killed)
1372
while (protect_against_global_read_lock && !thd->killed)
1322
1373
pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1323
1374
waiting_for_read_lock--;
1324
if (session->killed)
1326
session->exit_cond(old_message);
1377
thd->exit_cond(old_message);
1329
session->global_read_lock= GOT_GLOBAL_READ_LOCK;
1380
thd->global_read_lock= GOT_GLOBAL_READ_LOCK;
1330
1381
global_read_lock++;
1331
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1382
thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1334
1385
We DON'T set global_read_lock_blocks_commit now, it will be set after
1345
void unlock_global_read_lock(Session *session)
1396
void unlock_global_read_lock(THD *thd)
1349
1400
pthread_mutex_lock(&LOCK_global_read_lock);
1350
1401
tmp= --global_read_lock;
1351
if (session->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1402
if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1352
1403
--global_read_lock_blocks_commit;
1353
1404
pthread_mutex_unlock(&LOCK_global_read_lock);
1354
1405
/* Send the signal outside the mutex to avoid a context switch */
1395
1446
return(is_not_commit);
1397
old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1448
old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1398
1449
"Waiting for release of readlock");
1399
while (must_wait && ! session->killed &&
1400
(!abort_on_refresh || session->version == refresh_version))
1450
while (must_wait && ! thd->killed &&
1451
(!abort_on_refresh || thd->version == refresh_version))
1402
1453
(void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1404
if (session->killed)
1407
1458
if (!abort_on_refresh && !result)
1411
1462
and if old_message is set
1413
1464
if (unlikely(need_exit_cond))
1414
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1465
thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1416
1467
pthread_mutex_unlock(&LOCK_global_read_lock);
1417
1468
return(result);
1421
void start_waiting_global_read_lock(Session *session)
1472
void start_waiting_global_read_lock(THD *thd)
1424
if (unlikely(session->global_read_lock))
1475
if (unlikely(thd->global_read_lock))
1426
1477
(void) pthread_mutex_lock(&LOCK_global_read_lock);
1427
1478
tmp= (!--protect_against_global_read_lock &&
1441
1492
If we didn't succeed lock_global_read_lock(), or if we already suceeded
1442
1493
make_global_read_lock_block_commit(), do nothing.
1444
if (session->global_read_lock != GOT_GLOBAL_READ_LOCK)
1495
if (thd->global_read_lock != GOT_GLOBAL_READ_LOCK)
1446
1497
pthread_mutex_lock(&LOCK_global_read_lock);
1447
1498
/* increment this BEFORE waiting on cond (otherwise race cond) */
1448
1499
global_read_lock_blocks_commit++;
1449
1500
/* For testing we set up some blocking, to see if we can be killed */
1450
1501
protect_against_global_read_lock++;
1451
old_message= session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1502
old_message= thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1452
1503
"Waiting for all running commits to finish");
1453
while (protect_against_global_read_lock && !session->killed)
1504
while (protect_against_global_read_lock && !thd->killed)
1454
1505
pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1455
1506
protect_against_global_read_lock--;
1456
if ((error= test(session->killed)))
1507
if ((error= test(thd->killed)))
1457
1508
global_read_lock_blocks_commit--; // undo what we did
1459
session->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1460
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1510
thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1511
thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1506
1557
-1 Error: no recovery possible.
1509
int try_transactional_lock(Session *session, TableList *table_list)
1560
int try_transactional_lock(THD *thd, TABLE_LIST *table_list)
1511
uint32_t dummy_counter;
1515
1566
/* Need to open the tables to be able to access engine methods. */
1516
if (open_tables(session, &table_list, &dummy_counter, 0))
1567
if (open_tables(thd, &table_list, &dummy_counter, 0))
1518
1569
/* purecov: begin tested */
1523
1574
/* Required by InnoDB. */
1524
session->in_lock_tables= true;
1575
thd->in_lock_tables= true;
1526
if ((error= set_handler_table_locks(session, table_list, true)))
1577
if ((error= set_handler_table_locks(thd, table_list, true)))
1529
1580
Not all transactional locks could be taken. If the error was
1548
1599
/* We need to explicitly commit if autocommit mode is active. */
1549
(void) ha_autocommit_or_rollback(session, 0);
1600
(void) ha_autocommit_or_rollback(thd, 0);
1550
1601
/* Close the tables. The locks (if taken) persist in the storage engines. */
1551
close_tables_for_reopen(session, &table_list);
1552
session->in_lock_tables= false;
1602
close_tables_for_reopen(thd, &table_list);
1603
thd->in_lock_tables= false;
1553
1604
return(result);
1579
1630
-1 Error: Lock conversion is prohibited.
1582
int check_transactional_lock(Session *session, TableList *table_list)
1633
int check_transactional_lock(THD *thd, TABLE_LIST *table_list)
1586
char warn_buff[DRIZZLE_ERRMSG_SIZE];
1637
char warn_buff[MYSQL_ERRMSG_SIZE];
1588
1639
for (tlist= table_list; tlist; tlist= tlist->next_global)
1592
1643
Unfortunately we cannot use tlist->placeholder() here. This method
1593
1644
returns TRUE if the table is not open, which is always the case
1594
here. Whenever the definition of TableList::placeholder() is
1645
here. Whenever the definition of TABLE_LIST::placeholder() is
1595
1646
changed, probably this condition needs to be changed too.
1597
1648
if (tlist->derived || tlist->schema_table || !tlist->lock_transactional)
1619
1670
/* Warn about the conversion. */
1620
1671
snprintf(warn_buff, sizeof(warn_buff), ER(ER_WARN_AUTO_CONVERT_LOCK),
1621
1672
tlist->alias ? tlist->alias : tlist->table_name);
1622
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1673
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
1623
1674
ER_WARN_AUTO_CONVERT_LOCK, warn_buff);
1683
1734
For warning/error reporting we need to set the intended lock
1684
method in the TableList object. It will be used later by
1735
method in the TABLE_LIST object. It will be used later by
1685
1736
check_transactional_lock(). The lock method is not set if this
1686
1737
table belongs to a view. We can safely set it to transactional
1687
1738
locking here. Even for non-view tables. This function is not
1701
1752
if (!error || !transactional)
1703
error= tlist->table->file->lock_table(session, lock_type, lock_timeout);
1754
error= tlist->table->file->lock_table(thd, lock_type, lock_timeout);
1704
1755
if (error && transactional && (error != HA_ERR_WRONG_COMMAND))
1705
1756
tlist->table->file->print_error(error, MYF(0));