1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
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; either version 2 of the License, or
6
(at your option) any later version.
8
This program is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License
14
along with this program; if not, write to the Free Software
15
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18
/* locking functions for mysql */
20
Because of the new concurrent inserts, we must first get external locks
21
before getting internal locks. If we do it in the other order, the status
22
information is not up to date when called from the lock handler.
25
Change to use my_malloc() ONLY when using LOCK TABLES command or when
26
we are forced to use mysql_lock_merge.
29
#include "mysql_priv.h"
32
extern HASH open_cache;
34
static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
35
bool unlock, TABLE **write_locked);
36
static int lock_external(TABLE **table,uint count);
37
static int unlock_external(THD *thd, TABLE **table,uint count);
40
MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
43
TABLE *write_lock_used;
44
DBUG_ENTER("mysql_lock_tables");
48
if (!(sql_lock = get_lock_data(thd,tables,count, 0,&write_lock_used)))
51
if (global_read_lock && write_lock_used)
54
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
55
Wait until the lock is gone
57
if (thd->global_read_lock) // This thread had the read locks
59
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,MYF(0),
60
write_lock_used->table_name);
61
my_free((gptr) sql_lock,MYF(0));
66
pthread_mutex_lock(&LOCK_open);
67
pthread_mutex_lock(&thd->mysys_var->mutex);
68
thd->mysys_var->current_mutex= &LOCK_open;
69
thd->mysys_var->current_cond= &COND_refresh;
70
thd->proc_info="Waiting for table";
71
pthread_mutex_unlock(&thd->mysys_var->mutex);
73
while (global_read_lock && ! thd->killed ||
74
thd->version != refresh_version)
76
(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
78
pthread_mutex_unlock(&LOCK_open);
79
pthread_mutex_lock(&thd->mysys_var->mutex);
80
thd->mysys_var->current_mutex= 0;
81
thd->mysys_var->current_cond= 0;
83
pthread_mutex_unlock(&thd->mysys_var->mutex);
85
if (thd->version != refresh_version || thd->killed)
87
my_free((gptr) sql_lock,MYF(0));
92
thd->proc_info="System lock";
93
if (lock_external(tables,count))
95
my_free((gptr) sql_lock,MYF(0));
102
if (thr_multi_lock(sql_lock->locks,sql_lock->lock_count))
104
thd->some_tables_deleted=1; // Try again
105
sql_lock->lock_count=0; // Locks are alread freed
107
else if (!thd->some_tables_deleted)
113
/* some table was altered or deleted. reopen tables marked deleted */
114
mysql_unlock_tables(thd,sql_lock);
118
if (wait_for_tables(thd))
119
break; // Couldn't open tables
123
my_error(ER_SERVER_SHUTDOWN,MYF(0));
126
mysql_unlock_tables(thd,sql_lock);
130
DBUG_RETURN (sql_lock);
134
static int lock_external(TABLE **tables,uint count)
138
THD *thd=current_thd;
139
DBUG_ENTER("lock_external");
141
for (i=1 ; i <= count ; i++, tables++)
143
lock_type=F_WRLCK; /* Lock exclusive */
144
if ((*tables)->db_stat & HA_READ_ONLY ||
145
((*tables)->reginfo.lock_type >= TL_READ &&
146
(*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
149
if ((error=(*tables)->file->external_lock(thd,lock_type)))
151
for ( ; i-- ; tables--)
153
(*tables)->file->external_lock(thd, F_UNLCK);
154
(*tables)->current_lock=F_UNLCK;
156
my_error(ER_CANT_LOCK,MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG),error);
161
(*tables)->db_stat &= ~ HA_BLOCK_LOCK;
162
(*tables)->current_lock= lock_type;
169
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
171
DBUG_ENTER("mysql_unlock_tables");
172
thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
173
VOID(unlock_external(thd,sql_lock->table,sql_lock->table_count));
174
my_free((gptr) sql_lock,MYF(0));
179
Unlock some of the tables locked by mysql_lock_tables
180
This will work even if get_lock_data fails (next unlock will free all)
183
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count)
185
MYSQL_LOCK *sql_lock;
186
TABLE *write_lock_used;
187
if ((sql_lock = get_lock_data(thd, table, count, 1, &write_lock_used)))
188
mysql_unlock_tables(thd, sql_lock);
193
** unlock all tables locked for read.
196
void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
199
DBUG_ENTER("mysql_unlock_read_tables");
201
/* Move all write locks first */
202
THR_LOCK_DATA **lock=sql_lock->locks;
203
for (i=found=0 ; i < sql_lock->lock_count ; i++)
205
if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_READ)
207
swap(THR_LOCK_DATA *,*lock,sql_lock->locks[i]);
212
/* unlock the read locked tables */
215
thr_multi_unlock(lock,i-found);
216
sql_lock->lock_count-=found;
219
/* Then to the same for the external locks */
220
/* Move all write locked tables first */
221
TABLE **table=sql_lock->table;
222
for (i=found=0 ; i < sql_lock->table_count ; i++)
224
if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
226
swap(TABLE *,*table,sql_lock->table[i]);
231
/* Unlock all read locked tables */
234
VOID(unlock_external(thd,table,i-found));
235
sql_lock->table_count-=found;
242
void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table)
244
mysql_unlock_some_tables(thd, &table,1);
248
for (i=0; i < locked->table_count; i++)
250
if (locked->table[i] == table)
252
locked->table_count--;
253
bmove((char*) (locked->table+i),
254
(char*) (locked->table+i+1),
255
(locked->table_count-i)* sizeof(TABLE*));
259
THR_LOCK_DATA **prev=locked->locks;
260
for (i=0 ; i < locked->lock_count ; i++)
262
if (locked->locks[i]->type != TL_UNLOCK)
263
*prev++ = locked->locks[i];
265
locked->lock_count=(prev - locked->locks);
269
/* abort all other threads waiting to get lock in table */
271
void mysql_lock_abort(THD *thd, TABLE *table)
274
TABLE *write_lock_used;
275
if ((locked = get_lock_data(thd,&table,1,1,&write_lock_used)))
277
for (uint i=0; i < locked->lock_count; i++)
278
thr_abort_locks(locked->locks[i]->lock);
279
my_free((gptr) locked,MYF(0));
284
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
286
MYSQL_LOCK *sql_lock;
287
DBUG_ENTER("mysql_lock_merge");
288
if (!(sql_lock= (MYSQL_LOCK*)
289
my_malloc(sizeof(*sql_lock)+
290
sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+
291
sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME))))
292
DBUG_RETURN(0); // Fatal error
293
sql_lock->lock_count=a->lock_count+b->lock_count;
294
sql_lock->table_count=a->table_count+b->table_count;
295
sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
296
sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count);
297
memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
298
memcpy(sql_lock->locks+a->lock_count,b->locks,
299
b->lock_count*sizeof(*b->locks));
300
memcpy(sql_lock->table,a->table,a->table_count*sizeof(*a->table));
301
memcpy(sql_lock->table+a->table_count,b->table,
302
b->table_count*sizeof(*b->table));
303
my_free((gptr) a,MYF(0));
304
my_free((gptr) b,MYF(0));
305
DBUG_RETURN(sql_lock);
309
/* unlock a set of external */
311
static int unlock_external(THD *thd, TABLE **table,uint count)
313
int error,error_code;
314
DBUG_ENTER("unlock_external");
317
for (; count-- ; table++)
319
if ((*table)->current_lock != F_UNLCK)
321
(*table)->current_lock = F_UNLCK;
322
if ((error=(*table)->file->external_lock(thd, F_UNLCK)))
327
my_error(ER_CANT_LOCK,MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG),error_code);
328
DBUG_RETURN(error_code);
333
** Get lock structures from table structs and initialize locks
337
static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
338
bool get_old_locks, TABLE **write_lock_used)
340
uint i,tables,lock_count;
341
MYSQL_LOCK *sql_lock;
342
THR_LOCK_DATA **locks;
346
for (i=tables=lock_count=0 ; i < count ; i++)
348
if (!table_ptr[i]->tmp_table)
350
tables+=table_ptr[i]->file->lock_count();
355
if (!(sql_lock= (MYSQL_LOCK*)
356
my_malloc(sizeof(*sql_lock)+
357
sizeof(THR_LOCK_DATA*)*tables+sizeof(table_ptr)*lock_count,
360
locks=sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
361
to=sql_lock->table=(TABLE**) (locks+tables);
362
sql_lock->table_count=lock_count;
363
sql_lock->lock_count=tables;
365
for (i=0 ; i < count ; i++)
368
if ((table=table_ptr[i])->tmp_table)
371
enum thr_lock_type lock_type= table->reginfo.lock_type;
372
if (lock_type >= TL_WRITE_ALLOW_WRITE)
374
*write_lock_used=table;
375
if (table->db_stat & HA_READ_ONLY)
377
my_error(ER_OPEN_AS_READONLY,MYF(0),table->table_name);
378
my_free((gptr) sql_lock,MYF(0));
382
locks=table->file->store_lock(thd, locks, get_old_locks ? TL_IGNORE :