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.
72
Change to use malloc() ONLY when using LOCK TABLES command or when
72
Change to use my_malloc() ONLY when using LOCK TABLES command or when
73
73
we are forced to use mysql_lock_merge.
75
#include <drizzled/server_includes.h>
76
#include <drizzled/error.h>
77
#include <mysys/hash.h>
78
#include <mysys/thr_lock.h>
79
#include <drizzled/session.h>
80
#include <drizzled/sql_base.h>
81
#include <drizzled/lock.h>
76
#include "mysql_priv.h"
84
81
@defgroup Locking Locking
91
88
#define GET_LOCK_UNLOCK 1
92
89
#define GET_LOCK_STORE_LOCKS 2
94
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table,
96
uint32_t flags, Table **write_locked);
97
static int lock_external(Session *session, Table **table,uint32_t count);
98
static int unlock_external(Session *session, Table **table,uint32_t count);
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);
99
95
static void print_lock_error(int error, const char *);
105
101
mysql_lock_tables()
106
session The current thread.
102
thd The current thread.
107
103
tables An array of pointers to the tables to lock.
108
104
count The number of tables to lock.
110
DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
111
DRIZZLE_LOCK_IGNORE_GLOBAL_READ_ONLY Ignore SET GLOBAL READ_ONLY
112
DRIZZLE_LOCK_IGNORE_FLUSH Ignore a flush tables.
113
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
114
110
or dropped tables by itself,
115
111
mysql_lock_tables() should
116
112
notify upper level and rely
127
123
static int thr_lock_errno_to_mysql[]=
128
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));
132
173
Reset lock type in lock data and free.
148
189
lock request will set its lock type properly.
151
static void reset_lock_data_and_free(DRIZZLE_LOCK **mysql_lock)
192
static void reset_lock_data_and_free(MYSQL_LOCK **mysql_lock)
153
DRIZZLE_LOCK *sql_lock= *mysql_lock;
194
MYSQL_LOCK *sql_lock= *mysql_lock;
154
195
THR_LOCK_DATA **ldata, **ldata_end;
156
197
/* Clear the lock type of all lock data to avoid reusage. */
161
202
/* Reset lock type. */
162
203
(*ldata)->type= TL_UNLOCK;
164
free((unsigned char*) sql_lock);
205
my_free((uchar*) sql_lock, MYF(0));
169
DRIZZLE_LOCK *mysql_lock_tables(Session *session, Table **tables, uint32_t count,
170
uint32_t flags, bool *need_reopen)
210
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
211
uint flags, bool *need_reopen)
172
DRIZZLE_LOCK *sql_lock;
173
Table *write_lock_used;
213
MYSQL_LOCK *sql_lock;
214
TABLE *write_lock_used;
176
217
*need_reopen= false;
219
if (mysql_lock_tables_check(thd, tables, count, flags))
180
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,
181
225
&write_lock_used)))
184
228
if (global_read_lock && write_lock_used &&
185
! (flags & DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK))
229
! (flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK))
188
232
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
189
233
Wait until the lock is gone
191
if (wait_if_global_read_lock(session, 1, 1))
235
if (wait_if_global_read_lock(thd, 1, 1))
193
237
/* Clear the lock type of all lock data to avoid reusage. */
194
238
reset_lock_data_and_free(&sql_lock);
197
if (session->version != refresh_version)
241
if (thd->version != refresh_version)
199
243
/* Clear the lock type of all lock data to avoid reusage. */
200
244
reset_lock_data_and_free(&sql_lock);
219
session->set_proc_info("System lock");
220
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,
221
265
sql_lock->table_count))
223
267
/* Clear the lock type of all lock data to avoid reusage. */
224
268
reset_lock_data_and_free(&sql_lock);
227
session->set_proc_info("Table lock");
271
thd_proc_info(thd, "Table lock");
228
272
/* Copy the lock data array. thr_multi_lock() reorders its contens. */
229
273
memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
230
274
sql_lock->lock_count * sizeof(*sql_lock->locks));
232
276
rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
233
277
sql_lock->lock_count,
234
278
sql_lock->lock_count,
236
280
if (rc > 1) /* a timeout or a deadlock */
238
282
if (sql_lock->table_count)
239
unlock_external(session, sql_lock->table, sql_lock->table_count);
283
VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
240
284
reset_lock_data_and_free(&sql_lock);
241
285
my_error(rc, MYF(0));
244
288
else if (rc == 1) /* aborted */
246
session->some_tables_deleted=1; // Try again
290
thd->some_tables_deleted=1; // Try again
247
291
sql_lock->lock_count= 0; // Locks are already freed
248
292
// Fall through: unlock, reset lock data, free and retry
250
else if (!session->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
294
else if (!thd->some_tables_deleted || (flags & MYSQL_LOCK_IGNORE_FLUSH))
253
297
Thread was killed or lock aborted. Let upper level close all
258
else if (!session->open_tables)
302
else if (!thd->open_tables)
260
304
// Only using temporary tables, no need to unlock
261
session->some_tables_deleted=0;
305
thd->some_tables_deleted=0;
264
session->set_proc_info(0);
308
thd_proc_info(thd, 0);
266
310
/* going to retry, unlock all tables */
267
311
if (sql_lock->lock_count)
268
312
thr_multi_unlock(sql_lock->locks, sql_lock->lock_count);
270
314
if (sql_lock->table_count)
271
unlock_external(session, sql_lock->table, sql_lock->table_count);
315
VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
274
318
If thr_multi_lock fails it resets lock type for tables, which
278
322
reset_lock_data_and_free(&sql_lock);
280
if (flags & DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN)
324
if (flags & MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN)
282
326
*need_reopen= true;
285
if (wait_for_tables(session))
329
if (wait_for_tables(thd))
286
330
break; // Couldn't open tables
288
session->set_proc_info(0);
332
thd_proc_info(thd, 0);
291
session->send_kill_message();
335
thd->send_kill_message();
294
mysql_unlock_tables(session,sql_lock);
338
mysql_unlock_tables(thd,sql_lock);
299
session->set_time_after_lock();
343
thd->set_time_after_lock();
300
344
return (sql_lock);
304
static int lock_external(Session *session, Table **tables, uint32_t count)
348
static int lock_external(THD *thd, TABLE **tables, uint count)
307
351
int lock_type,error;
308
352
for (i=1 ; i <= count ; i++, tables++)
314
358
(*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
315
359
lock_type=F_RDLCK;
317
if ((error=(*tables)->file->ha_external_lock(session,lock_type)))
361
if ((error=(*tables)->file->ha_external_lock(thd,lock_type)))
319
363
print_lock_error(error, (*tables)->file->table_type());
323
(*tables)->file->ha_external_lock(session, F_UNLCK);
367
(*tables)->file->ha_external_lock(thd, F_UNLCK);
324
368
(*tables)->current_lock=F_UNLCK;
338
void mysql_unlock_tables(Session *session, DRIZZLE_LOCK *sql_lock)
382
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
340
384
if (sql_lock->lock_count)
341
385
thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
342
386
if (sql_lock->table_count)
343
unlock_external(session,sql_lock->table,sql_lock->table_count);
344
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));
351
395
This will work even if get_lock_data fails (next unlock will free all)
354
void mysql_unlock_some_tables(Session *session, Table **table,uint32_t count)
398
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count)
356
DRIZZLE_LOCK *sql_lock;
357
Table *write_lock_used;
358
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,
359
403
&write_lock_used)))
360
mysql_unlock_tables(session, sql_lock);
404
mysql_unlock_tables(thd, sql_lock);
390
434
/* Then do the same for the external locks */
391
435
/* Move all write locked tables first */
392
Table **table=sql_lock->table;
436
TABLE **table=sql_lock->table;
393
437
for (i=found=0 ; i < sql_lock->table_count ; i++)
395
439
assert(sql_lock->table[i]->lock_position == i);
396
440
if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
398
std::swap(*table, sql_lock->table[i]);
442
swap_variables(TABLE *, *table, sql_lock->table[i]);
403
447
/* Unlock all read locked tables */
406
unlock_external(session,table,i-found);
450
VOID(unlock_external(thd,table,i-found));
407
451
sql_lock->table_count=found;
409
/* Fix the lock positions in Table */
453
/* Fix the lock positions in TABLE */
410
454
table= sql_lock->table;
412
456
for (i= 0; i < sql_lock->table_count; i++)
415
459
tbl->lock_position= table - sql_lock->table;
416
460
tbl->lock_data_start= found;
417
461
found+= tbl->lock_count;
434
478
unlock_external() we call handler::external_lock(F_UNLCK) only
435
479
if table->current_lock is not F_UNLCK.
437
@param session thread context
481
@param thd thread context
438
482
@param locked list of locked tables
439
483
@param table the table to unlock
440
484
@param always_unlock specify explicitly if the legacy side
441
485
effect is desired.
444
void mysql_lock_remove(Session *session, DRIZZLE_LOCK *locked,Table *table,
488
void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table,
445
489
bool always_unlock)
447
491
if (always_unlock == true)
448
mysql_unlock_some_tables(session, &table, /* table count */ 1);
492
mysql_unlock_some_tables(thd, &table, /* table count */ 1);
452
496
for (i=0; i < locked->table_count; i++)
454
498
if (locked->table[i] == table)
456
uint32_t j, removed_locks, old_tables;
458
uint32_t lock_data_end;
500
uint j, removed_locks, old_tables;
460
504
assert(table->lock_position == i);
462
506
/* Unlock if not yet unlocked */
463
507
if (always_unlock == false)
464
mysql_unlock_some_tables(session, &table, /* table count */ 1);
508
mysql_unlock_some_tables(thd, &table, /* table count */ 1);
466
510
/* Decrement table_count in advance, making below expressions easier */
467
511
old_tables= --locked->table_count;
470
514
removed_locks= table->lock_count;
472
516
/* Move down all table pointers above 'i'. */
473
memmove((locked->table+i), (locked->table+i+1),
474
(old_tables - i) * sizeof(Table*));
517
bmove((char*) (locked->table+i),
518
(char*) (locked->table+i+1),
519
(old_tables - i) * sizeof(TABLE*));
476
521
lock_data_end= table->lock_data_start + table->lock_count;
477
522
/* Move down all lock data pointers above 'table->lock_data_end-1' */
478
memmove((locked->locks + table->lock_data_start),
479
(locked->locks + lock_data_end),
480
(locked->lock_count - lock_data_end) *
481
sizeof(THR_LOCK_DATA*));
523
bmove((char*) (locked->locks + table->lock_data_start),
524
(char*) (locked->locks + lock_data_end),
525
(locked->lock_count - lock_data_end) *
526
sizeof(THR_LOCK_DATA*));
484
529
Fix moved table elements.
507
552
/* Downgrade all locks on a table to new WRITE level from WRITE_ONLY */
509
void mysql_lock_downgrade_write(Session *session, Table *table,
554
void mysql_lock_downgrade_write(THD *thd, TABLE *table,
510
555
thr_lock_type new_lock_type)
512
DRIZZLE_LOCK *locked;
513
Table *write_lock_used;
514
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,
515
560
&write_lock_used)))
517
for (uint32_t i=0; i < locked->lock_count; i++)
562
for (uint i=0; i < locked->lock_count; i++)
518
563
thr_downgrade_write_lock(locked->locks[i], new_lock_type);
519
free((unsigned char*) locked);
564
my_free((uchar*) locked,MYF(0));
524
569
/** Abort all other threads waiting to get lock in table. */
526
void mysql_lock_abort(Session *session, Table *table, bool upgrade_lock)
571
void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock)
528
DRIZZLE_LOCK *locked;
529
Table *write_lock_used;
574
TABLE *write_lock_used;
531
if ((locked= get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
576
if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
532
577
&write_lock_used)))
534
for (uint32_t i=0; i < locked->lock_count; i++)
579
for (uint i=0; i < locked->lock_count; i++)
535
580
thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
536
free((unsigned char*) locked);
581
my_free((uchar*) locked,MYF(0));
551
596
1 Table was locked by at least one other thread
554
bool mysql_lock_abort_for_thread(Session *session, Table *table)
599
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
556
DRIZZLE_LOCK *locked;
557
Table *write_lock_used;
602
TABLE *write_lock_used;
558
603
bool result= false;
560
if ((locked= get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
605
if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
561
606
&write_lock_used)))
563
for (uint32_t i=0; i < locked->lock_count; i++)
608
for (uint i=0; i < locked->lock_count; i++)
565
610
if (thr_abort_locks_for_thread(locked->locks[i]->lock,
566
611
table->in_use->thread_id))
569
free((unsigned char*) locked);
614
my_free((uchar*) locked,MYF(0));
575
DRIZZLE_LOCK *mysql_lock_merge(DRIZZLE_LOCK *a,DRIZZLE_LOCK *b)
620
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
577
DRIZZLE_LOCK *sql_lock;
578
Table **table, **end_table;
622
MYSQL_LOCK *sql_lock;
623
TABLE **table, **end_table;
580
if (!(sql_lock= (DRIZZLE_LOCK*)
581
malloc(sizeof(*sql_lock)+
582
sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+
583
sizeof(Table*)*(a->table_count+b->table_count))))
625
if (!(sql_lock= (MYSQL_LOCK*)
626
my_malloc(sizeof(*sql_lock)+
627
sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+
628
sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME))))
584
629
return(0); // Fatal error
585
630
sql_lock->lock_count=a->lock_count+b->lock_count;
586
631
sql_lock->table_count=a->table_count+b->table_count;
587
632
sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
588
sql_lock->table=(Table**) (sql_lock->locks+sql_lock->lock_count);
633
sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count);
589
634
memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
590
635
memcpy(sql_lock->locks+a->lock_count,b->locks,
591
636
b->lock_count*sizeof(*b->locks));
592
637
memcpy(sql_lock->table,a->table,a->table_count*sizeof(*a->table));
593
638
memcpy(sql_lock->table+a->table_count,b->table,
594
b->table_count*sizeof(*b->table));
639
b->table_count*sizeof(*b->table));
597
642
Now adjust lock_position and lock_data_start for all objects that was
620
665
get_lock_data(). If we allow two opens on temporary tables later,
621
666
both functions should be checked.
623
@param session The current thread.
668
@param thd The current thread.
624
669
@param needle The table to check for duplicate lock.
625
670
@param haystack The list of tables to search for the dup lock.
636
681
!NULL First table from 'haystack' that matches a lock on 'needle'.
639
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)
642
DRIZZLE_LOCK *mylock;
646
691
THR_LOCK_DATA **lock_locks;
647
692
THR_LOCK_DATA **table_lock_data;
648
693
THR_LOCK_DATA **end_data;
726
771
if ((*table)->current_lock != F_UNLCK)
728
773
(*table)->current_lock = F_UNLCK;
729
if ((error=(*table)->file->ha_external_lock(session, F_UNLCK)))
774
if ((error=(*table)->file->ha_external_lock(thd, F_UNLCK)))
731
776
error_code=error;
732
777
print_lock_error(error_code, (*table)->file->table_type());
742
787
Get lock structures from table structs and initialize locks.
744
@param session Thread handler
789
@param thd Thread handler
745
790
@param table_ptr Pointer to tables that should be locks
746
791
@param flags One of:
747
792
- GET_LOCK_UNLOCK : If we should send TL_IGNORE to store lock
748
- GET_LOCK_STORE_LOCKS : Store lock info in Table
793
- GET_LOCK_STORE_LOCKS : Store lock info in TABLE
749
794
@param write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE
752
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table_ptr, uint32_t count,
753
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)
755
uint32_t i,tables,lock_count;
756
DRIZZLE_LOCK *sql_lock;
800
uint i,tables,lock_count;
801
MYSQL_LOCK *sql_lock;
757
802
THR_LOCK_DATA **locks, **locks_buf, **locks_start;
758
Table **to, **table_buf;
803
TABLE **to, **table_buf;
760
805
assert((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS));
762
807
*write_lock_used=0;
763
808
for (i=tables=lock_count=0 ; i < count ; i++)
765
Table *t= table_ptr[i];
810
TABLE *t= table_ptr[i];
767
812
if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE)
777
822
update the table values. So the second part of the array is copied
778
823
from the first part immediately before calling thr_multi_lock().
780
if (!(sql_lock= (DRIZZLE_LOCK*)
781
malloc(sizeof(*sql_lock) +
782
sizeof(THR_LOCK_DATA*) * tables * 2 +
783
sizeof(table_ptr) * lock_count)))
825
if (!(sql_lock= (MYSQL_LOCK*)
826
my_malloc(sizeof(*sql_lock) +
827
sizeof(THR_LOCK_DATA*) * tables * 2 +
828
sizeof(table_ptr) * lock_count,
785
831
locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
786
to= table_buf= sql_lock->table= (Table**) (locks + tables * 2);
832
to= table_buf= sql_lock->table= (TABLE**) (locks + tables * 2);
787
833
sql_lock->table_count=lock_count;
789
835
for (i=0 ; i < count ; i++)
792
838
enum thr_lock_type lock_type;
794
840
if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
856
THR_LOCK_DATA **org_locks = locks;
810
857
locks_start= locks;
811
locks= table->file->store_lock(session, locks,
858
locks= table->file->store_lock(thd, locks,
812
859
(flags & GET_LOCK_UNLOCK) ? TL_IGNORE :
814
861
if (flags & GET_LOCK_STORE_LOCKS)
862
int lock_and_wait_for_table_name(Session *session, TableList *table_list)
912
int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list)
864
914
int lock_retcode;
867
if (wait_if_global_read_lock(session, 0, 1))
917
if (wait_if_global_read_lock(thd, 0, 1))
869
pthread_mutex_lock(&LOCK_open);
870
if ((lock_retcode = lock_table_name(session, table_list, true)) < 0)
919
VOID(pthread_mutex_lock(&LOCK_open));
920
if ((lock_retcode = lock_table_name(thd, table_list, true)) < 0)
872
if (lock_retcode && wait_for_locked_table_names(session, table_list))
922
if (lock_retcode && wait_for_locked_table_names(thd, table_list))
874
unlock_table_name(session, table_list);
924
unlock_table_name(thd, table_list);
880
930
pthread_mutex_unlock(&LOCK_open);
881
start_waiting_global_read_lock(session);
931
start_waiting_global_read_lock(thd);
910
960
> 0 table locked, but someone is using it
913
int lock_table_name(Session *session, TableList *table_list, bool check_in_use)
963
int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use)
916
966
char key[MAX_DBKEY_LENGTH];
917
967
char *db= table_list->db;
919
969
bool found_locked_table= false;
920
970
HASH_SEARCH_STATE state;
922
key_length= create_table_def_key(session, key, table_list, 0);
972
key_length= create_table_def_key(thd, key, table_list, 0);
924
974
if (check_in_use)
926
976
/* Only insert the table if we haven't insert it already */
927
for (table=(Table*) hash_first(&open_cache, (unsigned char*)key,
977
for (table=(TABLE*) hash_first(&open_cache, (uchar*)key,
928
978
key_length, &state);
930
table = (Table*) hash_next(&open_cache,(unsigned char*) key,
980
table = (TABLE*) hash_next(&open_cache,(uchar*) key,
931
981
key_length, &state))
933
983
if (table->reginfo.lock_type < TL_WRITE)
935
if (table->in_use == session)
985
if (table->in_use == thd)
936
986
found_locked_table= true;
940
if (table->in_use == session)
990
if (table->in_use == thd)
942
992
table->s->version= 0; // Ensure no one can use this
943
993
table->locked_by_name= 1;
949
if (session->locked_tables && session->locked_tables->table_count &&
950
! find_temporary_table(session, table_list->db, table_list->table_name))
999
if (thd->locked_tables && thd->locked_tables->table_count &&
1000
! find_temporary_table(thd, table_list->db, table_list->table_name))
952
1002
if (found_locked_table)
953
1003
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_list->alias);
960
if (!(table= table_cache_insert_placeholder(session, key, key_length)))
1010
if (!(table= table_cache_insert_placeholder(thd, key, key_length)))
963
1013
table_list->table=table;
965
1015
/* Return 1 if table is in use */
966
return(test(remove_table_from_cache(session, db, table_list->table_name,
1016
return(test(remove_table_from_cache(thd, db, table_list->table_name,
967
1017
check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG)));
971
void unlock_table_name(Session *session __attribute__((unused)),
972
TableList *table_list)
1021
void unlock_table_name(THD *thd __attribute__((__unused__)),
1022
TABLE_LIST *table_list)
974
1024
if (table_list->table)
976
hash_delete(&open_cache, (unsigned char*) table_list->table);
1026
hash_delete(&open_cache, (uchar*) table_list->table);
977
1027
broadcast_refresh();
982
static bool locked_named_table(Session *session __attribute__((unused)),
983
TableList *table_list)
1032
static bool locked_named_table(THD *thd __attribute__((__unused__)),
1033
TABLE_LIST *table_list)
985
1035
for (; table_list ; table_list=table_list->next_local)
987
Table *table= table_list->table;
1037
TABLE *table= table_list->table;
990
Table *save_next= table->next;
1040
TABLE *save_next= table->next;
993
1043
result= table_is_used(table_list->table, 0);
1003
bool wait_for_locked_table_names(Session *session, TableList *table_list)
1053
bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list)
1007
1057
safe_mutex_assert_owner(&LOCK_open);
1009
while (locked_named_table(session,table_list))
1059
while (locked_named_table(thd,table_list))
1011
if (session->killed)
1016
wait_for_condition(session, &LOCK_open, &COND_refresh);
1066
wait_for_condition(thd, &LOCK_open, &COND_refresh);
1017
1067
pthread_mutex_lock(&LOCK_open);
1019
1069
return(result);
1039
1089
1 Fatal error (end of memory ?)
1042
bool lock_table_names(Session *session, TableList *table_list)
1092
bool lock_table_names(THD *thd, TABLE_LIST *table_list)
1044
1094
bool got_all_locks=1;
1045
TableList *lock_table;
1095
TABLE_LIST *lock_table;
1047
1097
for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
1050
if ((got_lock=lock_table_name(session,lock_table, true)) < 0)
1100
if ((got_lock=lock_table_name(thd,lock_table, true)) < 0)
1051
1101
goto end; // Fatal error
1053
1103
got_all_locks=0; // Someone is using table
1056
1106
/* If some table was in use, wait until we got the lock */
1057
if (!got_all_locks && wait_for_locked_table_names(session, table_list))
1107
if (!got_all_locks && wait_for_locked_table_names(thd, table_list))
1062
unlock_table_names(session, table_list, lock_table);
1112
unlock_table_names(thd, table_list, lock_table);
1068
1118
Unlock all tables in list with a name lock.
1070
@param session Thread handle.
1120
@param thd Thread handle.
1071
1121
@param table_list Names of tables to lock.
1074
This function needs to be protected by LOCK_open. If we're
1124
This function needs to be protected by LOCK_open. If we're
1075
1125
under LOCK TABLES, this function does not work as advertised. Namely,
1076
1126
it does not exclude other threads from using this table and does not
1077
1127
put an exclusive name lock on this table into the table cache.
1083
1133
@retval FALSE Name lock successfully acquired.
1086
bool lock_table_names_exclusively(Session *session, TableList *table_list)
1136
bool lock_table_names_exclusively(THD *thd, TABLE_LIST *table_list)
1088
if (lock_table_names(session, table_list))
1138
if (lock_table_names(thd, table_list))
1092
1142
Upgrade the table name locks from semi-exclusive to exclusive locks.
1094
for (TableList *table= table_list; table; table= table->next_global)
1144
for (TABLE_LIST *table= table_list; table; table= table->next_global)
1096
1146
if (table->table)
1097
1147
table->table->open_placeholder= 1;
1118
is_table_name_exclusively_locked_by_this_thread(Session *session,
1119
TableList *table_list)
1168
is_table_name_exclusively_locked_by_this_thread(THD *thd,
1169
TABLE_LIST *table_list)
1121
1171
char key[MAX_DBKEY_LENGTH];
1122
uint32_t key_length;
1124
key_length= create_table_def_key(session, key, table_list, 0);
1126
return is_table_name_exclusively_locked_by_this_thread(session, (unsigned char *)key,
1174
key_length= create_table_def_key(thd, key, table_list, 0);
1176
return is_table_name_exclusively_locked_by_this_thread(thd, (uchar *)key,
1145
is_table_name_exclusively_locked_by_this_thread(Session *session, unsigned char *key,
1195
is_table_name_exclusively_locked_by_this_thread(THD *thd, uchar *key,
1146
1196
int key_length)
1148
1198
HASH_SEARCH_STATE state;
1151
for (table= (Table*) hash_first(&open_cache, key,
1201
for (table= (TABLE*) hash_first(&open_cache, key,
1152
1202
key_length, &state);
1154
table= (Table*) hash_next(&open_cache, key,
1204
table= (TABLE*) hash_next(&open_cache, key,
1155
1205
key_length, &state))
1157
if (table->in_use == session &&
1207
if (table->in_use == thd &&
1158
1208
table->open_placeholder == 1 &&
1159
1209
table->s->version == 0)
1187
1237
1 Fatal error (end of memory ?)
1190
void unlock_table_names(Session *session, TableList *table_list,
1191
TableList *last_table)
1240
void unlock_table_names(THD *thd, TABLE_LIST *table_list,
1241
TABLE_LIST *last_table)
1193
for (TableList *table= table_list;
1243
for (TABLE_LIST *table= table_list;
1194
1244
table != last_table;
1195
1245
table= table->next_local)
1196
unlock_table_name(session,table);
1246
unlock_table_name(thd,table);
1197
1247
broadcast_refresh();
1290
1340
If we have merged 1) and 3) into 1), we would have had this deadlock:
1291
1341
imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
1293
session1: SELECT * FROM t FOR UPDATE;
1294
session2: UPDATE t SET a=1; # blocked by row-level locks of session1
1295
session3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
1296
table instance of session2
1297
session1: COMMIT; # blocked by session3.
1298
session1 blocks session2 which blocks session3 which blocks session1: deadlock.
1343
thd1: SELECT * FROM t FOR UPDATE;
1344
thd2: UPDATE t SET a=1; # blocked by row-level locks of thd1
1345
thd3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
1346
table instance of thd2
1347
thd1: COMMIT; # blocked by thd3.
1348
thd1 blocks thd2 which blocks thd3 which blocks thd1: deadlock.
1300
1350
Note that we need to support that one thread does
1301
1351
FLUSH TABLES WITH READ LOCK; and then COMMIT;
1306
1356
****************************************************************************/
1308
volatile uint32_t global_read_lock=0;
1309
volatile uint32_t global_read_lock_blocks_commit=0;
1310
static volatile uint32_t protect_against_global_read_lock=0;
1311
static volatile uint32_t waiting_for_read_lock=0;
1358
volatile uint global_read_lock=0;
1359
volatile uint global_read_lock_blocks_commit=0;
1360
static volatile uint protect_against_global_read_lock=0;
1361
static volatile uint waiting_for_read_lock=0;
1313
1363
#define GOT_GLOBAL_READ_LOCK 1
1314
1364
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
1316
bool lock_global_read_lock(Session *session)
1366
bool lock_global_read_lock(THD *thd)
1318
if (!session->global_read_lock)
1368
if (!thd->global_read_lock)
1320
1370
const char *old_message;
1321
1371
(void) pthread_mutex_lock(&LOCK_global_read_lock);
1322
old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1372
old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1323
1373
"Waiting to get readlock");
1325
1375
waiting_for_read_lock++;
1326
while (protect_against_global_read_lock && !session->killed)
1376
while (protect_against_global_read_lock && !thd->killed)
1327
1377
pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1328
1378
waiting_for_read_lock--;
1329
if (session->killed)
1331
session->exit_cond(old_message);
1381
thd->exit_cond(old_message);
1334
session->global_read_lock= GOT_GLOBAL_READ_LOCK;
1384
thd->global_read_lock= GOT_GLOBAL_READ_LOCK;
1335
1385
global_read_lock++;
1336
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1386
thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1339
1389
We DON'T set global_read_lock_blocks_commit now, it will be set after
1350
void unlock_global_read_lock(Session *session)
1400
void unlock_global_read_lock(THD *thd)
1354
1404
pthread_mutex_lock(&LOCK_global_read_lock);
1355
1405
tmp= --global_read_lock;
1356
if (session->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1406
if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1357
1407
--global_read_lock_blocks_commit;
1358
1408
pthread_mutex_unlock(&LOCK_global_read_lock);
1359
1409
/* Send the signal outside the mutex to avoid a context switch */
1400
1450
return(is_not_commit);
1402
old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1452
old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1403
1453
"Waiting for release of readlock");
1404
while (must_wait && ! session->killed &&
1405
(!abort_on_refresh || session->version == refresh_version))
1454
while (must_wait && ! thd->killed &&
1455
(!abort_on_refresh || thd->version == refresh_version))
1407
1457
(void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1409
if (session->killed)
1412
1462
if (!abort_on_refresh && !result)
1416
1466
and if old_message is set
1418
1468
if (unlikely(need_exit_cond))
1419
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1469
thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1421
1471
pthread_mutex_unlock(&LOCK_global_read_lock);
1422
1472
return(result);
1426
void start_waiting_global_read_lock(Session *session)
1476
void start_waiting_global_read_lock(THD *thd)
1429
if (unlikely(session->global_read_lock))
1479
if (unlikely(thd->global_read_lock))
1431
1481
(void) pthread_mutex_lock(&LOCK_global_read_lock);
1432
1482
tmp= (!--protect_against_global_read_lock &&
1446
1496
If we didn't succeed lock_global_read_lock(), or if we already suceeded
1447
1497
make_global_read_lock_block_commit(), do nothing.
1449
if (session->global_read_lock != GOT_GLOBAL_READ_LOCK)
1499
if (thd->global_read_lock != GOT_GLOBAL_READ_LOCK)
1451
1501
pthread_mutex_lock(&LOCK_global_read_lock);
1452
1502
/* increment this BEFORE waiting on cond (otherwise race cond) */
1453
1503
global_read_lock_blocks_commit++;
1454
1504
/* For testing we set up some blocking, to see if we can be killed */
1455
1505
protect_against_global_read_lock++;
1456
old_message= session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1506
old_message= thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1457
1507
"Waiting for all running commits to finish");
1458
while (protect_against_global_read_lock && !session->killed)
1508
while (protect_against_global_read_lock && !thd->killed)
1459
1509
pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1460
1510
protect_against_global_read_lock--;
1461
if ((error= test(session->killed)))
1511
if ((error= test(thd->killed)))
1462
1512
global_read_lock_blocks_commit--; // undo what we did
1464
session->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1465
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1514
thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1515
thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1511
1561
-1 Error: no recovery possible.
1514
int try_transactional_lock(Session *session, TableList *table_list)
1564
int try_transactional_lock(THD *thd, TABLE_LIST *table_list)
1516
uint32_t dummy_counter;
1520
1570
/* Need to open the tables to be able to access engine methods. */
1521
if (open_tables(session, &table_list, &dummy_counter, 0))
1571
if (open_tables(thd, &table_list, &dummy_counter, 0))
1523
1573
/* purecov: begin tested */
1528
1578
/* Required by InnoDB. */
1529
session->in_lock_tables= true;
1579
thd->in_lock_tables= true;
1531
if ((error= set_handler_table_locks(session, table_list, true)))
1581
if ((error= set_handler_table_locks(thd, table_list, true)))
1534
1584
Not all transactional locks could be taken. If the error was
1553
1603
/* We need to explicitly commit if autocommit mode is active. */
1554
(void) ha_autocommit_or_rollback(session, 0);
1604
(void) ha_autocommit_or_rollback(thd, 0);
1555
1605
/* Close the tables. The locks (if taken) persist in the storage engines. */
1556
close_tables_for_reopen(session, &table_list);
1557
session->in_lock_tables= false;
1606
close_tables_for_reopen(thd, &table_list);
1607
thd->in_lock_tables= false;
1558
1608
return(result);
1584
1634
-1 Error: Lock conversion is prohibited.
1587
int check_transactional_lock(Session *session, TableList *table_list)
1637
int check_transactional_lock(THD *thd, TABLE_LIST *table_list)
1591
char warn_buff[DRIZZLE_ERRMSG_SIZE];
1641
char warn_buff[MYSQL_ERRMSG_SIZE];
1593
1643
for (tlist= table_list; tlist; tlist= tlist->next_global)
1597
1647
Unfortunately we cannot use tlist->placeholder() here. This method
1598
1648
returns TRUE if the table is not open, which is always the case
1599
here. Whenever the definition of TableList::placeholder() is
1649
here. Whenever the definition of TABLE_LIST::placeholder() is
1600
1650
changed, probably this condition needs to be changed too.
1602
1652
if (tlist->derived || tlist->schema_table || !tlist->lock_transactional)
1624
1674
/* Warn about the conversion. */
1625
1675
snprintf(warn_buff, sizeof(warn_buff), ER(ER_WARN_AUTO_CONVERT_LOCK),
1626
1676
tlist->alias ? tlist->alias : tlist->table_name);
1627
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1677
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
1628
1678
ER_WARN_AUTO_CONVERT_LOCK, warn_buff);
1688
1738
For warning/error reporting we need to set the intended lock
1689
method in the TableList object. It will be used later by
1739
method in the TABLE_LIST object. It will be used later by
1690
1740
check_transactional_lock(). The lock method is not set if this
1691
1741
table belongs to a view. We can safely set it to transactional
1692
1742
locking here. Even for non-view tables. This function is not
1706
1756
if (!error || !transactional)
1708
error= tlist->table->file->lock_table(session, lock_type, lock_timeout);
1758
error= tlist->table->file->lock_table(thd, lock_type, lock_timeout);
1709
1759
if (error && transactional && (error != HA_ERR_WRONG_COMMAND))
1710
1760
tlist->table->file->print_error(error, MYF(0));