28
28
When not using LOCK TABLES:
30
- For each SQL statement mysql_lock_tables() is called for all involved
30
- For each SQL statement lockTables() is called for all involved
32
- mysql_lock_tables() will call
32
- lockTables() will call
33
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
- When statement is done, we call mysql_unlock_tables().
36
- When statement is done, we call unlockTables().
37
37
This will call DrizzleLock::unlock() followed by
38
38
table_handler->external_lock(session, F_UNLCK) for each table.
40
- Note that mysql_unlock_tables() may be called several times as
40
- Note that unlockTables() 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.
108
static DrizzleLock *get_lock_data(Session *session, Table **table,
110
bool should_lock, Table **write_locked);
111
static int lock_external(Session *session, Table **table,uint32_t count);
112
static int unlock_external(Session *session, Table **table,uint32_t count);
113
108
static void print_lock_error(int error, const char *);
120
session The current thread.
121
115
tables An array of pointers to the tables to lock.
122
116
count The number of tables to lock.
201
194
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
202
195
Wait until the lock is gone
204
if (wait_if_global_read_lock(session, 1, 1))
197
if (wait_if_global_read_lock(1, 1))
206
199
/* Clear the lock type of all lock data to avoid reusage. */
207
200
reset_lock_data_and_free(&sql_lock);
210
if (session->version != refresh_version)
203
if (version != refresh_version)
212
205
/* Clear the lock type of all lock data to avoid reusage. */
213
206
reset_lock_data_and_free(&sql_lock);
237
230
for_each(involved_engines.begin(),
238
231
involved_engines.end(),
239
bind2nd(mem_fun(&plugin::StorageEngine::startStatement), session));
232
bind2nd(mem_fun(&plugin::StorageEngine::startStatement), this));
242
session->set_proc_info("External lock");
235
set_proc_info("External lock");
244
237
* Here, the call to lock_external() informs the
245
238
* all engines for all tables used in this statement
246
239
* of the type of lock that Drizzle intends to take on a
247
240
* specific table.
249
if (sql_lock->table_count && lock_external(session, sql_lock->getTable(),
250
sql_lock->table_count))
242
if (sql_lock->table_count && lock_external(sql_lock->getTable(), sql_lock->table_count))
252
244
/* Clear the lock type of all lock data to avoid reusage. */
253
245
reset_lock_data_and_free(&sql_lock);
256
session->set_proc_info("Table lock");
248
set_proc_info("Table lock");
257
249
/* Copy the lock data array. thr_multi_lock() reorders its contens. */
258
250
memcpy(sql_lock->getLocks() + sql_lock->lock_count,
259
251
sql_lock->getLocks(),
262
254
rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->getLocks() +
263
255
sql_lock->lock_count,
264
256
sql_lock->lock_count,
266
258
if (rc > 1) /* a timeout or a deadlock */
268
260
if (sql_lock->table_count)
269
unlock_external(session, sql_lock->getTable(), sql_lock->table_count);
261
unlock_external(sql_lock->getTable(), sql_lock->table_count);
270
262
reset_lock_data_and_free(&sql_lock);
271
263
my_error(rc, MYF(0));
274
266
else if (rc == 1) /* aborted */
276
session->some_tables_deleted=1; // Try again
268
some_tables_deleted= 1; // Try again
277
269
sql_lock->lock_count= 0; // Locks are already freed
278
270
// Fall through: unlock, reset lock data, free and retry
280
else if (!session->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
272
else if (not some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
283
275
Thread was killed or lock aborted. Let upper level close all
288
else if (!session->open_tables)
280
else if (not open_tables)
290
282
// Only using temporary tables, no need to unlock
291
session->some_tables_deleted= 0;
283
some_tables_deleted= 0;
294
session->set_proc_info(0);
296
288
/* going to retry, unlock all tables */
297
289
if (sql_lock->lock_count)
298
290
sql_lock->unlock(sql_lock->lock_count);
300
292
if (sql_lock->table_count)
301
unlock_external(session, sql_lock->getTable(), sql_lock->table_count);
293
unlock_external(sql_lock->getTable(), sql_lock->table_count);
304
296
If thr_multi_lock fails it resets lock type for tables, which
314
306
for_each(involved_engines.begin(),
315
307
involved_engines.end(),
316
bind2nd(mem_fun(&plugin::StorageEngine::endStatement), session));
308
bind2nd(mem_fun(&plugin::StorageEngine::endStatement), this));
318
310
if (flags & DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN)
320
312
*need_reopen= true;
323
if (wait_for_tables(session))
316
if (wait_for_tables(this))
324
318
break; // Couldn't open tables
326
session->set_proc_info(0);
329
session->send_kill_message();
332
mysql_unlock_tables(session,sql_lock);
328
unlockTables(sql_lock);
336
session->set_time_after_lock();
332
set_time_after_lock();
337
333
return (sql_lock);
341
static int lock_external(Session *session, Table **tables, uint32_t count)
337
int Session::lock_external(Table **tables, uint32_t count)
343
339
int lock_type,error;
344
340
for (uint32_t i= 1 ; i <= count ; i++, tables++)
350
346
(*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
351
347
lock_type=F_RDLCK;
353
if ((error=(*tables)->cursor->ha_external_lock(session,lock_type)))
349
if ((error=(*tables)->cursor->ha_external_lock(this,lock_type)))
355
351
print_lock_error(error, (*tables)->cursor->getEngine()->getName().c_str());
359
(*tables)->cursor->ha_external_lock(session, F_UNLCK);
355
(*tables)->cursor->ha_external_lock(this, F_UNLCK);
360
356
(*tables)->current_lock=F_UNLCK;
374
void mysql_unlock_tables(Session *session, DrizzleLock *sql_lock)
370
void Session::unlockTables(DrizzleLock *sql_lock)
376
372
if (sql_lock->lock_count)
377
373
sql_lock->unlock(sql_lock->lock_count);
378
374
if (sql_lock->table_count)
379
unlock_external(session, sql_lock->getTable(), sql_lock->table_count);
375
unlock_external(sql_lock->getTable(), sql_lock->table_count);
384
Unlock some of the tables locked by mysql_lock_tables.
380
Unlock some of the tables locked by lockTables.
386
382
This will work even if get_lock_data fails (next unlock will free all)
389
void mysql_unlock_some_tables(Session *session, Table **table, uint32_t count)
385
void Session::unlockSomeTables(Table **table, uint32_t count)
391
387
DrizzleLock *sql_lock;
392
388
Table *write_lock_used;
393
if ((sql_lock= get_lock_data(session, table, count, false,
389
if ((sql_lock= get_lock_data(table, count, false,
394
390
&write_lock_used)))
395
mysql_unlock_tables(session, sql_lock);
391
unlockTables(sql_lock);
400
396
unlock all tables locked for read.
403
void mysql_unlock_read_tables(Session *session, DrizzleLock *sql_lock)
399
void Session::unlockReadTables(DrizzleLock *sql_lock)
405
401
uint32_t i,found;
407
403
/* Move all write locks first */
408
THR_LOCK_DATA **lock=sql_lock->getLocks();
404
THR_LOCK_DATA **lock_local= sql_lock->getLocks();
409
405
for (i=found=0 ; i < sql_lock->lock_count ; i++)
411
407
if (sql_lock->getLocks()[i]->type >= TL_WRITE_ALLOW_READ)
413
std::swap(*lock, sql_lock->getLocks()[i]);
409
std::swap(*lock_local, sql_lock->getLocks()[i]);
476
471
effect is desired.
479
void mysql_lock_remove(Session *session, Table *table)
474
void Session::removeLock(Table *table)
481
mysql_unlock_some_tables(session, &table, /* table count */ 1);
476
unlockSomeTables(&table, /* table count */ 1);
485
480
/** Abort all other threads waiting to get lock in table. */
487
void mysql_lock_abort(Session *session, Table *table)
482
void Session::abortLock(Table *table)
489
484
DrizzleLock *locked;
490
485
Table *write_lock_used;
492
if ((locked= get_lock_data(session, &table, 1, false,
487
if ((locked= get_lock_data(&table, 1, false,
493
488
&write_lock_used)))
495
490
for (uint32_t x= 0; x < locked->lock_count; x++)
511
506
1 Table was locked by at least one other thread
514
bool mysql_lock_abort_for_thread(Session *session, Table *table)
509
bool Session::abortLockForThread(Table *table)
516
511
DrizzleLock *locked;
517
512
Table *write_lock_used;
518
513
bool result= false;
520
if ((locked= get_lock_data(session, &table, 1, false,
515
if ((locked= get_lock_data(&table, 1, false,
521
516
&write_lock_used)))
523
518
for (uint32_t i= 0; i < locked->lock_count; i++)
718
711
table_list->table= reinterpret_cast<Table *>(table);
720
713
/* Return 1 if table is in use */
721
return(test(table::Cache::singleton().removeTable(session, identifier, RTFC_NO_FLAG)));
714
return(test(table::Cache::singleton().removeTable(this, identifier, RTFC_NO_FLAG)));
725
void unlock_table_name(TableList *table_list)
718
void TableList::unlock_table_name()
727
if (table_list->table)
729
table::remove_table(static_cast<table::Concurrent *>(table_list->table));
722
table::remove_table(static_cast<table::Concurrent *>(table));
723
locking::broadcast_refresh();
788
781
1 Fatal error (end of memory ?)
791
static bool lock_table_names(Session *session, TableList *table_list)
784
bool Session::lock_table_names(TableList *table_list)
793
bool got_all_locks=1;
786
bool got_all_locks= true;
794
787
TableList *lock_table;
796
789
for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
799
if ((got_lock= lock_table_name(session, lock_table)) < 0)
800
goto end; // Fatal error
792
if ((got_lock= lock_table_name(lock_table)) < 0)
794
table_list->unlock_table_names(table_list);
795
return true; // Fatal error
802
got_all_locks=0; // Someone is using table
799
got_all_locks= false; // Someone is using table
805
802
/* If some table was in use, wait until we got the lock */
806
if (!got_all_locks && wait_for_locked_table_names(session, table_list))
803
if (not got_all_locks && wait_for_locked_table_names(table_list))
805
table_list->unlock_table_names(table_list);
811
unlock_table_names(table_list, lock_table);
818
815
Unlock all tables in list with a name lock.
820
@param session Thread handle.
821
817
@param table_list Names of tables to lock.
872
868
1 Fatal error (end of memory ?)
875
void unlock_table_names(TableList *table_list, TableList *last_table)
871
void TableList::unlock_table_names(TableList *last_table)
877
for (TableList *table= table_list;
879
table= table->next_local)
880
unlock_table_name(table);
873
for (TableList *table_iter= this;
874
table_iter != last_table;
875
table_iter= table_iter->next_local)
877
table_iter->unlock_table_name();
880
locking::broadcast_refresh();
991
990
static volatile uint32_t protect_against_global_read_lock=0;
992
991
static volatile uint32_t waiting_for_read_lock=0;
994
#define GOT_GLOBAL_READ_LOCK 1
995
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
997
bool lock_global_read_lock(Session *session)
993
bool Session::lockGlobalReadLock()
999
if (!session->global_read_lock)
995
if (isGlobalReadLock() == Session::NONE)
1001
997
const char *old_message;
1002
998
LOCK_global_read_lock.lock();
1003
old_message=session->enter_cond(COND_global_read_lock, LOCK_global_read_lock,
1004
"Waiting to get readlock");
999
old_message= enter_cond(COND_global_read_lock, LOCK_global_read_lock,
1000
"Waiting to get readlock");
1006
1002
waiting_for_read_lock++;
1007
1003
boost_unique_lock_t scopedLock(LOCK_global_read_lock, boost::adopt_lock_t());
1008
while (protect_against_global_read_lock && !session->killed)
1004
while (protect_against_global_read_lock && not getKilled())
1009
1005
COND_global_read_lock.wait(scopedLock);
1010
1006
waiting_for_read_lock--;
1011
1007
scopedLock.release();
1012
if (session->killed)
1014
session->exit_cond(old_message);
1010
exit_cond(old_message);
1017
session->global_read_lock= GOT_GLOBAL_READ_LOCK;
1013
setGlobalReadLock(Session::GOT_GLOBAL_READ_LOCK);
1018
1014
global_read_lock++;
1019
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1015
exit_cond(old_message); // this unlocks LOCK_global_read_lock
1022
1019
We DON'T set global_read_lock_blocks_commit now, it will be set after
1023
1020
tables are flushed (as the present function serves for FLUSH TABLES WITH
1033
void unlock_global_read_lock(Session *session)
1030
void Session::unlockGlobalReadLock(void)
1038
1035
boost_unique_lock_t scopedLock(LOCK_global_read_lock);
1039
1036
tmp= --global_read_lock;
1040
if (session->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1037
if (isGlobalReadLock() == Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1041
1038
--global_read_lock_blocks_commit;
1043
1040
/* Send the signal outside the mutex to avoid a context switch */
1046
1043
COND_global_read_lock.notify_all();
1048
session->global_read_lock= 0;
1045
setGlobalReadLock(Session::NONE);
1051
1048
static inline bool must_wait(bool is_not_commit)
1085
1081
return is_not_commit;
1087
old_message=session->enter_cond(COND_global_read_lock, LOCK_global_read_lock,
1088
"Waiting for release of readlock");
1089
while (must_wait(is_not_commit) && ! session->killed &&
1090
(!abort_on_refresh || session->version == refresh_version))
1083
old_message= enter_cond(COND_global_read_lock, LOCK_global_read_lock,
1084
"Waiting for release of readlock");
1086
while (must_wait(is_not_commit) && not getKilled() &&
1087
(!abort_on_refresh || version == refresh_version))
1092
1089
boost_unique_lock_t scoped(LOCK_global_read_lock, boost::adopt_lock_t());
1093
1090
COND_global_read_lock.wait(scoped);
1094
1091
scoped.release();
1096
if (session->killed)
1099
if (!abort_on_refresh && !result)
1096
if (not abort_on_refresh && not result)
1100
1097
protect_against_global_read_lock++;
1102
1100
The following is only true in case of a global read locks (which is rare)
1103
1101
and if old_message is set
1105
1103
if (unlikely(need_exit_cond))
1106
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1105
exit_cond(old_message); // this unlocks LOCK_global_read_lock
1108
1109
LOCK_global_read_lock.unlock();
1113
void start_waiting_global_read_lock(Session *session)
1116
void Session::startWaitingGlobalReadLock()
1116
if (unlikely(session->global_read_lock))
1119
if (unlikely(isGlobalReadLock()))
1118
1122
LOCK_global_read_lock.lock();
1119
1123
tmp= (!--protect_against_global_read_lock &&
1120
1124
(waiting_for_read_lock || global_read_lock_blocks_commit));
1121
1125
LOCK_global_read_lock.unlock();
1123
1128
COND_global_read_lock.notify_all();
1128
bool make_global_read_lock_block_commit(Session *session)
1132
bool Session::makeGlobalReadLockBlockCommit()
1131
1135
const char *old_message;
1133
1137
If we didn't succeed lock_global_read_lock(), or if we already suceeded
1134
make_global_read_lock_block_commit(), do nothing.
1138
Session::makeGlobalReadLockBlockCommit(), do nothing.
1136
if (session->global_read_lock != GOT_GLOBAL_READ_LOCK)
1140
if (isGlobalReadLock() != Session::GOT_GLOBAL_READ_LOCK)
1138
1142
LOCK_global_read_lock.lock();
1139
1143
/* increment this BEFORE waiting on cond (otherwise race cond) */
1140
1144
global_read_lock_blocks_commit++;
1141
old_message= session->enter_cond(COND_global_read_lock, LOCK_global_read_lock,
1142
"Waiting for all running commits to finish");
1143
while (protect_against_global_read_lock && !session->killed)
1145
old_message= enter_cond(COND_global_read_lock, LOCK_global_read_lock,
1146
"Waiting for all running commits to finish");
1147
while (protect_against_global_read_lock && not getKilled())
1145
1149
boost_unique_lock_t scopedLock(LOCK_global_read_lock, boost::adopt_lock_t());
1146
1150
COND_global_read_lock.wait(scopedLock);
1147
1151
scopedLock.release();
1149
if ((error= test(session->killed)))
1153
if ((error= test(getKilled())))
1150
1155
global_read_lock_blocks_commit--; // undo what we did
1152
session->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1153
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1159
setGlobalReadLock(Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT);
1162
exit_cond(old_message); // this unlocks LOCK_global_read_lock