1
by brian
clean slate |
1 |
/* Copyright (C) 2000-2006 MySQL AB
|
2 |
||
3 |
This program is free software; you can redistribute it and/or modify
|
|
4 |
it under the terms of the GNU General Public License as published by
|
|
5 |
the Free Software Foundation; version 2 of the License.
|
|
6 |
||
7 |
This program is distributed in the hope that it will be useful,
|
|
8 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
9 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
10 |
GNU General Public License for more details.
|
|
11 |
||
12 |
You should have received a copy of the GNU General Public License
|
|
13 |
along with this program; if not, write to the Free Software
|
|
14 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
15 |
||
16 |
||
17 |
/**
|
|
18 |
@file
|
|
19 |
||
20 |
Locking functions for mysql.
|
|
21 |
||
22 |
Because of the new concurrent inserts, we must first get external locks
|
|
23 |
before getting internal locks. If we do it in the other order, the status
|
|
24 |
information is not up to date when called from the lock handler.
|
|
25 |
||
26 |
GENERAL DESCRIPTION OF LOCKING
|
|
27 |
||
28 |
When not using LOCK TABLES:
|
|
29 |
||
30 |
- For each SQL statement mysql_lock_tables() is called for all involved
|
|
31 |
tables.
|
|
32 |
- mysql_lock_tables() will call
|
|
33 |
table_handler->external_lock(thd,locktype) for each table.
|
|
34 |
This is followed by a call to thr_multi_lock() for all tables.
|
|
35 |
||
36 |
- When statement is done, we call mysql_unlock_tables().
|
|
37 |
This will call thr_multi_unlock() followed by
|
|
38 |
table_handler->external_lock(thd, F_UNLCK) for each table.
|
|
39 |
||
40 |
- Note that mysql_unlock_tables() may be called several times as
|
|
41 |
MySQL in some cases can free some tables earlier than others.
|
|
42 |
||
43 |
- The above is true both for normal and temporary tables.
|
|
44 |
||
45 |
- Temporary non transactional tables are never passed to thr_multi_lock()
|
|
46 |
and we never call external_lock(thd, F_UNLOCK) on these.
|
|
47 |
||
48 |
When using LOCK TABLES:
|
|
49 |
||
50 |
- LOCK TABLE will call mysql_lock_tables() for all tables.
|
|
51 |
mysql_lock_tables() will call
|
|
52 |
table_handler->external_lock(thd,locktype) for each table.
|
|
53 |
This is followed by a call to thr_multi_lock() for all tables.
|
|
54 |
||
55 |
- For each statement, we will call table_handler->start_stmt(THD)
|
|
56 |
to inform the table handler that we are using the table.
|
|
57 |
||
58 |
The tables used can only be tables used in LOCK TABLES or a
|
|
59 |
temporary table.
|
|
60 |
||
61 |
- When statement is done, we will call ha_commit_stmt(thd);
|
|
62 |
||
63 |
- When calling UNLOCK TABLES we call mysql_unlock_tables() for all
|
|
64 |
tables used in LOCK TABLES
|
|
65 |
||
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 |
excluding one that caused failure. That means handler must cleanup itself
|
|
69 |
in case external_lock() fails.
|
|
70 |
||
71 |
@todo
|
|
72 |
Change to use my_malloc() ONLY when using LOCK TABLES command or when
|
|
73 |
we are forced to use mysql_lock_merge.
|
|
74 |
*/
|
|
75 |
||
76 |
#include "mysql_priv.h" |
|
77 |
#include <hash.h> |
|
78 |
#include <assert.h> |
|
79 |
||
80 |
/**
|
|
81 |
@defgroup Locking Locking
|
|
82 |
@{
|
|
83 |
*/
|
|
84 |
||
85 |
extern HASH open_cache; |
|
86 |
||
87 |
/* flags for get_lock_data */
|
|
88 |
#define GET_LOCK_UNLOCK 1
|
|
89 |
#define GET_LOCK_STORE_LOCKS 2
|
|
90 |
||
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); |
|
95 |
static void print_lock_error(int error, const char *); |
|
96 |
||
97 |
/*
|
|
98 |
Lock tables.
|
|
99 |
||
100 |
SYNOPSIS
|
|
101 |
mysql_lock_tables()
|
|
102 |
thd The current thread.
|
|
103 |
tables An array of pointers to the tables to lock.
|
|
104 |
count The number of tables to lock.
|
|
105 |
flags Options:
|
|
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
|
|
110 |
or dropped tables by itself,
|
|
111 |
mysql_lock_tables() should
|
|
112 |
notify upper level and rely
|
|
113 |
on caller doing this.
|
|
114 |
need_reopen Out parameter, TRUE if some tables were altered
|
|
115 |
or deleted and should be reopened by caller.
|
|
116 |
||
117 |
RETURN
|
|
118 |
A lock structure pointer on success.
|
|
119 |
NULL on error or if some tables should be reopen.
|
|
120 |
*/
|
|
121 |
||
122 |
/* Map the return value of thr_lock to an error from errmsg.txt */
|
|
123 |
static int thr_lock_errno_to_mysql[]= |
|
124 |
{ 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK }; |
|
125 |
||
126 |
/**
|
|
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.
|
|
133 |
*/
|
|
77.1.45
by Monty Taylor
Warning fixes. |
134 |
int mysql_lock_tables_check(THD *thd __attribute__((__unused__)), |
135 |
TABLE **tables, uint count, |
|
136 |
uint flags __attribute__((__unused__))) |
|
1
by brian
clean slate |
137 |
{
|
138 |
uint system_count; |
|
139 |
uint i; |
|
140 |
||
141 |
system_count= 0; |
|
142 |
||
143 |
for (i=0 ; i<count; i++) |
|
144 |
{
|
|
145 |
TABLE *t= tables[i]; |
|
146 |
||
147 |
/* Protect against 'fake' partially initialized TABLE_SHARE */
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
148 |
assert(t->s->table_category != TABLE_UNKNOWN_CATEGORY); |
1
by brian
clean slate |
149 |
|
150 |
if ((t->s->table_category == TABLE_CATEGORY_SYSTEM) && |
|
151 |
(t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE)) |
|
152 |
{
|
|
153 |
system_count++; |
|
154 |
}
|
|
155 |
}
|
|
156 |
||
157 |
/*
|
|
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.
|
|
161 |
*/
|
|
162 |
if ((system_count > 0) && (system_count < count)) |
|
163 |
{
|
|
164 |
my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0)); |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
165 |
return(1); |
1
by brian
clean slate |
166 |
}
|
167 |
||
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
168 |
return(0); |
1
by brian
clean slate |
169 |
}
|
170 |
||
171 |
||
172 |
/**
|
|
173 |
Reset lock type in lock data and free.
|
|
174 |
||
175 |
@param mysql_lock Lock structures to reset.
|
|
176 |
||
177 |
@note After a locking error we want to quit the locking of the table(s).
|
|
178 |
The test case in the bug report for Bug #18544 has the following
|
|
179 |
cases: 1. Locking error in lock_external() due to InnoDB timeout.
|
|
180 |
2. Locking error in get_lock_data() due to missing write permission.
|
|
181 |
3. Locking error in wait_if_global_read_lock() due to lock conflict.
|
|
182 |
||
183 |
@note In all these cases we have already set the lock type into the lock
|
|
184 |
data of the open table(s). If the table(s) are in the open table
|
|
185 |
cache, they could be reused with the non-zero lock type set. This
|
|
186 |
could lead to ignoring a different lock type with the next lock.
|
|
187 |
||
188 |
@note Clear the lock type of all lock data. This ensures that the next
|
|
189 |
lock request will set its lock type properly.
|
|
190 |
*/
|
|
191 |
||
192 |
static void reset_lock_data_and_free(MYSQL_LOCK **mysql_lock) |
|
193 |
{
|
|
194 |
MYSQL_LOCK *sql_lock= *mysql_lock; |
|
195 |
THR_LOCK_DATA **ldata, **ldata_end; |
|
196 |
||
197 |
/* Clear the lock type of all lock data to avoid reusage. */
|
|
198 |
for (ldata= sql_lock->locks, ldata_end= ldata + sql_lock->lock_count; |
|
199 |
ldata < ldata_end; |
|
200 |
ldata++) |
|
201 |
{
|
|
202 |
/* Reset lock type. */
|
|
203 |
(*ldata)->type= TL_UNLOCK; |
|
204 |
}
|
|
205 |
my_free((uchar*) sql_lock, MYF(0)); |
|
206 |
*mysql_lock= 0; |
|
207 |
}
|
|
208 |
||
209 |
||
210 |
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, |
|
211 |
uint flags, bool *need_reopen) |
|
212 |
{
|
|
213 |
MYSQL_LOCK *sql_lock; |
|
214 |
TABLE *write_lock_used; |
|
215 |
int rc; |
|
216 |
||
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
217 |
*need_reopen= false; |
1
by brian
clean slate |
218 |
|
219 |
if (mysql_lock_tables_check(thd, tables, count, flags)) |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
220 |
return (NULL); |
1
by brian
clean slate |
221 |
|
222 |
for (;;) |
|
223 |
{
|
|
224 |
if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS, |
|
225 |
&write_lock_used))) |
|
226 |
break; |
|
227 |
||
228 |
if (global_read_lock && write_lock_used && |
|
229 |
! (flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK)) |
|
230 |
{
|
|
231 |
/*
|
|
232 |
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
|
|
233 |
Wait until the lock is gone
|
|
234 |
*/
|
|
235 |
if (wait_if_global_read_lock(thd, 1, 1)) |
|
236 |
{
|
|
237 |
/* Clear the lock type of all lock data to avoid reusage. */
|
|
238 |
reset_lock_data_and_free(&sql_lock); |
|
239 |
break; |
|
240 |
}
|
|
241 |
if (thd->version != refresh_version) |
|
242 |
{
|
|
243 |
/* Clear the lock type of all lock data to avoid reusage. */
|
|
244 |
reset_lock_data_and_free(&sql_lock); |
|
245 |
goto retry; |
|
246 |
}
|
|
247 |
}
|
|
248 |
||
249 |
if (!(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY) && |
|
250 |
write_lock_used && |
|
251 |
opt_readonly && |
|
252 |
!thd->slave_thread) |
|
253 |
{
|
|
254 |
/*
|
|
255 |
Someone has issued SET GLOBAL READ_ONLY=1 and we want a write lock.
|
|
256 |
We do not wait for READ_ONLY=0, and fail.
|
|
257 |
*/
|
|
258 |
reset_lock_data_and_free(&sql_lock); |
|
259 |
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); |
|
260 |
break; |
|
261 |
}
|
|
262 |
||
263 |
thd_proc_info(thd, "System lock"); |
|
264 |
if (sql_lock->table_count && lock_external(thd, sql_lock->table, |
|
265 |
sql_lock->table_count)) |
|
266 |
{
|
|
267 |
/* Clear the lock type of all lock data to avoid reusage. */
|
|
268 |
reset_lock_data_and_free(&sql_lock); |
|
269 |
break; |
|
270 |
}
|
|
271 |
thd_proc_info(thd, "Table lock"); |
|
272 |
/* Copy the lock data array. thr_multi_lock() reorders its contens. */
|
|
273 |
memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks, |
|
274 |
sql_lock->lock_count * sizeof(*sql_lock->locks)); |
|
275 |
/* Lock on the copied half of the lock data array. */
|
|
276 |
rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks + |
|
277 |
sql_lock->lock_count, |
|
278 |
sql_lock->lock_count, |
|
279 |
thd->lock_id)]; |
|
280 |
if (rc > 1) /* a timeout or a deadlock */ |
|
281 |
{
|
|
282 |
if (sql_lock->table_count) |
|
283 |
VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count)); |
|
284 |
reset_lock_data_and_free(&sql_lock); |
|
285 |
my_error(rc, MYF(0)); |
|
286 |
break; |
|
287 |
}
|
|
288 |
else if (rc == 1) /* aborted */ |
|
289 |
{
|
|
290 |
thd->some_tables_deleted=1; // Try again |
|
291 |
sql_lock->lock_count= 0; // Locks are already freed |
|
292 |
// Fall through: unlock, reset lock data, free and retry
|
|
293 |
}
|
|
294 |
else if (!thd->some_tables_deleted || (flags & MYSQL_LOCK_IGNORE_FLUSH)) |
|
295 |
{
|
|
296 |
/*
|
|
297 |
Thread was killed or lock aborted. Let upper level close all
|
|
298 |
used tables and retry or give error.
|
|
299 |
*/
|
|
300 |
break; |
|
301 |
}
|
|
302 |
else if (!thd->open_tables) |
|
303 |
{
|
|
304 |
// Only using temporary tables, no need to unlock
|
|
305 |
thd->some_tables_deleted=0; |
|
306 |
break; |
|
307 |
}
|
|
308 |
thd_proc_info(thd, 0); |
|
309 |
||
310 |
/* going to retry, unlock all tables */
|
|
311 |
if (sql_lock->lock_count) |
|
312 |
thr_multi_unlock(sql_lock->locks, sql_lock->lock_count); |
|
313 |
||
314 |
if (sql_lock->table_count) |
|
315 |
VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count)); |
|
316 |
||
317 |
/*
|
|
318 |
If thr_multi_lock fails it resets lock type for tables, which
|
|
319 |
were locked before (and including) one that caused error. Lock
|
|
320 |
type for other tables preserved.
|
|
321 |
*/
|
|
322 |
reset_lock_data_and_free(&sql_lock); |
|
323 |
retry: |
|
324 |
if (flags & MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN) |
|
325 |
{
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
326 |
*need_reopen= true; |
1
by brian
clean slate |
327 |
break; |
328 |
}
|
|
329 |
if (wait_for_tables(thd)) |
|
330 |
break; // Couldn't open tables |
|
331 |
}
|
|
332 |
thd_proc_info(thd, 0); |
|
333 |
if (thd->killed) |
|
334 |
{
|
|
335 |
thd->send_kill_message(); |
|
336 |
if (sql_lock) |
|
337 |
{
|
|
338 |
mysql_unlock_tables(thd,sql_lock); |
|
339 |
sql_lock=0; |
|
340 |
}
|
|
341 |
}
|
|
342 |
||
343 |
thd->set_time_after_lock(); |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
344 |
return (sql_lock); |
1
by brian
clean slate |
345 |
}
|
346 |
||
347 |
||
348 |
static int lock_external(THD *thd, TABLE **tables, uint count) |
|
349 |
{
|
|
350 |
register uint i; |
|
351 |
int lock_type,error; |
|
352 |
for (i=1 ; i <= count ; i++, tables++) |
|
353 |
{
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
354 |
assert((*tables)->reginfo.lock_type >= TL_READ); |
1
by brian
clean slate |
355 |
lock_type=F_WRLCK; /* Lock exclusive */ |
356 |
if ((*tables)->db_stat & HA_READ_ONLY || |
|
357 |
((*tables)->reginfo.lock_type >= TL_READ && |
|
358 |
(*tables)->reginfo.lock_type <= TL_READ_NO_INSERT)) |
|
359 |
lock_type=F_RDLCK; |
|
360 |
||
361 |
if ((error=(*tables)->file->ha_external_lock(thd,lock_type))) |
|
362 |
{
|
|
363 |
print_lock_error(error, (*tables)->file->table_type()); |
|
364 |
while (--i) |
|
365 |
{
|
|
366 |
tables--; |
|
367 |
(*tables)->file->ha_external_lock(thd, F_UNLCK); |
|
368 |
(*tables)->current_lock=F_UNLCK; |
|
369 |
}
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
370 |
return(error); |
1
by brian
clean slate |
371 |
}
|
372 |
else
|
|
373 |
{
|
|
374 |
(*tables)->db_stat &= ~ HA_BLOCK_LOCK; |
|
375 |
(*tables)->current_lock= lock_type; |
|
376 |
}
|
|
377 |
}
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
378 |
return(0); |
1
by brian
clean slate |
379 |
}
|
380 |
||
381 |
||
382 |
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock) |
|
383 |
{
|
|
384 |
if (sql_lock->lock_count) |
|
385 |
thr_multi_unlock(sql_lock->locks,sql_lock->lock_count); |
|
386 |
if (sql_lock->table_count) |
|
387 |
VOID(unlock_external(thd,sql_lock->table,sql_lock->table_count)); |
|
388 |
my_free((uchar*) sql_lock,MYF(0)); |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
389 |
return; |
1
by brian
clean slate |
390 |
}
|
391 |
||
392 |
/**
|
|
393 |
Unlock some of the tables locked by mysql_lock_tables.
|
|
394 |
||
395 |
This will work even if get_lock_data fails (next unlock will free all)
|
|
396 |
*/
|
|
397 |
||
398 |
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count) |
|
399 |
{
|
|
400 |
MYSQL_LOCK *sql_lock; |
|
401 |
TABLE *write_lock_used; |
|
402 |
if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK, |
|
403 |
&write_lock_used))) |
|
404 |
mysql_unlock_tables(thd, sql_lock); |
|
405 |
}
|
|
406 |
||
407 |
||
408 |
/**
|
|
409 |
unlock all tables locked for read.
|
|
410 |
*/
|
|
411 |
||
412 |
void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock) |
|
413 |
{
|
|
414 |
uint i,found; |
|
415 |
||
416 |
/* Move all write locks first */
|
|
417 |
THR_LOCK_DATA **lock=sql_lock->locks; |
|
418 |
for (i=found=0 ; i < sql_lock->lock_count ; i++) |
|
419 |
{
|
|
420 |
if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_READ) |
|
421 |
{
|
|
422 |
swap_variables(THR_LOCK_DATA *, *lock, sql_lock->locks[i]); |
|
423 |
lock++; |
|
424 |
found++; |
|
425 |
}
|
|
426 |
}
|
|
427 |
/* unlock the read locked tables */
|
|
428 |
if (i != found) |
|
429 |
{
|
|
430 |
thr_multi_unlock(lock,i-found); |
|
431 |
sql_lock->lock_count= found; |
|
432 |
}
|
|
433 |
||
434 |
/* Then do the same for the external locks */
|
|
435 |
/* Move all write locked tables first */
|
|
436 |
TABLE **table=sql_lock->table; |
|
437 |
for (i=found=0 ; i < sql_lock->table_count ; i++) |
|
438 |
{
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
439 |
assert(sql_lock->table[i]->lock_position == i); |
1
by brian
clean slate |
440 |
if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ) |
441 |
{
|
|
442 |
swap_variables(TABLE *, *table, sql_lock->table[i]); |
|
443 |
table++; |
|
444 |
found++; |
|
445 |
}
|
|
446 |
}
|
|
447 |
/* Unlock all read locked tables */
|
|
448 |
if (i != found) |
|
449 |
{
|
|
450 |
VOID(unlock_external(thd,table,i-found)); |
|
451 |
sql_lock->table_count=found; |
|
452 |
}
|
|
453 |
/* Fix the lock positions in TABLE */
|
|
454 |
table= sql_lock->table; |
|
455 |
found= 0; |
|
456 |
for (i= 0; i < sql_lock->table_count; i++) |
|
457 |
{
|
|
458 |
TABLE *tbl= *table; |
|
459 |
tbl->lock_position= table - sql_lock->table; |
|
460 |
tbl->lock_data_start= found; |
|
461 |
found+= tbl->lock_count; |
|
462 |
table++; |
|
463 |
}
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
464 |
return; |
1
by brian
clean slate |
465 |
}
|
466 |
||
467 |
||
468 |
/**
|
|
469 |
Try to find the table in the list of locked tables.
|
|
470 |
In case of success, unlock the table and remove it from this list.
|
|
471 |
||
472 |
@note This function has a legacy side effect: the table is
|
|
473 |
unlocked even if it is not found in the locked list.
|
|
474 |
It's not clear if this side effect is intentional or still
|
|
475 |
desirable. It might lead to unmatched calls to
|
|
476 |
unlock_external(). Moreover, a discrepancy can be left
|
|
477 |
unnoticed by the storage engine, because in
|
|
478 |
unlock_external() we call handler::external_lock(F_UNLCK) only
|
|
479 |
if table->current_lock is not F_UNLCK.
|
|
480 |
||
481 |
@param thd thread context
|
|
482 |
@param locked list of locked tables
|
|
483 |
@param table the table to unlock
|
|
484 |
@param always_unlock specify explicitly if the legacy side
|
|
485 |
effect is desired.
|
|
486 |
*/
|
|
487 |
||
488 |
void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table, |
|
489 |
bool always_unlock) |
|
490 |
{
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
491 |
if (always_unlock == true) |
1
by brian
clean slate |
492 |
mysql_unlock_some_tables(thd, &table, /* table count */ 1); |
493 |
if (locked) |
|
494 |
{
|
|
495 |
register uint i; |
|
496 |
for (i=0; i < locked->table_count; i++) |
|
497 |
{
|
|
498 |
if (locked->table[i] == table) |
|
499 |
{
|
|
500 |
uint j, removed_locks, old_tables; |
|
501 |
TABLE *tbl; |
|
502 |
uint lock_data_end; |
|
503 |
||
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
504 |
assert(table->lock_position == i); |
1
by brian
clean slate |
505 |
|
506 |
/* Unlock if not yet unlocked */
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
507 |
if (always_unlock == false) |
1
by brian
clean slate |
508 |
mysql_unlock_some_tables(thd, &table, /* table count */ 1); |
509 |
||
510 |
/* Decrement table_count in advance, making below expressions easier */
|
|
511 |
old_tables= --locked->table_count; |
|
512 |
||
513 |
/* The table has 'removed_locks' lock data elements in locked->locks */
|
|
514 |
removed_locks= table->lock_count; |
|
515 |
||
516 |
/* Move down all table pointers above 'i'. */
|
|
517 |
bmove((char*) (locked->table+i), |
|
518 |
(char*) (locked->table+i+1), |
|
519 |
(old_tables - i) * sizeof(TABLE*)); |
|
520 |
||
521 |
lock_data_end= table->lock_data_start + table->lock_count; |
|
522 |
/* Move down all lock data pointers above 'table->lock_data_end-1' */
|
|
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*)); |
|
527 |
||
528 |
/*
|
|
529 |
Fix moved table elements.
|
|
530 |
lock_position is the index in the 'locked->table' array,
|
|
531 |
it must be fixed by one.
|
|
532 |
table->lock_data_start is pointer to the lock data for this table
|
|
533 |
in the 'locked->locks' array, they must be fixed by 'removed_locks',
|
|
534 |
the lock data count of the removed table.
|
|
535 |
*/
|
|
536 |
for (j= i ; j < old_tables; j++) |
|
537 |
{
|
|
538 |
tbl= locked->table[j]; |
|
539 |
tbl->lock_position--; |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
540 |
assert(tbl->lock_position == j); |
1
by brian
clean slate |
541 |
tbl->lock_data_start-= removed_locks; |
542 |
}
|
|
543 |
||
544 |
/* Finally adjust lock_count. */
|
|
545 |
locked->lock_count-= removed_locks; |
|
546 |
break; |
|
547 |
}
|
|
548 |
}
|
|
549 |
}
|
|
550 |
}
|
|
551 |
||
552 |
/* Downgrade all locks on a table to new WRITE level from WRITE_ONLY */
|
|
553 |
||
554 |
void mysql_lock_downgrade_write(THD *thd, TABLE *table, |
|
555 |
thr_lock_type new_lock_type) |
|
556 |
{
|
|
557 |
MYSQL_LOCK *locked; |
|
558 |
TABLE *write_lock_used; |
|
559 |
if ((locked = get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK, |
|
560 |
&write_lock_used))) |
|
561 |
{
|
|
562 |
for (uint i=0; i < locked->lock_count; i++) |
|
563 |
thr_downgrade_write_lock(locked->locks[i], new_lock_type); |
|
564 |
my_free((uchar*) locked,MYF(0)); |
|
565 |
}
|
|
566 |
}
|
|
567 |
||
568 |
||
569 |
/** Abort all other threads waiting to get lock in table. */
|
|
570 |
||
571 |
void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock) |
|
572 |
{
|
|
573 |
MYSQL_LOCK *locked; |
|
574 |
TABLE *write_lock_used; |
|
575 |
||
576 |
if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK, |
|
577 |
&write_lock_used))) |
|
578 |
{
|
|
579 |
for (uint i=0; i < locked->lock_count; i++) |
|
580 |
thr_abort_locks(locked->locks[i]->lock, upgrade_lock); |
|
581 |
my_free((uchar*) locked,MYF(0)); |
|
582 |
}
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
583 |
return; |
1
by brian
clean slate |
584 |
}
|
585 |
||
586 |
||
587 |
/**
|
|
588 |
Abort one thread / table combination.
|
|
589 |
||
590 |
@param thd Thread handler
|
|
591 |
@param table Table that should be removed from lock queue
|
|
592 |
||
593 |
@retval
|
|
594 |
0 Table was not locked by another thread
|
|
595 |
@retval
|
|
596 |
1 Table was locked by at least one other thread
|
|
597 |
*/
|
|
598 |
||
599 |
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table) |
|
600 |
{
|
|
601 |
MYSQL_LOCK *locked; |
|
602 |
TABLE *write_lock_used; |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
603 |
bool result= false; |
1
by brian
clean slate |
604 |
|
605 |
if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK, |
|
606 |
&write_lock_used))) |
|
607 |
{
|
|
608 |
for (uint i=0; i < locked->lock_count; i++) |
|
609 |
{
|
|
610 |
if (thr_abort_locks_for_thread(locked->locks[i]->lock, |
|
611 |
table->in_use->thread_id)) |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
612 |
result= true; |
1
by brian
clean slate |
613 |
}
|
614 |
my_free((uchar*) locked,MYF(0)); |
|
615 |
}
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
616 |
return(result); |
1
by brian
clean slate |
617 |
}
|
618 |
||
619 |
||
620 |
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b) |
|
621 |
{
|
|
622 |
MYSQL_LOCK *sql_lock; |
|
623 |
TABLE **table, **end_table; |
|
624 |
||
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)))) |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
629 |
return(0); // Fatal error |
1
by brian
clean slate |
630 |
sql_lock->lock_count=a->lock_count+b->lock_count; |
631 |
sql_lock->table_count=a->table_count+b->table_count; |
|
632 |
sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1); |
|
633 |
sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count); |
|
634 |
memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks)); |
|
635 |
memcpy(sql_lock->locks+a->lock_count,b->locks, |
|
636 |
b->lock_count*sizeof(*b->locks)); |
|
637 |
memcpy(sql_lock->table,a->table,a->table_count*sizeof(*a->table)); |
|
638 |
memcpy(sql_lock->table+a->table_count,b->table, |
|
639 |
b->table_count*sizeof(*b->table)); |
|
640 |
||
641 |
/*
|
|
642 |
Now adjust lock_position and lock_data_start for all objects that was
|
|
643 |
moved in 'b' (as there is now all objects in 'a' before these).
|
|
644 |
*/
|
|
645 |
for (table= sql_lock->table + a->table_count, |
|
646 |
end_table= table + b->table_count; |
|
647 |
table < end_table; |
|
648 |
table++) |
|
649 |
{
|
|
650 |
(*table)->lock_position+= a->table_count; |
|
651 |
(*table)->lock_data_start+= a->lock_count; |
|
652 |
}
|
|
653 |
||
654 |
/* Delete old, not needed locks */
|
|
655 |
my_free((uchar*) a,MYF(0)); |
|
656 |
my_free((uchar*) b,MYF(0)); |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
657 |
return(sql_lock); |
1
by brian
clean slate |
658 |
}
|
659 |
||
660 |
||
661 |
/**
|
|
662 |
Find duplicate lock in tables.
|
|
663 |
||
664 |
Temporary tables are ignored here like they are ignored in
|
|
665 |
get_lock_data(). If we allow two opens on temporary tables later,
|
|
666 |
both functions should be checked.
|
|
667 |
||
668 |
@param thd The current thread.
|
|
669 |
@param needle The table to check for duplicate lock.
|
|
670 |
@param haystack The list of tables to search for the dup lock.
|
|
671 |
||
672 |
@note
|
|
673 |
This is mainly meant for MERGE tables in INSERT ... SELECT
|
|
674 |
situations. The 'real', underlying tables can be found only after
|
|
675 |
the MERGE tables are opened. This function assumes that the tables are
|
|
676 |
already locked.
|
|
677 |
||
678 |
@retval
|
|
679 |
NULL No duplicate lock found.
|
|
680 |
@retval
|
|
681 |
!NULL First table from 'haystack' that matches a lock on 'needle'.
|
|
682 |
*/
|
|
683 |
||
684 |
TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle, |
|
685 |
TABLE_LIST *haystack) |
|
686 |
{
|
|
687 |
MYSQL_LOCK *mylock; |
|
688 |
TABLE **lock_tables; |
|
689 |
TABLE *table; |
|
690 |
TABLE *table2; |
|
691 |
THR_LOCK_DATA **lock_locks; |
|
692 |
THR_LOCK_DATA **table_lock_data; |
|
693 |
THR_LOCK_DATA **end_data; |
|
694 |
THR_LOCK_DATA **lock_data2; |
|
695 |
THR_LOCK_DATA **end_data2; |
|
696 |
||
697 |
/*
|
|
698 |
Table may not be defined for derived or view tables.
|
|
699 |
Table may not be part of a lock for delayed operations.
|
|
700 |
*/
|
|
701 |
if (! (table= needle->table) || ! table->lock_count) |
|
702 |
goto end; |
|
703 |
||
704 |
/* A temporary table does not have locks. */
|
|
705 |
if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE) |
|
706 |
goto end; |
|
707 |
||
708 |
/* Get command lock or LOCK TABLES lock. Maybe empty for INSERT DELAYED. */
|
|
709 |
if (! (mylock= thd->lock ? thd->lock : thd->locked_tables)) |
|
710 |
goto end; |
|
711 |
||
712 |
/* If we have less than two tables, we cannot have duplicates. */
|
|
713 |
if (mylock->table_count < 2) |
|
714 |
goto end; |
|
715 |
||
716 |
lock_locks= mylock->locks; |
|
717 |
lock_tables= mylock->table; |
|
718 |
||
719 |
/* Prepare table related variables that don't change in loop. */
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
720 |
assert((table->lock_position < mylock->table_count) && |
1
by brian
clean slate |
721 |
(table == lock_tables[table->lock_position])); |
722 |
table_lock_data= lock_locks + table->lock_data_start; |
|
723 |
end_data= table_lock_data + table->lock_count; |
|
724 |
||
725 |
for (; haystack; haystack= haystack->next_global) |
|
726 |
{
|
|
727 |
if (haystack->placeholder()) |
|
728 |
continue; |
|
729 |
table2= haystack->table; |
|
730 |
if (table2->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE) |
|
731 |
continue; |
|
732 |
||
733 |
/* All tables in list must be in lock. */
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
734 |
assert((table2->lock_position < mylock->table_count) && |
1
by brian
clean slate |
735 |
(table2 == lock_tables[table2->lock_position])); |
736 |
||
737 |
for (lock_data2= lock_locks + table2->lock_data_start, |
|
738 |
end_data2= lock_data2 + table2->lock_count; |
|
739 |
lock_data2 < end_data2; |
|
740 |
lock_data2++) |
|
741 |
{
|
|
742 |
THR_LOCK_DATA **lock_data; |
|
743 |
THR_LOCK *lock2= (*lock_data2)->lock; |
|
744 |
||
745 |
for (lock_data= table_lock_data; |
|
746 |
lock_data < end_data; |
|
747 |
lock_data++) |
|
748 |
{
|
|
749 |
if ((*lock_data)->lock == lock2) |
|
750 |
{
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
751 |
return(haystack); |
1
by brian
clean slate |
752 |
}
|
753 |
}
|
|
754 |
}
|
|
755 |
}
|
|
756 |
||
757 |
end: |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
758 |
return(NULL); |
1
by brian
clean slate |
759 |
}
|
760 |
||
761 |
||
762 |
/** Unlock a set of external. */
|
|
763 |
||
764 |
static int unlock_external(THD *thd, TABLE **table,uint count) |
|
765 |
{
|
|
766 |
int error,error_code; |
|
767 |
||
768 |
error_code=0; |
|
769 |
do
|
|
770 |
{
|
|
771 |
if ((*table)->current_lock != F_UNLCK) |
|
772 |
{
|
|
773 |
(*table)->current_lock = F_UNLCK; |
|
774 |
if ((error=(*table)->file->ha_external_lock(thd, F_UNLCK))) |
|
775 |
{
|
|
776 |
error_code=error; |
|
777 |
print_lock_error(error_code, (*table)->file->table_type()); |
|
778 |
}
|
|
779 |
}
|
|
780 |
table++; |
|
781 |
} while (--count); |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
782 |
return(error_code); |
1
by brian
clean slate |
783 |
}
|
784 |
||
785 |
||
786 |
/**
|
|
787 |
Get lock structures from table structs and initialize locks.
|
|
788 |
||
789 |
@param thd Thread handler
|
|
790 |
@param table_ptr Pointer to tables that should be locks
|
|
791 |
@param flags One of:
|
|
792 |
- GET_LOCK_UNLOCK : If we should send TL_IGNORE to store lock
|
|
793 |
- GET_LOCK_STORE_LOCKS : Store lock info in TABLE
|
|
794 |
@param write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE
|
|
795 |
*/
|
|
796 |
||
797 |
static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, |
|
798 |
uint flags, TABLE **write_lock_used) |
|
799 |
{
|
|
800 |
uint i,tables,lock_count; |
|
801 |
MYSQL_LOCK *sql_lock; |
|
802 |
THR_LOCK_DATA **locks, **locks_buf, **locks_start; |
|
803 |
TABLE **to, **table_buf; |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
804 |
|
805 |
assert((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS)); |
|
806 |
||
1
by brian
clean slate |
807 |
*write_lock_used=0; |
808 |
for (i=tables=lock_count=0 ; i < count ; i++) |
|
809 |
{
|
|
810 |
TABLE *t= table_ptr[i]; |
|
811 |
||
812 |
if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE) |
|
813 |
{
|
|
814 |
tables+= t->file->lock_count(); |
|
815 |
lock_count++; |
|
816 |
}
|
|
817 |
}
|
|
818 |
||
819 |
/*
|
|
820 |
Allocating twice the number of pointers for lock data for use in
|
|
821 |
thr_mulit_lock(). This function reorders the lock data, but cannot
|
|
822 |
update the table values. So the second part of the array is copied
|
|
823 |
from the first part immediately before calling thr_multi_lock().
|
|
824 |
*/
|
|
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, |
|
829 |
MYF(0)))) |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
830 |
return(0); |
1
by brian
clean slate |
831 |
locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1); |
832 |
to= table_buf= sql_lock->table= (TABLE**) (locks + tables * 2); |
|
833 |
sql_lock->table_count=lock_count; |
|
834 |
||
835 |
for (i=0 ; i < count ; i++) |
|
836 |
{
|
|
837 |
TABLE *table; |
|
838 |
enum thr_lock_type lock_type; |
|
839 |
||
840 |
if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE) |
|
841 |
continue; |
|
842 |
lock_type= table->reginfo.lock_type; |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
843 |
assert (lock_type != TL_WRITE_DEFAULT); |
1
by brian
clean slate |
844 |
if (lock_type >= TL_WRITE_ALLOW_WRITE) |
845 |
{
|
|
846 |
*write_lock_used=table; |
|
847 |
if (table->db_stat & HA_READ_ONLY) |
|
848 |
{
|
|
849 |
my_error(ER_OPEN_AS_READONLY,MYF(0),table->alias); |
|
850 |
/* Clear the lock type of the lock data that are stored already. */
|
|
851 |
sql_lock->lock_count= locks - sql_lock->locks; |
|
852 |
reset_lock_data_and_free(&sql_lock); |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
853 |
return(0); |
1
by brian
clean slate |
854 |
}
|
855 |
}
|
|
856 |
THR_LOCK_DATA **org_locks = locks; |
|
857 |
locks_start= locks; |
|
858 |
locks= table->file->store_lock(thd, locks, |
|
859 |
(flags & GET_LOCK_UNLOCK) ? TL_IGNORE : |
|
860 |
lock_type); |
|
861 |
if (flags & GET_LOCK_STORE_LOCKS) |
|
862 |
{
|
|
863 |
table->lock_position= (uint) (to - table_buf); |
|
864 |
table->lock_data_start= (uint) (locks_start - locks_buf); |
|
865 |
table->lock_count= (uint) (locks - locks_start); |
|
866 |
}
|
|
867 |
*to++= table; |
|
868 |
if (locks) |
|
869 |
for ( ; org_locks != locks ; org_locks++) |
|
870 |
(*org_locks)->debug_print_param= (void *) table; |
|
871 |
}
|
|
872 |
/*
|
|
873 |
We do not use 'tables', because there are cases where store_lock()
|
|
874 |
returns less locks than lock_count() claimed. This can happen when
|
|
875 |
a FLUSH TABLES tries to abort locks from a MERGE table of another
|
|
876 |
thread. When that thread has just opened the table, but not yet
|
|
877 |
attached its children, it cannot return the locks. lock_count()
|
|
878 |
always returns the number of locks that an attached table has.
|
|
879 |
This is done to avoid the reverse situation: If lock_count() would
|
|
880 |
return 0 for a non-attached MERGE table, and that table becomes
|
|
881 |
attached between the calls to lock_count() and store_lock(), then
|
|
882 |
we would have allocated too little memory for the lock data. Now
|
|
883 |
we may allocate too much, but better safe than memory overrun.
|
|
884 |
And in the FLUSH case, the memory is released quickly anyway.
|
|
885 |
*/
|
|
886 |
sql_lock->lock_count= locks - locks_buf; |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
887 |
return(sql_lock); |
1
by brian
clean slate |
888 |
}
|
889 |
||
890 |
||
891 |
/*****************************************************************************
|
|
892 |
Lock table based on the name.
|
|
893 |
This is used when we need total access to a closed, not open table
|
|
894 |
*****************************************************************************/
|
|
895 |
||
896 |
/**
|
|
897 |
Lock and wait for the named lock.
|
|
898 |
||
899 |
@param thd Thread handler
|
|
900 |
@param table_list Lock first table in this list
|
|
901 |
||
902 |
||
903 |
@note
|
|
904 |
Works together with global read lock.
|
|
905 |
||
906 |
@retval
|
|
907 |
0 ok
|
|
908 |
@retval
|
|
909 |
1 error
|
|
910 |
*/
|
|
911 |
||
912 |
int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list) |
|
913 |
{
|
|
914 |
int lock_retcode; |
|
915 |
int error= -1; |
|
916 |
||
917 |
if (wait_if_global_read_lock(thd, 0, 1)) |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
918 |
return(1); |
1
by brian
clean slate |
919 |
VOID(pthread_mutex_lock(&LOCK_open)); |
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
920 |
if ((lock_retcode = lock_table_name(thd, table_list, true)) < 0) |
1
by brian
clean slate |
921 |
goto end; |
922 |
if (lock_retcode && wait_for_locked_table_names(thd, table_list)) |
|
923 |
{
|
|
924 |
unlock_table_name(thd, table_list); |
|
925 |
goto end; |
|
926 |
}
|
|
927 |
error=0; |
|
928 |
||
929 |
end: |
|
930 |
pthread_mutex_unlock(&LOCK_open); |
|
931 |
start_waiting_global_read_lock(thd); |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
932 |
return(error); |
1
by brian
clean slate |
933 |
}
|
934 |
||
935 |
||
936 |
/**
|
|
937 |
Put a not open table with an old refresh version in the table cache.
|
|
938 |
||
939 |
@param thd Thread handler
|
|
940 |
@param table_list Lock first table in this list
|
|
941 |
@param check_in_use Do we need to check if table already in use by us
|
|
942 |
||
943 |
@note
|
|
944 |
One must have a lock on LOCK_open!
|
|
945 |
||
946 |
@warning
|
|
947 |
If you are going to update the table, you should use
|
|
948 |
lock_and_wait_for_table_name instead of this function as this works
|
|
949 |
together with 'FLUSH TABLES WITH READ LOCK'
|
|
950 |
||
951 |
@note
|
|
952 |
This will force any other threads that uses the table to release it
|
|
953 |
as soon as possible.
|
|
954 |
||
955 |
@return
|
|
956 |
< 0 error
|
|
957 |
@return
|
|
958 |
== 0 table locked
|
|
959 |
@return
|
|
960 |
> 0 table locked, but someone is using it
|
|
961 |
*/
|
|
962 |
||
963 |
int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use) |
|
964 |
{
|
|
965 |
TABLE *table; |
|
966 |
char key[MAX_DBKEY_LENGTH]; |
|
967 |
char *db= table_list->db; |
|
968 |
uint key_length; |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
969 |
bool found_locked_table= false; |
1
by brian
clean slate |
970 |
HASH_SEARCH_STATE state; |
971 |
||
972 |
key_length= create_table_def_key(thd, key, table_list, 0); |
|
973 |
||
974 |
if (check_in_use) |
|
975 |
{
|
|
976 |
/* Only insert the table if we haven't insert it already */
|
|
977 |
for (table=(TABLE*) hash_first(&open_cache, (uchar*)key, |
|
978 |
key_length, &state); |
|
979 |
table ; |
|
980 |
table = (TABLE*) hash_next(&open_cache,(uchar*) key, |
|
981 |
key_length, &state)) |
|
982 |
{
|
|
983 |
if (table->reginfo.lock_type < TL_WRITE) |
|
984 |
{
|
|
985 |
if (table->in_use == thd) |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
986 |
found_locked_table= true; |
1
by brian
clean slate |
987 |
continue; |
988 |
}
|
|
989 |
||
990 |
if (table->in_use == thd) |
|
991 |
{
|
|
992 |
table->s->version= 0; // Ensure no one can use this |
|
993 |
table->locked_by_name= 1; |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
994 |
return(0); |
1
by brian
clean slate |
995 |
}
|
996 |
}
|
|
997 |
}
|
|
998 |
||
999 |
if (thd->locked_tables && thd->locked_tables->table_count && |
|
1000 |
! find_temporary_table(thd, table_list->db, table_list->table_name)) |
|
1001 |
{
|
|
1002 |
if (found_locked_table) |
|
1003 |
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_list->alias); |
|
1004 |
else
|
|
1005 |
my_error(ER_TABLE_NOT_LOCKED, MYF(0), table_list->alias); |
|
1006 |
||
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1007 |
return(-1); |
1
by brian
clean slate |
1008 |
}
|
1009 |
||
1010 |
if (!(table= table_cache_insert_placeholder(thd, key, key_length))) |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1011 |
return(-1); |
1
by brian
clean slate |
1012 |
|
1013 |
table_list->table=table; |
|
1014 |
||
1015 |
/* Return 1 if table is in use */
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1016 |
return(test(remove_table_from_cache(thd, db, table_list->table_name, |
1
by brian
clean slate |
1017 |
check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG))); |
1018 |
}
|
|
1019 |
||
1020 |
||
77.1.45
by Monty Taylor
Warning fixes. |
1021 |
void unlock_table_name(THD *thd __attribute__((__unused__)), |
1022 |
TABLE_LIST *table_list) |
|
1
by brian
clean slate |
1023 |
{
|
1024 |
if (table_list->table) |
|
1025 |
{
|
|
1026 |
hash_delete(&open_cache, (uchar*) table_list->table); |
|
1027 |
broadcast_refresh(); |
|
1028 |
}
|
|
1029 |
}
|
|
1030 |
||
1031 |
||
77.1.45
by Monty Taylor
Warning fixes. |
1032 |
static bool locked_named_table(THD *thd __attribute__((__unused__)), |
1033 |
TABLE_LIST *table_list) |
|
1
by brian
clean slate |
1034 |
{
|
1035 |
for (; table_list ; table_list=table_list->next_local) |
|
1036 |
{
|
|
1037 |
TABLE *table= table_list->table; |
|
1038 |
if (table) |
|
1039 |
{
|
|
1040 |
TABLE *save_next= table->next; |
|
1041 |
bool result; |
|
1042 |
table->next= 0; |
|
1043 |
result= table_is_used(table_list->table, 0); |
|
1044 |
table->next= save_next; |
|
1045 |
if (result) |
|
1046 |
return 1; |
|
1047 |
}
|
|
1048 |
}
|
|
1049 |
return 0; // All tables are locked |
|
1050 |
}
|
|
1051 |
||
1052 |
||
1053 |
bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list) |
|
1054 |
{
|
|
1055 |
bool result=0; |
|
1056 |
||
1057 |
safe_mutex_assert_owner(&LOCK_open); |
|
1058 |
||
1059 |
while (locked_named_table(thd,table_list)) |
|
1060 |
{
|
|
1061 |
if (thd->killed) |
|
1062 |
{
|
|
1063 |
result=1; |
|
1064 |
break; |
|
1065 |
}
|
|
1066 |
wait_for_condition(thd, &LOCK_open, &COND_refresh); |
|
1067 |
pthread_mutex_lock(&LOCK_open); |
|
1068 |
}
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1069 |
return(result); |
1
by brian
clean slate |
1070 |
}
|
1071 |
||
1072 |
||
1073 |
/**
|
|
1074 |
Lock all tables in list with a name lock.
|
|
1075 |
||
1076 |
REQUIREMENTS
|
|
1077 |
- One must have a lock on LOCK_open when calling this
|
|
1078 |
||
1079 |
@param thd Thread handle
|
|
1080 |
@param table_list Names of tables to lock
|
|
1081 |
||
1082 |
@note
|
|
1083 |
If you are just locking one table, you should use
|
|
1084 |
lock_and_wait_for_table_name().
|
|
1085 |
||
1086 |
@retval
|
|
1087 |
0 ok
|
|
1088 |
@retval
|
|
1089 |
1 Fatal error (end of memory ?)
|
|
1090 |
*/
|
|
1091 |
||
1092 |
bool lock_table_names(THD *thd, TABLE_LIST *table_list) |
|
1093 |
{
|
|
1094 |
bool got_all_locks=1; |
|
1095 |
TABLE_LIST *lock_table; |
|
1096 |
||
1097 |
for (lock_table= table_list; lock_table; lock_table= lock_table->next_local) |
|
1098 |
{
|
|
1099 |
int got_lock; |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1100 |
if ((got_lock=lock_table_name(thd,lock_table, true)) < 0) |
1
by brian
clean slate |
1101 |
goto end; // Fatal error |
1102 |
if (got_lock) |
|
1103 |
got_all_locks=0; // Someone is using table |
|
1104 |
}
|
|
1105 |
||
1106 |
/* If some table was in use, wait until we got the lock */
|
|
1107 |
if (!got_all_locks && wait_for_locked_table_names(thd, table_list)) |
|
1108 |
goto end; |
|
1109 |
return 0; |
|
1110 |
||
1111 |
end: |
|
1112 |
unlock_table_names(thd, table_list, lock_table); |
|
1113 |
return 1; |
|
1114 |
}
|
|
1115 |
||
1116 |
||
1117 |
/**
|
|
1118 |
Unlock all tables in list with a name lock.
|
|
1119 |
||
1120 |
@param thd Thread handle.
|
|
1121 |
@param table_list Names of tables to lock.
|
|
1122 |
||
1123 |
@note
|
|
1124 |
This function needs to be protected by LOCK_open. If we're
|
|
1125 |
under LOCK TABLES, this function does not work as advertised. Namely,
|
|
1126 |
it does not exclude other threads from using this table and does not
|
|
1127 |
put an exclusive name lock on this table into the table cache.
|
|
1128 |
||
1129 |
@see lock_table_names
|
|
1130 |
@see unlock_table_names
|
|
1131 |
||
1132 |
@retval TRUE An error occured.
|
|
1133 |
@retval FALSE Name lock successfully acquired.
|
|
1134 |
*/
|
|
1135 |
||
1136 |
bool lock_table_names_exclusively(THD *thd, TABLE_LIST *table_list) |
|
1137 |
{
|
|
1138 |
if (lock_table_names(thd, table_list)) |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1139 |
return true; |
1
by brian
clean slate |
1140 |
|
1141 |
/*
|
|
1142 |
Upgrade the table name locks from semi-exclusive to exclusive locks.
|
|
1143 |
*/
|
|
1144 |
for (TABLE_LIST *table= table_list; table; table= table->next_global) |
|
1145 |
{
|
|
1146 |
if (table->table) |
|
1147 |
table->table->open_placeholder= 1; |
|
1148 |
}
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1149 |
return false; |
1
by brian
clean slate |
1150 |
}
|
1151 |
||
1152 |
||
1153 |
/**
|
|
1154 |
Test is 'table' is protected by an exclusive name lock.
|
|
1155 |
||
1156 |
@param[in] thd The current thread handler
|
|
1157 |
@param[in] table_list Table container containing the single table to be
|
|
1158 |
tested
|
|
1159 |
||
1160 |
@note Needs to be protected by LOCK_open mutex.
|
|
1161 |
||
1162 |
@return Error status code
|
|
1163 |
@retval TRUE Table is protected
|
|
1164 |
@retval FALSE Table is not protected
|
|
1165 |
*/
|
|
1166 |
||
1167 |
bool
|
|
1168 |
is_table_name_exclusively_locked_by_this_thread(THD *thd, |
|
1169 |
TABLE_LIST *table_list) |
|
1170 |
{
|
|
1171 |
char key[MAX_DBKEY_LENGTH]; |
|
1172 |
uint key_length; |
|
1173 |
||
1174 |
key_length= create_table_def_key(thd, key, table_list, 0); |
|
1175 |
||
1176 |
return is_table_name_exclusively_locked_by_this_thread(thd, (uchar *)key, |
|
1177 |
key_length); |
|
1178 |
}
|
|
1179 |
||
1180 |
||
1181 |
/**
|
|
1182 |
Test is 'table key' is protected by an exclusive name lock.
|
|
1183 |
||
1184 |
@param[in] thd The current thread handler.
|
|
1185 |
@param[in] key
|
|
1186 |
@param[in] key_length
|
|
1187 |
||
1188 |
@note Needs to be protected by LOCK_open mutex
|
|
1189 |
||
1190 |
@retval TRUE Table is protected
|
|
1191 |
@retval FALSE Table is not protected
|
|
1192 |
*/
|
|
1193 |
||
1194 |
bool
|
|
1195 |
is_table_name_exclusively_locked_by_this_thread(THD *thd, uchar *key, |
|
1196 |
int key_length) |
|
1197 |
{
|
|
1198 |
HASH_SEARCH_STATE state; |
|
1199 |
TABLE *table; |
|
1200 |
||
1201 |
for (table= (TABLE*) hash_first(&open_cache, key, |
|
1202 |
key_length, &state); |
|
1203 |
table ; |
|
1204 |
table= (TABLE*) hash_next(&open_cache, key, |
|
1205 |
key_length, &state)) |
|
1206 |
{
|
|
1207 |
if (table->in_use == thd && |
|
1208 |
table->open_placeholder == 1 && |
|
1209 |
table->s->version == 0) |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1210 |
return true; |
1
by brian
clean slate |
1211 |
}
|
1212 |
||
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1213 |
return false; |
1
by brian
clean slate |
1214 |
}
|
1215 |
||
1216 |
/**
|
|
1217 |
Unlock all tables in list with a name lock.
|
|
1218 |
||
1219 |
@param
|
|
1220 |
thd Thread handle
|
|
1221 |
@param
|
|
1222 |
table_list Names of tables to unlock
|
|
1223 |
@param
|
|
1224 |
last_table Don't unlock any tables after this one.
|
|
1225 |
(default 0, which will unlock all tables)
|
|
1226 |
||
1227 |
@note
|
|
1228 |
One must have a lock on LOCK_open when calling this.
|
|
1229 |
||
1230 |
@note
|
|
1231 |
This function will broadcast refresh signals to inform other threads
|
|
1232 |
that the name locks are removed.
|
|
1233 |
||
1234 |
@retval
|
|
1235 |
0 ok
|
|
1236 |
@retval
|
|
1237 |
1 Fatal error (end of memory ?)
|
|
1238 |
*/
|
|
1239 |
||
1240 |
void unlock_table_names(THD *thd, TABLE_LIST *table_list, |
|
1241 |
TABLE_LIST *last_table) |
|
1242 |
{
|
|
1243 |
for (TABLE_LIST *table= table_list; |
|
1244 |
table != last_table; |
|
1245 |
table= table->next_local) |
|
1246 |
unlock_table_name(thd,table); |
|
1247 |
broadcast_refresh(); |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1248 |
return; |
1
by brian
clean slate |
1249 |
}
|
1250 |
||
1251 |
||
1252 |
static void print_lock_error(int error, const char *table) |
|
1253 |
{
|
|
1254 |
int textno; |
|
1255 |
||
1256 |
switch (error) { |
|
1257 |
case HA_ERR_LOCK_WAIT_TIMEOUT: |
|
1258 |
textno=ER_LOCK_WAIT_TIMEOUT; |
|
1259 |
break; |
|
1260 |
case HA_ERR_READ_ONLY_TRANSACTION: |
|
1261 |
textno=ER_READ_ONLY_TRANSACTION; |
|
1262 |
break; |
|
1263 |
case HA_ERR_LOCK_DEADLOCK: |
|
1264 |
textno=ER_LOCK_DEADLOCK; |
|
1265 |
break; |
|
1266 |
case HA_ERR_WRONG_COMMAND: |
|
1267 |
textno=ER_ILLEGAL_HA; |
|
1268 |
break; |
|
1269 |
default: |
|
1270 |
textno=ER_CANT_LOCK; |
|
1271 |
break; |
|
1272 |
}
|
|
1273 |
||
1274 |
if ( textno == ER_ILLEGAL_HA ) |
|
1275 |
my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), table); |
|
1276 |
else
|
|
1277 |
my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error); |
|
1278 |
||
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1279 |
return; |
1
by brian
clean slate |
1280 |
}
|
1281 |
||
1282 |
||
1283 |
/****************************************************************************
|
|
1284 |
Handling of global read locks
|
|
1285 |
||
1286 |
Taking the global read lock is TWO steps (2nd step is optional; without
|
|
1287 |
it, COMMIT of existing transactions will be allowed):
|
|
1288 |
lock_global_read_lock() THEN make_global_read_lock_block_commit().
|
|
1289 |
||
1290 |
The global locks are handled through the global variables:
|
|
1291 |
global_read_lock
|
|
1292 |
count of threads which have the global read lock (i.e. have completed at
|
|
1293 |
least the first step above)
|
|
1294 |
global_read_lock_blocks_commit
|
|
1295 |
count of threads which have the global read lock and block
|
|
1296 |
commits (i.e. are in or have completed the second step above)
|
|
1297 |
waiting_for_read_lock
|
|
1298 |
count of threads which want to take a global read lock but cannot
|
|
1299 |
protect_against_global_read_lock
|
|
1300 |
count of threads which have set protection against global read lock.
|
|
1301 |
||
1302 |
access to them is protected with a mutex LOCK_global_read_lock
|
|
1303 |
||
1304 |
(XXX: one should never take LOCK_open if LOCK_global_read_lock is
|
|
1305 |
taken, otherwise a deadlock may occur. Other mutexes could be a
|
|
1306 |
problem too - grep the code for global_read_lock if you want to use
|
|
1307 |
any other mutex here) Also one must not hold LOCK_open when calling
|
|
1308 |
wait_if_global_read_lock(). When the thread with the global read lock
|
|
1309 |
tries to close its tables, it needs to take LOCK_open in
|
|
1310 |
close_thread_table().
|
|
1311 |
||
1312 |
How blocking of threads by global read lock is achieved: that's
|
|
1313 |
advisory. Any piece of code which should be blocked by global read lock must
|
|
1314 |
be designed like this:
|
|
1315 |
- call to wait_if_global_read_lock(). When this returns 0, no global read
|
|
1316 |
lock is owned; if argument abort_on_refresh was 0, none can be obtained.
|
|
1317 |
- job
|
|
1318 |
- if abort_on_refresh was 0, call to start_waiting_global_read_lock() to
|
|
1319 |
allow other threads to get the global read lock. I.e. removal of the
|
|
1320 |
protection.
|
|
1321 |
(Note: it's a bit like an implementation of rwlock).
|
|
1322 |
||
1323 |
[ I am sorry to mention some SQL syntaxes below I know I shouldn't but found
|
|
1324 |
no better descriptive way ]
|
|
1325 |
||
1326 |
Why does FLUSH TABLES WITH READ LOCK need to block COMMIT: because it's used
|
|
1327 |
to read a non-moving SHOW MASTER STATUS, and a COMMIT writes to the binary
|
|
1328 |
log.
|
|
1329 |
||
1330 |
Why getting the global read lock is two steps and not one. Because FLUSH
|
|
1331 |
TABLES WITH READ LOCK needs to insert one other step between the two:
|
|
1332 |
flushing tables. So the order is
|
|
1333 |
1) lock_global_read_lock() (prevents any new table write locks, i.e. stalls
|
|
1334 |
all new updates)
|
|
1335 |
2) close_cached_tables() (the FLUSH TABLES), which will wait for tables
|
|
1336 |
currently opened and being updated to close (so it's possible that there is
|
|
1337 |
a moment where all new updates of server are stalled *and* FLUSH TABLES WITH
|
|
1338 |
READ LOCK is, too).
|
|
1339 |
3) make_global_read_lock_block_commit().
|
|
1340 |
If we have merged 1) and 3) into 1), we would have had this deadlock:
|
|
1341 |
imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
|
|
1342 |
table t.
|
|
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.
|
|
1349 |
||
1350 |
Note that we need to support that one thread does
|
|
1351 |
FLUSH TABLES WITH READ LOCK; and then COMMIT;
|
|
1352 |
(that's what innobackup does, for some good reason).
|
|
1353 |
So in this exceptional case the COMMIT should not be blocked by the FLUSH
|
|
1354 |
TABLES WITH READ LOCK.
|
|
1355 |
||
1356 |
****************************************************************************/
|
|
1357 |
||
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; |
|
1362 |
||
1363 |
#define GOT_GLOBAL_READ_LOCK 1
|
|
1364 |
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
|
|
1365 |
||
1366 |
bool lock_global_read_lock(THD *thd) |
|
1367 |
{
|
|
1368 |
if (!thd->global_read_lock) |
|
1369 |
{
|
|
1370 |
const char *old_message; |
|
1371 |
(void) pthread_mutex_lock(&LOCK_global_read_lock); |
|
1372 |
old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock, |
|
1373 |
"Waiting to get readlock"); |
|
1374 |
||
1375 |
waiting_for_read_lock++; |
|
1376 |
while (protect_against_global_read_lock && !thd->killed) |
|
1377 |
pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock); |
|
1378 |
waiting_for_read_lock--; |
|
1379 |
if (thd->killed) |
|
1380 |
{
|
|
1381 |
thd->exit_cond(old_message); |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1382 |
return(1); |
1
by brian
clean slate |
1383 |
}
|
1384 |
thd->global_read_lock= GOT_GLOBAL_READ_LOCK; |
|
1385 |
global_read_lock++; |
|
1386 |
thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock |
|
1387 |
}
|
|
1388 |
/*
|
|
1389 |
We DON'T set global_read_lock_blocks_commit now, it will be set after
|
|
1390 |
tables are flushed (as the present function serves for FLUSH TABLES WITH
|
|
1391 |
READ LOCK only). Doing things in this order is necessary to avoid
|
|
1392 |
deadlocks (we must allow COMMIT until all tables are closed; we should not
|
|
1393 |
forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
|
|
1394 |
UPDATE and one does FLUSH TABLES WITH READ LOCK).
|
|
1395 |
*/
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1396 |
return(0); |
1
by brian
clean slate |
1397 |
}
|
1398 |
||
1399 |
||
1400 |
void unlock_global_read_lock(THD *thd) |
|
1401 |
{
|
|
1402 |
uint tmp; |
|
1403 |
||
1404 |
pthread_mutex_lock(&LOCK_global_read_lock); |
|
1405 |
tmp= --global_read_lock; |
|
1406 |
if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT) |
|
1407 |
--global_read_lock_blocks_commit; |
|
1408 |
pthread_mutex_unlock(&LOCK_global_read_lock); |
|
1409 |
/* Send the signal outside the mutex to avoid a context switch */
|
|
1410 |
if (!tmp) |
|
1411 |
{
|
|
1412 |
pthread_cond_broadcast(&COND_global_read_lock); |
|
1413 |
}
|
|
1414 |
thd->global_read_lock= 0; |
|
1415 |
||
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1416 |
return; |
1
by brian
clean slate |
1417 |
}
|
1418 |
||
1419 |
#define must_wait (global_read_lock && \
|
|
1420 |
(is_not_commit || \
|
|
1421 |
global_read_lock_blocks_commit))
|
|
1422 |
||
1423 |
bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, |
|
1424 |
bool is_not_commit) |
|
1425 |
{
|
|
1426 |
const char *old_message= NULL; |
|
1427 |
bool result= 0, need_exit_cond; |
|
1428 |
||
1429 |
/*
|
|
1430 |
Assert that we do not own LOCK_open. If we would own it, other
|
|
1431 |
threads could not close their tables. This would make a pretty
|
|
1432 |
deadlock.
|
|
1433 |
*/
|
|
1434 |
safe_mutex_assert_not_owner(&LOCK_open); |
|
1435 |
||
1436 |
(void) pthread_mutex_lock(&LOCK_global_read_lock); |
|
1437 |
if ((need_exit_cond= must_wait)) |
|
1438 |
{
|
|
1439 |
if (thd->global_read_lock) // This thread had the read locks |
|
1440 |
{
|
|
1441 |
if (is_not_commit) |
|
1442 |
my_message(ER_CANT_UPDATE_WITH_READLOCK, |
|
1443 |
ER(ER_CANT_UPDATE_WITH_READLOCK), MYF(0)); |
|
1444 |
(void) pthread_mutex_unlock(&LOCK_global_read_lock); |
|
1445 |
/*
|
|
1446 |
We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
|
|
1447 |
This allowance is needed to not break existing versions of innobackup
|
|
1448 |
which do a BEGIN; INSERT; FLUSH TABLES WITH READ LOCK; COMMIT.
|
|
1449 |
*/
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1450 |
return(is_not_commit); |
1
by brian
clean slate |
1451 |
}
|
1452 |
old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock, |
|
1453 |
"Waiting for release of readlock"); |
|
1454 |
while (must_wait && ! thd->killed && |
|
1455 |
(!abort_on_refresh || thd->version == refresh_version)) |
|
1456 |
{
|
|
1457 |
(void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock); |
|
1458 |
}
|
|
1459 |
if (thd->killed) |
|
1460 |
result=1; |
|
1461 |
}
|
|
1462 |
if (!abort_on_refresh && !result) |
|
1463 |
protect_against_global_read_lock++; |
|
1464 |
/*
|
|
1465 |
The following is only true in case of a global read locks (which is rare)
|
|
1466 |
and if old_message is set
|
|
1467 |
*/
|
|
1468 |
if (unlikely(need_exit_cond)) |
|
1469 |
thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock |
|
1470 |
else
|
|
1471 |
pthread_mutex_unlock(&LOCK_global_read_lock); |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1472 |
return(result); |
1
by brian
clean slate |
1473 |
}
|
1474 |
||
1475 |
||
1476 |
void start_waiting_global_read_lock(THD *thd) |
|
1477 |
{
|
|
1478 |
bool tmp; |
|
1479 |
if (unlikely(thd->global_read_lock)) |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1480 |
return; |
1
by brian
clean slate |
1481 |
(void) pthread_mutex_lock(&LOCK_global_read_lock); |
1482 |
tmp= (!--protect_against_global_read_lock && |
|
1483 |
(waiting_for_read_lock || global_read_lock_blocks_commit)); |
|
1484 |
(void) pthread_mutex_unlock(&LOCK_global_read_lock); |
|
1485 |
if (tmp) |
|
1486 |
pthread_cond_broadcast(&COND_global_read_lock); |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1487 |
return; |
1
by brian
clean slate |
1488 |
}
|
1489 |
||
1490 |
||
1491 |
bool make_global_read_lock_block_commit(THD *thd) |
|
1492 |
{
|
|
1493 |
bool error; |
|
1494 |
const char *old_message; |
|
1495 |
/*
|
|
1496 |
If we didn't succeed lock_global_read_lock(), or if we already suceeded
|
|
1497 |
make_global_read_lock_block_commit(), do nothing.
|
|
1498 |
*/
|
|
1499 |
if (thd->global_read_lock != GOT_GLOBAL_READ_LOCK) |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1500 |
return(0); |
1
by brian
clean slate |
1501 |
pthread_mutex_lock(&LOCK_global_read_lock); |
1502 |
/* increment this BEFORE waiting on cond (otherwise race cond) */
|
|
1503 |
global_read_lock_blocks_commit++; |
|
1504 |
/* For testing we set up some blocking, to see if we can be killed */
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1505 |
protect_against_global_read_lock++; |
1
by brian
clean slate |
1506 |
old_message= thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock, |
1507 |
"Waiting for all running commits to finish"); |
|
1508 |
while (protect_against_global_read_lock && !thd->killed) |
|
1509 |
pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock); |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1510 |
protect_against_global_read_lock--; |
1
by brian
clean slate |
1511 |
if ((error= test(thd->killed))) |
1512 |
global_read_lock_blocks_commit--; // undo what we did |
|
1513 |
else
|
|
1514 |
thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT; |
|
1515 |
thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1516 |
return(error); |
1
by brian
clean slate |
1517 |
}
|
1518 |
||
1519 |
||
1520 |
/**
|
|
1521 |
Broadcast COND_refresh and COND_global_read_lock.
|
|
1522 |
||
1523 |
Due to a bug in a threading library it could happen that a signal
|
|
1524 |
did not reach its target. A condition for this was that the same
|
|
1525 |
condition variable was used with different mutexes in
|
|
1526 |
pthread_cond_wait(). Some time ago we changed LOCK_open to
|
|
1527 |
LOCK_global_read_lock in global read lock handling. So COND_refresh
|
|
1528 |
was used with LOCK_open and LOCK_global_read_lock.
|
|
1529 |
||
1530 |
We did now also change from COND_refresh to COND_global_read_lock
|
|
1531 |
in global read lock handling. But now it is necessary to signal
|
|
1532 |
both conditions at the same time.
|
|
1533 |
||
1534 |
@note
|
|
1535 |
When signalling COND_global_read_lock within the global read lock
|
|
1536 |
handling, it is not necessary to also signal COND_refresh.
|
|
1537 |
*/
|
|
1538 |
||
1539 |
void broadcast_refresh(void) |
|
1540 |
{
|
|
1541 |
VOID(pthread_cond_broadcast(&COND_refresh)); |
|
1542 |
VOID(pthread_cond_broadcast(&COND_global_read_lock)); |
|
1543 |
}
|
|
1544 |
||
1545 |
||
1546 |
/*
|
|
1547 |
Try to get transactional table locks for the tables in the list.
|
|
1548 |
||
1549 |
SYNOPSIS
|
|
1550 |
try_transactional_lock()
|
|
1551 |
thd Thread handle
|
|
1552 |
table_list List of tables to lock
|
|
1553 |
||
1554 |
DESCRIPTION
|
|
1555 |
This is called if transactional table locks are requested for all
|
|
1556 |
tables in table_list and no non-transactional locks pre-exist.
|
|
1557 |
||
1558 |
RETURN
|
|
1559 |
0 OK. All tables are transactional locked.
|
|
1560 |
1 Error: must fall back to non-transactional locks.
|
|
1561 |
-1 Error: no recovery possible.
|
|
1562 |
*/
|
|
1563 |
||
1564 |
int try_transactional_lock(THD *thd, TABLE_LIST *table_list) |
|
1565 |
{
|
|
1566 |
uint dummy_counter; |
|
1567 |
int error; |
|
1568 |
int result= 0; |
|
1569 |
||
1570 |
/* Need to open the tables to be able to access engine methods. */
|
|
1571 |
if (open_tables(thd, &table_list, &dummy_counter, 0)) |
|
1572 |
{
|
|
1573 |
/* purecov: begin tested */
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1574 |
return(-1); |
1
by brian
clean slate |
1575 |
/* purecov: end */
|
1576 |
}
|
|
1577 |
||
1578 |
/* Required by InnoDB. */
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1579 |
thd->in_lock_tables= true; |
1
by brian
clean slate |
1580 |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1581 |
if ((error= set_handler_table_locks(thd, table_list, true))) |
1
by brian
clean slate |
1582 |
{
|
1583 |
/*
|
|
1584 |
Not all transactional locks could be taken. If the error was
|
|
1585 |
something else but "unsupported by storage engine", abort the
|
|
1586 |
execution of this statement.
|
|
1587 |
*/
|
|
1588 |
if (error != HA_ERR_WRONG_COMMAND) |
|
1589 |
{
|
|
1590 |
result= -1; |
|
1591 |
goto err; |
|
1592 |
}
|
|
1593 |
/*
|
|
1594 |
Fall back to non-transactional locks because transactional locks
|
|
1595 |
are unsupported by a storage engine. No need to unlock the
|
|
1596 |
successfully taken transactional locks. They go away at end of
|
|
1597 |
transaction anyway.
|
|
1598 |
*/
|
|
1599 |
result= 1; |
|
1600 |
}
|
|
1601 |
||
1602 |
err: |
|
1603 |
/* We need to explicitly commit if autocommit mode is active. */
|
|
1604 |
(void) ha_autocommit_or_rollback(thd, 0); |
|
1605 |
/* Close the tables. The locks (if taken) persist in the storage engines. */
|
|
1606 |
close_tables_for_reopen(thd, &table_list); |
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1607 |
thd->in_lock_tables= false; |
1608 |
return(result); |
|
1
by brian
clean slate |
1609 |
}
|
1610 |
||
1611 |
||
1612 |
/*
|
|
1613 |
Check if lock method conversion was done and was allowed.
|
|
1614 |
||
1615 |
SYNOPSIS
|
|
1616 |
check_transactional_lock()
|
|
1617 |
thd Thread handle
|
|
1618 |
table_list List of tables to lock
|
|
1619 |
||
1620 |
DESCRIPTION
|
|
1621 |
||
1622 |
Lock method conversion can be done during parsing if one of the
|
|
1623 |
locks is non-transactional. It can also happen if non-transactional
|
|
1624 |
table locks exist when the statement is executed or if a storage
|
|
1625 |
engine does not support transactional table locks.
|
|
1626 |
||
1627 |
Check if transactional table locks have been converted to
|
|
1628 |
non-transactional and if this was allowed. In a running transaction
|
|
1629 |
or in strict mode lock method conversion is not allowed - report an
|
|
1630 |
error. Otherwise it is allowed - issue a warning.
|
|
1631 |
||
1632 |
RETURN
|
|
1633 |
0 OK. Proceed with non-transactional locks.
|
|
1634 |
-1 Error: Lock conversion is prohibited.
|
|
1635 |
*/
|
|
1636 |
||
1637 |
int check_transactional_lock(THD *thd, TABLE_LIST *table_list) |
|
1638 |
{
|
|
1639 |
TABLE_LIST *tlist; |
|
1640 |
int result= 0; |
|
1641 |
char warn_buff[MYSQL_ERRMSG_SIZE]; |
|
1642 |
||
1643 |
for (tlist= table_list; tlist; tlist= tlist->next_global) |
|
1644 |
{
|
|
1645 |
||
1646 |
/*
|
|
1647 |
Unfortunately we cannot use tlist->placeholder() here. This method
|
|
1648 |
returns TRUE if the table is not open, which is always the case
|
|
1649 |
here. Whenever the definition of TABLE_LIST::placeholder() is
|
|
1650 |
changed, probably this condition needs to be changed too.
|
|
1651 |
*/
|
|
1652 |
if (tlist->derived || tlist->schema_table || !tlist->lock_transactional) |
|
1653 |
{
|
|
1654 |
continue; |
|
1655 |
}
|
|
1656 |
||
1657 |
/* We must not convert the lock method in strict mode. */
|
|
1658 |
{
|
|
1659 |
my_error(ER_NO_AUTO_CONVERT_LOCK_STRICT, MYF(0), |
|
1660 |
tlist->alias ? tlist->alias : tlist->table_name); |
|
1661 |
result= -1; |
|
1662 |
continue; |
|
1663 |
}
|
|
1664 |
||
1665 |
/* We must not convert the lock method within an active transaction. */
|
|
1666 |
if (thd->active_transaction()) |
|
1667 |
{
|
|
1668 |
my_error(ER_NO_AUTO_CONVERT_LOCK_TRANSACTION, MYF(0), |
|
1669 |
tlist->alias ? tlist->alias : tlist->table_name); |
|
1670 |
result= -1; |
|
1671 |
continue; |
|
1672 |
}
|
|
1673 |
||
1674 |
/* Warn about the conversion. */
|
|
77.1.18
by Monty Taylor
Removed my_vsnprintf and my_snprintf. |
1675 |
snprintf(warn_buff, sizeof(warn_buff), ER(ER_WARN_AUTO_CONVERT_LOCK), |
1676 |
tlist->alias ? tlist->alias : tlist->table_name); |
|
1
by brian
clean slate |
1677 |
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, |
1678 |
ER_WARN_AUTO_CONVERT_LOCK, warn_buff); |
|
1679 |
}
|
|
1680 |
||
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1681 |
return(result); |
1
by brian
clean slate |
1682 |
}
|
1683 |
||
1684 |
||
1685 |
/*
|
|
1686 |
Set table locks in the table handler.
|
|
1687 |
||
1688 |
SYNOPSIS
|
|
1689 |
set_handler_table_locks()
|
|
1690 |
thd Thread handle
|
|
1691 |
table_list List of tables to lock
|
|
1692 |
transactional If to lock transactional or non-transactional
|
|
1693 |
||
1694 |
RETURN
|
|
1695 |
0 OK.
|
|
1696 |
!= 0 Error code from handler::lock_table().
|
|
1697 |
*/
|
|
1698 |
||
1699 |
int set_handler_table_locks(THD *thd, TABLE_LIST *table_list, |
|
1700 |
bool transactional) |
|
1701 |
{
|
|
1702 |
TABLE_LIST *tlist; |
|
1703 |
int error= 0; |
|
1704 |
||
1705 |
for (tlist= table_list; tlist; tlist= tlist->next_global) |
|
1706 |
{
|
|
1707 |
int lock_type; |
|
1708 |
int lock_timeout= -1; /* Use default for non-transactional locks. */ |
|
1709 |
||
1710 |
if (tlist->placeholder()) |
|
1711 |
continue; |
|
1712 |
||
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1713 |
assert((tlist->lock_type == TL_READ) || |
1
by brian
clean slate |
1714 |
(tlist->lock_type == TL_READ_NO_INSERT) || |
1715 |
(tlist->lock_type == TL_WRITE_DEFAULT) || |
|
1716 |
(tlist->lock_type == TL_WRITE) || |
|
1717 |
(tlist->lock_type == TL_WRITE_LOW_PRIORITY)); |
|
1718 |
||
1719 |
/*
|
|
1720 |
Every tlist object has a proper lock_type set. Even if it came in
|
|
1721 |
the list as a base table from a view only.
|
|
1722 |
*/
|
|
1723 |
lock_type= ((tlist->lock_type <= TL_READ_NO_INSERT) ? |
|
1724 |
HA_LOCK_IN_SHARE_MODE : HA_LOCK_IN_EXCLUSIVE_MODE); |
|
1725 |
||
1726 |
if (transactional) |
|
1727 |
{
|
|
1728 |
/*
|
|
1729 |
The lock timeout is not set if this table belongs to a view. We
|
|
1730 |
need to take it from the top-level view. After this loop
|
|
1731 |
iteration, lock_timeout is not needed any more. Not even if the
|
|
1732 |
locks are converted to non-transactional locks later.
|
|
1733 |
Non-transactional locks do not support a lock_timeout.
|
|
1734 |
*/
|
|
1735 |
lock_timeout= tlist->top_table()->lock_timeout; |
|
1736 |
||
1737 |
/*
|
|
1738 |
For warning/error reporting we need to set the intended lock
|
|
1739 |
method in the TABLE_LIST object. It will be used later by
|
|
1740 |
check_transactional_lock(). The lock method is not set if this
|
|
1741 |
table belongs to a view. We can safely set it to transactional
|
|
1742 |
locking here. Even for non-view tables. This function is not
|
|
1743 |
called if non-transactional locking was requested for any
|
|
1744 |
object.
|
|
1745 |
*/
|
|
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1746 |
tlist->lock_transactional= true; |
1
by brian
clean slate |
1747 |
}
|
1748 |
||
1749 |
/*
|
|
1750 |
Because we need to set the lock method (see above) for all
|
|
1751 |
involved tables, we cannot break the loop on an error.
|
|
1752 |
But we do not try more locks after the first error.
|
|
1753 |
However, for non-transactional locking handler::lock_table() is
|
|
1754 |
a hint only. So we continue to call it for other tables.
|
|
1755 |
*/
|
|
1756 |
if (!error || !transactional) |
|
1757 |
{
|
|
1758 |
error= tlist->table->file->lock_table(thd, lock_type, lock_timeout); |
|
1759 |
if (error && transactional && (error != HA_ERR_WRONG_COMMAND)) |
|
1760 |
tlist->table->file->print_error(error, MYF(0)); |
|
1761 |
}
|
|
1762 |
}
|
|
1763 |
||
51.1.27
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
1764 |
return(error); |
1
by brian
clean slate |
1765 |
}
|
1766 |
||
1767 |
||
1768 |
/**
|
|
1769 |
@} (end of group Locking)
|
|
1770 |
*/
|