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
- 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(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,uint count,
90
uint flags, TABLE **write_locked);
91
static int lock_external(THD *thd, TABLE **table,uint count);
92
static int unlock_external(THD *thd, TABLE **table,uint count);
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,
155
160
/* Reset lock type. */
156
161
(*ldata)->type= TL_UNLOCK;
158
my_free((uchar*) sql_lock, MYF(0));
163
free((unsigned char*) sql_lock);
163
DRIZZLE_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
164
uint flags, bool *need_reopen)
168
DRIZZLE_LOCK *mysql_lock_tables(Session *session, Table **tables, uint32_t count,
169
uint32_t flags, bool *need_reopen)
166
171
DRIZZLE_LOCK *sql_lock;
167
TABLE *write_lock_used;
172
Table *write_lock_used;
170
175
*need_reopen= false;
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
VOID(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
VOID(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, uint count)
289
static int lock_external(Session *session, Table **tables, uint32_t count)
301
292
int lock_type,error;
302
293
for (i=1 ; i <= count ; i++, tables++)
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
VOID(unlock_external(thd,sql_lock->table,sql_lock->table_count));
338
my_free((uchar*) sql_lock,MYF(0));
328
unlock_external(session,sql_lock->table,sql_lock->table_count);
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,uint count)
339
void mysql_unlock_some_tables(Session *session, Table **table,uint32_t count)
350
341
DRIZZLE_LOCK *sql_lock;
351
TABLE *write_lock_used;
352
if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK,
342
Table *write_lock_used;
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);
359
350
unlock all tables locked for read.
362
void mysql_unlock_read_tables(THD *thd, DRIZZLE_LOCK *sql_lock)
353
void mysql_unlock_read_tables(Session *session, DRIZZLE_LOCK *sql_lock)
366
357
/* Move all write locks first */
367
358
THR_LOCK_DATA **lock=sql_lock->locks;
384
375
/* Then do the same for the external locks */
385
376
/* Move all write locked tables first */
386
TABLE **table=sql_lock->table;
377
Table **table=sql_lock->table;
387
378
for (i=found=0 ; i < sql_lock->table_count ; i++)
389
380
assert(sql_lock->table[i]->lock_position == i);
390
if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
381
if ((uint32_t) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
392
swap_variables(TABLE *, *table, sql_lock->table[i]);
383
std::swap(*table, sql_lock->table[i]);
397
388
/* Unlock all read locked tables */
400
VOID(unlock_external(thd,table,i-found));
391
unlock_external(session,table,i-found);
401
392
sql_lock->table_count=found;
403
/* Fix the lock positions in TABLE */
394
/* Fix the lock positions in Table */
404
395
table= sql_lock->table;
406
397
for (i= 0; i < sql_lock->table_count; i++)
409
400
tbl->lock_position= table - sql_lock->table;
410
401
tbl->lock_data_start= found;
411
402
found+= tbl->lock_count;
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);
446
437
for (i=0; i < locked->table_count; i++)
448
439
if (locked->table[i] == table)
450
uint j, removed_locks, old_tables;
441
uint32_t j, removed_locks, old_tables;
443
uint32_t lock_data_end;
454
445
assert(table->lock_position == 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
TABLE *write_lock_used;
508
if ((locked = get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
498
Table *write_lock_used;
499
if ((locked = get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
509
500
&write_lock_used)))
511
for (uint i=0; i < locked->lock_count; i++)
502
for (uint32_t i=0; i < locked->lock_count; i++)
512
503
thr_downgrade_write_lock(locked->locks[i], new_lock_type);
513
my_free((uchar*) locked,MYF(0));
504
free((unsigned char*) locked);
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
TABLE *write_lock_used;
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
for (uint i=0; i < locked->lock_count; i++)
519
for (uint32_t i=0; i < locked->lock_count; i++)
529
520
thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
530
my_free((uchar*) locked,MYF(0));
521
free((unsigned char*) locked);
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
TABLE *write_lock_used;
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
for (uint i=0; i < locked->lock_count; i++)
548
for (uint32_t i=0; i < locked->lock_count; i++)
559
550
if (thr_abort_locks_for_thread(locked->locks[i]->lock,
560
551
table->in_use->thread_id))
563
my_free((uchar*) locked,MYF(0));
554
free((unsigned char*) locked);
569
560
DRIZZLE_LOCK *mysql_lock_merge(DRIZZLE_LOCK *a,DRIZZLE_LOCK *b)
571
562
DRIZZLE_LOCK *sql_lock;
572
TABLE **table, **end_table;
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;
581
572
sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
582
sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count);
573
sql_lock->table=(Table**) (sql_lock->locks+sql_lock->lock_count);
583
574
memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
584
575
memcpy(sql_lock->locks+a->lock_count,b->locks,
585
576
b->lock_count*sizeof(*b->locks));
603
594
/* Delete old, not needed locks */
604
my_free((uchar*) a,MYF(0));
605
my_free((uchar*) b,MYF(0));
595
free((unsigned char*) a);
596
free((unsigned char*) b);
606
597
return(sql_lock);
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.
630
621
!NULL First table from 'haystack' that matches a lock on 'needle'.
633
TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
634
TABLE_LIST *haystack)
624
TableList *mysql_lock_have_duplicate(Session *session, TableList *needle,
636
627
DRIZZLE_LOCK *mylock;
640
631
THR_LOCK_DATA **lock_locks;
641
632
THR_LOCK_DATA **table_lock_data;
642
633
THR_LOCK_DATA **end_data;
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());
736
727
Get lock structures from table structs and initialize locks.
738
@param thd Thread handler
729
@param session Thread handler
739
730
@param table_ptr Pointer to tables that should be locks
740
731
@param flags One of:
741
732
- GET_LOCK_UNLOCK : If we should send TL_IGNORE to store lock
742
- GET_LOCK_STORE_LOCKS : Store lock info in TABLE
733
- GET_LOCK_STORE_LOCKS : Store lock info in Table
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, uint count,
747
uint flags, TABLE **write_lock_used)
737
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table_ptr, uint32_t count,
738
uint32_t flags, Table **write_lock_used)
749
uint i,tables,lock_count;
740
uint32_t i,tables,lock_count;
750
741
DRIZZLE_LOCK *sql_lock;
751
742
THR_LOCK_DATA **locks, **locks_buf, **locks_start;
752
TABLE **to, **table_buf;
743
Table **to, **table_buf;
754
745
assert((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS));
756
747
*write_lock_used=0;
757
748
for (i=tables=lock_count=0 ; i < count ; i++)
759
TABLE *t= table_ptr[i];
750
Table *t= table_ptr[i];
761
752
if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE)
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
to= table_buf= sql_lock->table= (TABLE**) (locks + tables * 2);
771
to= table_buf= sql_lock->table= (Table**) (locks + tables * 2);
782
772
sql_lock->table_count=lock_count;
784
774
for (i=0 ; i < count ; i++)
787
777
enum thr_lock_type lock_type;
789
779
if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
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)
811
table->lock_position= (uint) (to - table_buf);
812
table->lock_data_start= (uint) (locks_start - locks_buf);
813
table->lock_count= (uint) (locks - locks_start);
801
table->lock_position= (uint32_t) (to - table_buf);
802
table->lock_data_start= (uint32_t) (locks_start - locks_buf);
803
table->lock_count= (uint32_t) (locks - locks_start);
857
int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *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
VOID(pthread_mutex_lock(&LOCK_open));
865
if ((lock_retcode = lock_table_name(thd, table_list, true)) < 0)
854
pthread_mutex_lock(&LOCK_open);
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);
905
895
> 0 table locked, but someone is using it
908
int lock_table_name(THD *thd, TABLE_LIST *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];
912
902
char *db= table_list->db;
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)
921
911
/* Only insert the table if we haven't insert it already */
922
for (table=(TABLE*) hash_first(&open_cache, (uchar*)key,
912
for (table=(Table*) hash_first(&open_cache, (unsigned char*)key,
923
913
key_length, &state);
925
table = (TABLE*) hash_next(&open_cache,(uchar*) key,
915
table = (Table*) hash_next(&open_cache,(unsigned char*) key,
926
916
key_length, &state))
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)),
967
TABLE_LIST *table_list)
956
void unlock_table_name(Session *,
957
TableList *table_list)
969
959
if (table_list->table)
971
hash_delete(&open_cache, (uchar*) table_list->table);
961
hash_delete(&open_cache, (unsigned char*) table_list->table);
972
962
broadcast_refresh();
977
static bool locked_named_table(THD *thd __attribute__((unused)),
978
TABLE_LIST *table_list)
967
static bool locked_named_table(Session *,
968
TableList *table_list)
980
970
for (; table_list ; table_list=table_list->next_local)
982
TABLE *table= table_list->table;
972
Table *table= table_list->table;
985
TABLE *save_next= table->next;
975
Table *save_next= table->next;
988
978
result= table_is_used(table_list->table, 0);
998
bool wait_for_locked_table_names(THD *thd, TABLE_LIST *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);
1034
1024
1 Fatal error (end of memory ?)
1037
bool lock_table_names(THD *thd, TABLE_LIST *table_list)
1027
bool lock_table_names(Session *session, TableList *table_list)
1039
1029
bool got_all_locks=1;
1040
TABLE_LIST *lock_table;
1030
TableList *lock_table;
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, TABLE_LIST *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))
1087
1077
Upgrade the table name locks from semi-exclusive to exclusive locks.
1089
for (TABLE_LIST *table= table_list; table; table= table->next_global)
1079
for (TableList *table= table_list; table; table= table->next_global)
1091
1081
if (table->table)
1092
1082
table->table->open_placeholder= 1;
1113
is_table_name_exclusively_locked_by_this_thread(THD *thd,
1114
TABLE_LIST *table_list)
1103
is_table_name_exclusively_locked_by_this_thread(Session *session,
1104
TableList *table_list)
1116
1106
char key[MAX_DBKEY_LENGTH];
1119
key_length= create_table_def_key(thd, key, table_list, 0);
1121
return is_table_name_exclusively_locked_by_this_thread(thd, (uchar *)key,
1107
uint32_t key_length;
1109
key_length= create_table_def_key(session, key, table_list, 0);
1111
return is_table_name_exclusively_locked_by_this_thread(session, (unsigned char *)key,
1140
is_table_name_exclusively_locked_by_this_thread(THD *thd, uchar *key,
1130
is_table_name_exclusively_locked_by_this_thread(Session *session, unsigned char *key,
1141
1131
int key_length)
1143
1133
HASH_SEARCH_STATE state;
1146
for (table= (TABLE*) hash_first(&open_cache, key,
1136
for (table= (Table*) hash_first(&open_cache, key,
1147
1137
key_length, &state);
1149
table= (TABLE*) hash_next(&open_cache, key,
1139
table= (Table*) hash_next(&open_cache, key,
1150
1140
key_length, &state))
1152
if (table->in_use == thd &&
1142
if (table->in_use == session &&
1153
1143
table->open_placeholder == 1 &&
1154
1144
table->s->version == 0)
1182
1172
1 Fatal error (end of memory ?)
1185
void unlock_table_names(THD *thd, TABLE_LIST *table_list,
1186
TABLE_LIST *last_table)
1175
void unlock_table_names(Session *session, TableList *table_list,
1176
TableList *last_table)
1188
for (TABLE_LIST *table= table_list;
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;
1301
1291
****************************************************************************/
1303
volatile uint global_read_lock=0;
1304
volatile uint global_read_lock_blocks_commit=0;
1305
static volatile uint protect_against_global_read_lock=0;
1306
static volatile uint waiting_for_read_lock=0;
1293
volatile uint32_t global_read_lock=0;
1294
volatile uint32_t global_read_lock_blocks_commit=0;
1295
static volatile uint32_t protect_against_global_read_lock=0;
1296
static volatile uint32_t waiting_for_read_lock=0;
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, TABLE_LIST *table_list)
1496
int try_transactional_lock(Session *session, TableList *table_list)
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);
1579
1566
-1 Error: Lock conversion is prohibited.
1582
int check_transactional_lock(THD *thd, TABLE_LIST *table_list)
1569
int check_transactional_lock(Session *, TableList *table_list)
1586
char warn_buff[DRIZZLE_ERRMSG_SIZE];
1588
1574
for (tlist= table_list; tlist; tlist= tlist->next_global)
1592
1578
Unfortunately we cannot use tlist->placeholder() here. This method
1593
1579
returns TRUE if the table is not open, which is always the case
1594
here. Whenever the definition of TABLE_LIST::placeholder() is
1580
here. Whenever the definition of TableList::placeholder() is
1595
1581
changed, probably this condition needs to be changed too.
1597
1583
if (tlist->derived || tlist->schema_table || !tlist->lock_transactional)
1610
/* We must not convert the lock method within an active transaction. */
1611
if (thd->active_transaction())
1613
my_error(ER_NO_AUTO_CONVERT_LOCK_TRANSACTION, MYF(0),
1614
tlist->alias ? tlist->alias : tlist->table_name);
1619
/* Warn about the conversion. */
1620
snprintf(warn_buff, sizeof(warn_buff), ER(ER_WARN_AUTO_CONVERT_LOCK),
1621
tlist->alias ? tlist->alias : tlist->table_name);
1622
push_warning(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1623
ER_WARN_AUTO_CONVERT_LOCK, warn_buff);
1626
1598
return(result);
1641
1613
!= 0 Error code from handler::lock_table().
1644
int set_handler_table_locks(THD *thd, TABLE_LIST *table_list,
1616
int set_handler_table_locks(Session *session, TableList *table_list,
1645
1617
bool transactional)
1650
1622
for (tlist= table_list; tlist; tlist= tlist->next_global)
1683
1655
For warning/error reporting we need to set the intended lock
1684
method in the TABLE_LIST object. It will be used later by
1656
method in the TableList object. It will be used later by
1685
1657
check_transactional_lock(). The lock method is not set if this
1686
1658
table belongs to a view. We can safely set it to transactional
1687
1659
locking here. Even for non-view tables. This function is not
1701
1673
if (!error || !transactional)
1703
error= tlist->table->file->lock_table(thd, lock_type, lock_timeout);
1675
error= tlist->table->file->lock_table(session, lock_type, lock_timeout);
1704
1676
if (error && transactional && (error != HA_ERR_WRONG_COMMAND))
1705
1677
tlist->table->file->print_error(error, MYF(0));