~drizzle-trunk/drizzle/development

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