~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/lock.cc

  • Committer: Brian Aker
  • Date: 2010-02-07 01:33:54 UTC
  • Revision ID: brian@gaz-20100207013354-d2pg1n68u5c09pgo
Remove giant include header to its own file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
  - For each SQL statement mysql_lock_tables() is called for all involved
31
31
    tables.
32
32
    - mysql_lock_tables() will call
33
 
      table_handler->external_lock(thd,locktype) for each table.
 
33
      table_handler->external_lock(session,locktype) for each table.
34
34
      This is followed by a call to thr_multi_lock() for all tables.
35
35
 
36
36
  - When statement is done, we call mysql_unlock_tables().
37
37
    This will call thr_multi_unlock() followed by
38
 
    table_handler->external_lock(thd, F_UNLCK) for each table.
 
38
    table_handler->external_lock(session, F_UNLCK) for each table.
39
39
 
40
40
  - Note that mysql_unlock_tables() may be called several times as
41
41
    MySQL in some cases can free some tables earlier than others.
43
43
  - The above is true both for normal and temporary tables.
44
44
 
45
45
  - Temporary non transactional tables are never passed to thr_multi_lock()
46
 
    and we never call external_lock(thd, F_UNLOCK) on these.
 
46
    and we never call external_lock(session, F_UNLOCK) on these.
47
47
 
48
48
  When using LOCK TABLES:
49
49
 
50
 
  - LOCK TABLE will call mysql_lock_tables() for all tables.
 
50
  - LOCK Table will call mysql_lock_tables() for all tables.
51
51
    mysql_lock_tables() will call
52
 
    table_handler->external_lock(thd,locktype) for each table.
 
52
    table_handler->external_lock(session,locktype) for each table.
53
53
    This is followed by a call to thr_multi_lock() for all tables.
54
54
 
55
 
  - For each statement, we will call table_handler->start_stmt(THD)
 
55
  - For each statement, we will call table_handler->start_stmt(Session)
56
56
    to inform the table handler that we are using the table.
57
57
 
58
58
    The tables used can only be tables used in LOCK TABLES or a
59
59
    temporary table.
60
60
 
61
 
  - When statement is done, we will call ha_commit_stmt(thd);
 
61
  - When statement is done, we will call ha_commit_stmt(session);
62
62
 
63
63
  - When calling UNLOCK TABLES we call mysql_unlock_tables() for all
64
64
    tables used in LOCK TABLES
65
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,
 
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,
68
68
  excluding one that caused failure. That means handler must cleanup itself
69
69
  in case external_lock() fails.
70
70
 
71
71
  @todo
72
 
  Change to use my_malloc() ONLY when using LOCK TABLES command or when
 
72
  Change to use malloc() ONLY when using LOCK TABLES command or when
73
73
  we are forced to use mysql_lock_merge.
74
74
*/
75
 
#include <drizzled/server_includes.h>
76
 
#include <drizzled/drizzled_error_messages.h>
 
75
#include "config.h"
 
76
#include <fcntl.h>
 
77
#include <drizzled/error.h>
 
78
#include <drizzled/my_hash.h>
 
79
#include <drizzled/thr_lock.h>
 
80
#include <drizzled/session.h>
 
81
#include <drizzled/sql_base.h>
 
82
#include <drizzled/lock.h>
 
83
#include "drizzled/pthread_globals.h"
 
84
#include "drizzled/internal/my_sys.h"
 
85
 
 
86
namespace drizzled
 
87
{
77
88
 
78
89
/**
79
90
  @defgroup Locking Locking
82
93
 
83
94
extern HASH open_cache;
84
95
 
85
 
/* flags for get_lock_data */
86
 
#define GET_LOCK_UNLOCK         1
87
 
#define GET_LOCK_STORE_LOCKS    2
88
 
 
89
 
static DRIZZLE_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
90
 
                                 uint flags, TABLE **write_locked);
91
 
static int lock_external(THD *thd, TABLE **table,uint count);
92
 
static int unlock_external(THD *thd, TABLE **table,uint count);
 
96
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table,
 
97
                                   uint32_t count,
 
98
                                   bool should_lock, Table **write_locked);
 
99
static int lock_external(Session *session, Table **table,uint32_t count);
 
100
static int unlock_external(Session *session, Table **table,uint32_t count);
93
101
static void print_lock_error(int error, const char *);
94
102
 
95
103
/*
97
105
 
98
106
  SYNOPSIS
99
107
    mysql_lock_tables()
100
 
    thd                         The current thread.
 
108
    session                         The current thread.
101
109
    tables                      An array of pointers to the tables to lock.
102
110
    count                       The number of tables to lock.
103
111
    flags                       Options:
104
112
      DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK      Ignore a global read lock
105
 
      DRIZZLE_LOCK_IGNORE_GLOBAL_READ_ONLY      Ignore SET GLOBAL READ_ONLY
106
113
      DRIZZLE_LOCK_IGNORE_FLUSH                 Ignore a flush tables.
107
114
      DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN        Instead of reopening altered
108
115
                                              or dropped tables by itself,
155
162
    /* Reset lock type. */
156
163
    (*ldata)->type= TL_UNLOCK;
157
164
  }
158
 
  my_free((uchar*) sql_lock, MYF(0));
 
165
  free((unsigned char*) sql_lock);
159
166
  *mysql_lock= 0;
160
167
}
161
168
 
162
169
 
163
 
DRIZZLE_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
164
 
                              uint flags, bool *need_reopen)
 
170
DRIZZLE_LOCK *mysql_lock_tables(Session *session, Table **tables, uint32_t count,
 
171
                                uint32_t flags, bool *need_reopen)
165
172
{
166
173
  DRIZZLE_LOCK *sql_lock;
167
 
  TABLE *write_lock_used;
 
174
  Table *write_lock_used;
168
175
  int rc;
169
176
 
170
177
  *need_reopen= false;
171
178
 
172
179
  for (;;)
173
180
  {
174
 
    if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS,
 
181
    if (! (sql_lock= get_lock_data(session, tables, count, true,
175
182
                                   &write_lock_used)))
176
183
      break;
177
184
 
182
189
        Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
183
190
        Wait until the lock is gone
184
191
      */
185
 
      if (wait_if_global_read_lock(thd, 1, 1))
 
192
      if (wait_if_global_read_lock(session, 1, 1))
186
193
      {
187
194
        /* Clear the lock type of all lock data to avoid reusage. */
188
195
        reset_lock_data_and_free(&sql_lock);
189
196
        break;
190
197
      }
191
 
      if (thd->version != refresh_version)
 
198
      if (session->version != refresh_version)
192
199
      {
193
200
        /* Clear the lock type of all lock data to avoid reusage. */
194
201
        reset_lock_data_and_free(&sql_lock);
196
203
      }
197
204
    }
198
205
 
199
 
    if (!(flags & DRIZZLE_LOCK_IGNORE_GLOBAL_READ_ONLY) &&
200
 
        write_lock_used &&
201
 
        opt_readonly &&
202
 
        !thd->slave_thread)
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
 
 
213
 
    thd_proc_info(thd, "System lock");
214
 
    if (sql_lock->table_count && lock_external(thd, sql_lock->table,
 
206
    session->set_proc_info("System lock");
 
207
    if (sql_lock->table_count && lock_external(session, sql_lock->table,
215
208
                                               sql_lock->table_count))
216
209
    {
217
210
      /* Clear the lock type of all lock data to avoid reusage. */
218
211
      reset_lock_data_and_free(&sql_lock);
219
212
      break;
220
213
    }
221
 
    thd_proc_info(thd, "Table lock");
 
214
    session->set_proc_info("Table lock");
222
215
    /* Copy the lock data array. thr_multi_lock() reorders its contens. */
223
216
    memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
224
217
           sql_lock->lock_count * sizeof(*sql_lock->locks));
226
219
    rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
227
220
                                                     sql_lock->lock_count,
228
221
                                                     sql_lock->lock_count,
229
 
                                                     thd->lock_id)];
 
222
                                                     session->lock_id)];
230
223
    if (rc > 1)                                 /* a timeout or a deadlock */
231
224
    {
232
225
      if (sql_lock->table_count)
233
 
        VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
 
226
        unlock_external(session, sql_lock->table, sql_lock->table_count);
234
227
      reset_lock_data_and_free(&sql_lock);
235
228
      my_error(rc, MYF(0));
236
229
      break;
237
230
    }
238
231
    else if (rc == 1)                           /* aborted */
239
232
    {
240
 
      thd->some_tables_deleted=1;               // Try again
 
233
      session->some_tables_deleted=1;           // Try again
241
234
      sql_lock->lock_count= 0;                  // Locks are already freed
242
235
      // Fall through: unlock, reset lock data, free and retry
243
236
    }
244
 
    else if (!thd->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
 
237
    else if (!session->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
245
238
    {
246
239
      /*
247
240
        Thread was killed or lock aborted. Let upper level close all
249
242
      */
250
243
      break;
251
244
    }
252
 
    else if (!thd->open_tables)
 
245
    else if (!session->open_tables)
253
246
    {
254
247
      // Only using temporary tables, no need to unlock
255
 
      thd->some_tables_deleted=0;
 
248
      session->some_tables_deleted= 0;
256
249
      break;
257
250
    }
258
 
    thd_proc_info(thd, 0);
 
251
    session->set_proc_info(0);
259
252
 
260
253
    /* going to retry, unlock all tables */
261
254
    if (sql_lock->lock_count)
262
255
        thr_multi_unlock(sql_lock->locks, sql_lock->lock_count);
263
256
 
264
257
    if (sql_lock->table_count)
265
 
      VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
 
258
      unlock_external(session, sql_lock->table, sql_lock->table_count);
266
259
 
267
260
    /*
268
261
      If thr_multi_lock fails it resets lock type for tables, which
276
269
      *need_reopen= true;
277
270
      break;
278
271
    }
279
 
    if (wait_for_tables(thd))
 
272
    if (wait_for_tables(session))
280
273
      break;                                    // Couldn't open tables
281
274
  }
282
 
  thd_proc_info(thd, 0);
283
 
  if (thd->killed)
 
275
  session->set_proc_info(0);
 
276
  if (session->killed)
284
277
  {
285
 
    thd->send_kill_message();
 
278
    session->send_kill_message();
286
279
    if (sql_lock)
287
280
    {
288
 
      mysql_unlock_tables(thd,sql_lock);
289
 
      sql_lock=0;
 
281
      mysql_unlock_tables(session,sql_lock);
 
282
      sql_lock= NULL;
290
283
    }
291
284
  }
292
285
 
293
 
  thd->set_time_after_lock();
 
286
  session->set_time_after_lock();
294
287
  return (sql_lock);
295
288
}
296
289
 
297
290
 
298
 
static int lock_external(THD *thd, TABLE **tables, uint count)
 
291
static int lock_external(Session *session, Table **tables, uint32_t count)
299
292
{
300
 
  register uint i;
 
293
  register uint32_t i;
301
294
  int lock_type,error;
302
295
  for (i=1 ; i <= count ; i++, tables++)
303
296
  {
308
301
         (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
309
302
      lock_type=F_RDLCK;
310
303
 
311
 
    if ((error=(*tables)->file->ha_external_lock(thd,lock_type)))
 
304
    if ((error=(*tables)->cursor->ha_external_lock(session,lock_type)))
312
305
    {
313
 
      print_lock_error(error, (*tables)->file->table_type());
 
306
      print_lock_error(error, (*tables)->cursor->engine->getName().c_str());
314
307
      while (--i)
315
308
      {
316
309
        tables--;
317
 
        (*tables)->file->ha_external_lock(thd, F_UNLCK);
 
310
        (*tables)->cursor->ha_external_lock(session, F_UNLCK);
318
311
        (*tables)->current_lock=F_UNLCK;
319
312
      }
320
 
      return(error);
 
313
      return error;
321
314
    }
322
315
    else
323
316
    {
325
318
      (*tables)->current_lock= lock_type;
326
319
    }
327
320
  }
328
 
  return(0);
 
321
  return 0;
329
322
}
330
323
 
331
324
 
332
 
void mysql_unlock_tables(THD *thd, DRIZZLE_LOCK *sql_lock)
 
325
void mysql_unlock_tables(Session *session, DRIZZLE_LOCK *sql_lock)
333
326
{
334
327
  if (sql_lock->lock_count)
335
328
    thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
336
329
  if (sql_lock->table_count)
337
 
    VOID(unlock_external(thd,sql_lock->table,sql_lock->table_count));
338
 
  my_free((uchar*) sql_lock,MYF(0));
 
330
    unlock_external(session,sql_lock->table,sql_lock->table_count);
 
331
  free((unsigned char*) sql_lock);
339
332
  return;
340
333
}
341
334
 
345
338
  This will work even if get_lock_data fails (next unlock will free all)
346
339
*/
347
340
 
348
 
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count)
 
341
void mysql_unlock_some_tables(Session *session, Table **table, uint32_t count)
349
342
{
350
343
  DRIZZLE_LOCK *sql_lock;
351
 
  TABLE *write_lock_used;
352
 
  if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK,
 
344
  Table *write_lock_used;
 
345
  if ((sql_lock= get_lock_data(session, table, count, false,
353
346
                               &write_lock_used)))
354
 
    mysql_unlock_tables(thd, sql_lock);
 
347
    mysql_unlock_tables(session, sql_lock);
355
348
}
356
349
 
357
350
 
359
352
  unlock all tables locked for read.
360
353
*/
361
354
 
362
 
void mysql_unlock_read_tables(THD *thd, DRIZZLE_LOCK *sql_lock)
 
355
void mysql_unlock_read_tables(Session *session, DRIZZLE_LOCK *sql_lock)
363
356
{
364
 
  uint i,found;
 
357
  uint32_t i,found;
365
358
 
366
359
  /* Move all write locks first */
367
360
  THR_LOCK_DATA **lock=sql_lock->locks;
369
362
  {
370
363
    if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_READ)
371
364
    {
372
 
      swap_variables(THR_LOCK_DATA *, *lock, sql_lock->locks[i]);
 
365
      std::swap(*lock, sql_lock->locks[i]);
373
366
      lock++;
374
367
      found++;
375
368
    }
383
376
 
384
377
  /* Then do the same for the external locks */
385
378
  /* Move all write locked tables first */
386
 
  TABLE **table=sql_lock->table;
 
379
  Table **table=sql_lock->table;
387
380
  for (i=found=0 ; i < sql_lock->table_count ; i++)
388
381
  {
389
382
    assert(sql_lock->table[i]->lock_position == i);
390
 
    if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
 
383
    if ((uint32_t) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
391
384
    {
392
 
      swap_variables(TABLE *, *table, sql_lock->table[i]);
 
385
      std::swap(*table, sql_lock->table[i]);
393
386
      table++;
394
387
      found++;
395
388
    }
397
390
  /* Unlock all read locked tables */
398
391
  if (i != found)
399
392
  {
400
 
    VOID(unlock_external(thd,table,i-found));
 
393
    unlock_external(session,table,i-found);
401
394
    sql_lock->table_count=found;
402
395
  }
403
 
  /* Fix the lock positions in TABLE */
 
396
  /* Fix the lock positions in Table */
404
397
  table= sql_lock->table;
405
398
  found= 0;
406
399
  for (i= 0; i < sql_lock->table_count; i++)
407
400
  {
408
 
    TABLE *tbl= *table;
 
401
    Table *tbl= *table;
409
402
    tbl->lock_position= table - sql_lock->table;
410
403
    tbl->lock_data_start= found;
411
404
    found+= tbl->lock_count;
428
421
  unlock_external() we call handler::external_lock(F_UNLCK) only
429
422
  if table->current_lock is not F_UNLCK.
430
423
 
431
 
  @param  thd             thread context
 
424
  @param  session             thread context
432
425
  @param  locked          list of locked tables
433
426
  @param  table           the table to unlock
434
427
  @param  always_unlock   specify explicitly if the legacy side
435
428
                          effect is desired.
436
429
*/
437
430
 
438
 
void mysql_lock_remove(THD *thd, DRIZZLE_LOCK *locked,TABLE *table,
439
 
                       bool always_unlock)
440
 
{
441
 
  if (always_unlock == true)
442
 
    mysql_unlock_some_tables(thd, &table, /* table count */ 1);
443
 
  if (locked)
444
 
  {
445
 
    register uint i;
446
 
    for (i=0; i < locked->table_count; i++)
447
 
    {
448
 
      if (locked->table[i] == table)
449
 
      {
450
 
        uint  j, removed_locks, old_tables;
451
 
        TABLE *tbl;
452
 
        uint lock_data_end;
453
 
 
454
 
        assert(table->lock_position == i);
455
 
 
456
 
        /* Unlock if not yet unlocked */
457
 
        if (always_unlock == false)
458
 
          mysql_unlock_some_tables(thd, &table, /* table count */ 1);
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'. */
467
 
        memcpy((locked->table+i), (locked->table+i+1),
468
 
               (old_tables - i) * sizeof(TABLE*));
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' */
472
 
        memcpy((locked->locks + table->lock_data_start),
473
 
               (locked->locks + lock_data_end),
474
 
               (locked->lock_count - lock_data_end) *
475
 
               sizeof(THR_LOCK_DATA*));
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--;
489
 
          assert(tbl->lock_position == j);
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
 
 
503
 
void mysql_lock_downgrade_write(THD *thd, TABLE *table,
504
 
                                thr_lock_type new_lock_type)
505
 
{
506
 
  DRIZZLE_LOCK *locked;
507
 
  TABLE *write_lock_used;
508
 
  if ((locked = get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
509
 
                              &write_lock_used)))
510
 
  {
511
 
    for (uint i=0; i < locked->lock_count; i++)
512
 
      thr_downgrade_write_lock(locked->locks[i], new_lock_type);
513
 
    my_free((uchar*) locked,MYF(0));
514
 
  }
 
431
void mysql_lock_remove(Session *session, Table *table)
 
432
{
 
433
  mysql_unlock_some_tables(session, &table, /* table count */ 1);
515
434
}
516
435
 
517
436
 
518
437
/** Abort all other threads waiting to get lock in table. */
519
438
 
520
 
void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock)
 
439
void mysql_lock_abort(Session *session, Table *table)
521
440
{
522
441
  DRIZZLE_LOCK *locked;
523
 
  TABLE *write_lock_used;
 
442
  Table *write_lock_used;
524
443
 
525
 
  if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
 
444
  if ((locked= get_lock_data(session, &table, 1, false,
526
445
                             &write_lock_used)))
527
446
  {
528
 
    for (uint i=0; i < locked->lock_count; i++)
529
 
      thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
530
 
    my_free((uchar*) locked,MYF(0));
 
447
    for (uint32_t x= 0; x < locked->lock_count; x++)
 
448
      thr_abort_locks(locked->locks[x]->lock);
 
449
    free((unsigned char*) locked);
531
450
  }
532
 
  return;
533
451
}
534
452
 
535
453
 
536
454
/**
537
455
  Abort one thread / table combination.
538
456
 
539
 
  @param thd       Thread handler
 
457
  @param session           Thread handler
540
458
  @param table     Table that should be removed from lock queue
541
459
 
542
460
  @retval
545
463
    1  Table was locked by at least one other thread
546
464
*/
547
465
 
548
 
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
 
466
bool mysql_lock_abort_for_thread(Session *session, Table *table)
549
467
{
550
468
  DRIZZLE_LOCK *locked;
551
 
  TABLE *write_lock_used;
 
469
  Table *write_lock_used;
552
470
  bool result= false;
553
471
 
554
 
  if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
 
472
  if ((locked= get_lock_data(session, &table, 1, false,
555
473
                             &write_lock_used)))
556
474
  {
557
 
    for (uint i=0; i < locked->lock_count; i++)
 
475
    for (uint32_t i=0; i < locked->lock_count; i++)
558
476
    {
559
477
      if (thr_abort_locks_for_thread(locked->locks[i]->lock,
560
478
                                     table->in_use->thread_id))
561
479
        result= true;
562
480
    }
563
 
    my_free((uchar*) locked,MYF(0));
564
 
  }
565
 
  return(result);
566
 
}
567
 
 
568
 
 
569
 
DRIZZLE_LOCK *mysql_lock_merge(DRIZZLE_LOCK *a,DRIZZLE_LOCK *b)
570
 
{
571
 
  DRIZZLE_LOCK *sql_lock;
572
 
  TABLE **table, **end_table;
573
 
 
574
 
  if (!(sql_lock= (DRIZZLE_LOCK*)
575
 
        my_malloc(sizeof(*sql_lock)+
576
 
                  sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+
577
 
                  sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME))))
578
 
    return(0);                          // Fatal error
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);
582
 
  sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count);
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,
588
 
         b->table_count*sizeof(*b->table));
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 */
604
 
  my_free((uchar*) a,MYF(0));
605
 
  my_free((uchar*) b,MYF(0));
606
 
  return(sql_lock);
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
 
 
617
 
  @param thd                 The current thread.
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
 
 
633
 
TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
634
 
                                      TABLE_LIST *haystack)
635
 
{
636
 
  DRIZZLE_LOCK            *mylock;
637
 
  TABLE                 **lock_tables;
638
 
  TABLE                 *table;
639
 
  TABLE                 *table2;
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. */
658
 
  if (! (mylock= thd->lock ? thd->lock : thd->locked_tables))
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. */
669
 
  assert((table->lock_position < mylock->table_count) &&
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. */
683
 
    assert((table2->lock_position < mylock->table_count) &&
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
 
        {
700
 
          return(haystack);
701
 
        }
702
 
      }
703
 
    }
704
 
  }
705
 
 
706
 
 end:
707
 
  return(NULL);
 
481
    free((unsigned char*) locked);
 
482
  }
 
483
  return result;
708
484
}
709
485
 
710
486
 
711
487
/** Unlock a set of external. */
712
488
 
713
 
static int unlock_external(THD *thd, TABLE **table,uint count)
 
489
static int unlock_external(Session *session, Table **table,uint32_t count)
714
490
{
715
491
  int error,error_code;
716
492
 
720
496
    if ((*table)->current_lock != F_UNLCK)
721
497
    {
722
498
      (*table)->current_lock = F_UNLCK;
723
 
      if ((error=(*table)->file->ha_external_lock(thd, F_UNLCK)))
 
499
      if ((error=(*table)->cursor->ha_external_lock(session, F_UNLCK)))
724
500
      {
725
501
        error_code=error;
726
 
        print_lock_error(error_code, (*table)->file->table_type());
 
502
        print_lock_error(error_code, (*table)->cursor->engine->getName().c_str());
727
503
      }
728
504
    }
729
505
    table++;
730
506
  } while (--count);
731
 
  return(error_code);
 
507
  return error_code;
732
508
}
733
509
 
734
510
 
735
511
/**
736
512
  Get lock structures from table structs and initialize locks.
737
513
 
738
 
  @param thd                Thread handler
 
514
  @param session                    Thread handler
739
515
  @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
742
 
           - GET_LOCK_STORE_LOCKS : Store lock info in TABLE
 
516
  @param should_lock                One of:
 
517
           - false      : If we should send TL_IGNORE to store lock
 
518
           - true       : Store lock info in Table
743
519
  @param write_lock_used   Store pointer to last table with WRITE_ALLOW_WRITE
744
520
*/
745
521
 
746
 
static DRIZZLE_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
747
 
                                 uint flags, TABLE **write_lock_used)
 
522
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table_ptr, uint32_t count,
 
523
                                 bool should_lock, Table **write_lock_used)
748
524
{
749
 
  uint i,tables,lock_count;
 
525
  uint32_t i,tables,lock_count;
750
526
  DRIZZLE_LOCK *sql_lock;
751
527
  THR_LOCK_DATA **locks, **locks_buf, **locks_start;
752
 
  TABLE **to, **table_buf;
753
 
 
754
 
  assert((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS));
 
528
  Table **to, **table_buf;
755
529
 
756
530
  *write_lock_used=0;
757
 
  for (i=tables=lock_count=0 ; i < count ; i++)
 
531
  for (i= tables= lock_count= 0 ; i < count ; i++)
758
532
  {
759
 
    TABLE *t= table_ptr[i];
 
533
    Table *t= table_ptr[i];
760
534
 
761
 
    if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE)
 
535
    if (! (t->getEngine()->check_flag(HTON_BIT_SKIP_STORE_LOCK)))
762
536
    {
763
 
      tables+= t->file->lock_count();
 
537
      tables++;
764
538
      lock_count++;
765
539
    }
766
540
  }
772
546
    from the first part immediately before calling thr_multi_lock().
773
547
  */
774
548
  if (!(sql_lock= (DRIZZLE_LOCK*)
775
 
        my_malloc(sizeof(*sql_lock) +
776
 
                  sizeof(THR_LOCK_DATA*) * tables * 2 +
777
 
                  sizeof(table_ptr) * lock_count,
778
 
                  MYF(0))))
779
 
    return(0);
 
549
        malloc(sizeof(*sql_lock) +
 
550
               sizeof(THR_LOCK_DATA*) * tables * 2 +
 
551
               sizeof(table_ptr) * lock_count)))
 
552
    return NULL;
780
553
  locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
781
 
  to= table_buf= sql_lock->table= (TABLE**) (locks + tables * 2);
782
 
  sql_lock->table_count=lock_count;
 
554
  to= table_buf= sql_lock->table= (Table**) (locks + tables * 2);
 
555
  sql_lock->table_count= lock_count;
783
556
 
784
557
  for (i=0 ; i < count ; i++)
785
558
  {
786
 
    TABLE *table;
 
559
    Table *table;
787
560
    enum thr_lock_type lock_type;
788
561
 
789
 
    if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
 
562
    if (table_ptr[i]->getEngine()->check_flag(HTON_BIT_SKIP_STORE_LOCK))
790
563
      continue;
 
564
 
 
565
    table= table_ptr[i];
791
566
    lock_type= table->reginfo.lock_type;
792
567
    assert (lock_type != TL_WRITE_DEFAULT);
793
568
    if (lock_type >= TL_WRITE_ALLOW_WRITE)
799
574
        /* Clear the lock type of the lock data that are stored already. */
800
575
        sql_lock->lock_count= locks - sql_lock->locks;
801
576
        reset_lock_data_and_free(&sql_lock);
802
 
        return(0);
 
577
        return NULL;
803
578
      }
804
579
    }
805
580
    locks_start= locks;
806
 
    locks= table->file->store_lock(thd, locks,
807
 
                                   (flags & GET_LOCK_UNLOCK) ? TL_IGNORE :
808
 
                                   lock_type);
809
 
    if (flags & GET_LOCK_STORE_LOCKS)
 
581
    locks= table->cursor->store_lock(session, locks,
 
582
                                   should_lock == false ? TL_IGNORE : lock_type);
 
583
    if (should_lock)
810
584
    {
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);
 
585
      table->lock_position=   (uint32_t) (to - table_buf);
 
586
      table->lock_data_start= (uint32_t) (locks_start - locks_buf);
 
587
      table->lock_count=      (uint32_t) (locks - locks_start);
 
588
      assert(table->lock_count == 1);
814
589
    }
815
590
    *to++= table;
816
591
  }
829
604
    And in the FLUSH case, the memory is released quickly anyway.
830
605
  */
831
606
  sql_lock->lock_count= locks - locks_buf;
832
 
  return(sql_lock);
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
 
 
844
 
  @param thd                    Thread handler
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
 
 
857
 
int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list)
858
 
{
859
 
  int lock_retcode;
860
 
  int error= -1;
861
 
 
862
 
  if (wait_if_global_read_lock(thd, 0, 1))
863
 
    return(1);
864
 
  VOID(pthread_mutex_lock(&LOCK_open));
865
 
  if ((lock_retcode = lock_table_name(thd, table_list, true)) < 0)
866
 
    goto end;
867
 
  if (lock_retcode && wait_for_locked_table_names(thd, table_list))
868
 
  {
869
 
    unlock_table_name(thd, table_list);
870
 
    goto end;
871
 
  }
872
 
  error=0;
873
 
 
874
 
end:
875
 
  pthread_mutex_unlock(&LOCK_open);
876
 
  start_waiting_global_read_lock(thd);
877
 
  return(error);
 
607
 
 
608
  return sql_lock;
878
609
}
879
610
 
880
611
 
881
612
/**
882
613
  Put a not open table with an old refresh version in the table cache.
883
614
 
884
 
  @param thd                    Thread handler
 
615
  @param session                        Thread handler
885
616
  @param table_list             Lock first table in this list
886
617
  @param check_in_use           Do we need to check if table already in use by us
887
618
 
890
621
 
891
622
  @warning
892
623
    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
 
624
    lock_and_wait_for_table_name(removed) instead of this function as this works
894
625
    together with 'FLUSH TABLES WITH READ LOCK'
895
626
 
896
627
  @note
905
636
    > 0  table locked, but someone is using it
906
637
*/
907
638
 
908
 
int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use)
 
639
int lock_table_name(Session *session, TableList *table_list, bool check_in_use)
909
640
{
910
 
  TABLE *table;
 
641
  Table *table;
911
642
  char  key[MAX_DBKEY_LENGTH];
912
643
  char *db= table_list->db;
913
 
  uint  key_length;
 
644
  uint32_t  key_length;
914
645
  bool  found_locked_table= false;
915
646
  HASH_SEARCH_STATE state;
916
647
 
917
 
  key_length= create_table_def_key(thd, key, table_list, 0);
 
648
  key_length= table_list->create_table_def_key(key);
918
649
 
919
650
  if (check_in_use)
920
651
  {
921
652
    /* Only insert the table if we haven't insert it already */
922
 
    for (table=(TABLE*) hash_first(&open_cache, (uchar*)key,
 
653
    for (table=(Table*) hash_first(&open_cache, (unsigned char*)key,
923
654
                                   key_length, &state);
924
655
         table ;
925
 
         table = (TABLE*) hash_next(&open_cache,(uchar*) key,
 
656
         table = (Table*) hash_next(&open_cache,(unsigned char*) key,
926
657
                                    key_length, &state))
927
658
    {
928
659
      if (table->reginfo.lock_type < TL_WRITE)
929
660
      {
930
 
        if (table->in_use == thd)
 
661
        if (table->in_use == session)
931
662
          found_locked_table= true;
932
663
        continue;
933
664
      }
934
665
 
935
 
      if (table->in_use == thd)
 
666
      if (table->in_use == session)
936
667
      {
937
668
        table->s->version= 0;                  // Ensure no one can use this
938
669
        table->locked_by_name= 1;
939
 
        return(0);
 
670
        return 0;
940
671
      }
941
672
    }
942
673
  }
943
674
 
944
 
  if (thd->locked_tables && thd->locked_tables->table_count &&
945
 
      ! find_temporary_table(thd, table_list->db, table_list->table_name))
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
 
 
952
 
    return(-1);
953
 
  }
954
 
 
955
 
  if (!(table= table_cache_insert_placeholder(thd, key, key_length)))
956
 
    return(-1);
 
675
  if (!(table= session->table_cache_insert_placeholder(key, key_length)))
 
676
    return -1;
957
677
 
958
678
  table_list->table=table;
959
679
 
960
680
  /* Return 1 if table is in use */
961
 
  return(test(remove_table_from_cache(thd, db, table_list->table_name,
 
681
  return(test(remove_table_from_cache(session, db, table_list->table_name,
962
682
             check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG)));
963
683
}
964
684
 
965
685
 
966
 
void unlock_table_name(THD *thd __attribute__((unused)),
967
 
                       TABLE_LIST *table_list)
 
686
void unlock_table_name(TableList *table_list)
968
687
{
969
688
  if (table_list->table)
970
689
  {
971
 
    hash_delete(&open_cache, (uchar*) table_list->table);
 
690
    hash_delete(&open_cache, (unsigned char*) table_list->table);
972
691
    broadcast_refresh();
973
692
  }
974
693
}
975
694
 
976
695
 
977
 
static bool locked_named_table(THD *thd __attribute__((unused)),
978
 
                               TABLE_LIST *table_list)
 
696
static bool locked_named_table(TableList *table_list)
979
697
{
980
698
  for (; table_list ; table_list=table_list->next_local)
981
699
  {
982
 
    TABLE *table= table_list->table;
 
700
    Table *table= table_list->table;
983
701
    if (table)
984
702
    {
985
 
      TABLE *save_next= table->next;
 
703
      Table *save_next= table->next;
986
704
      bool result;
987
705
      table->next= 0;
988
706
      result= table_is_used(table_list->table, 0);
995
713
}
996
714
 
997
715
 
998
 
bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list)
 
716
bool wait_for_locked_table_names(Session *session, TableList *table_list)
999
717
{
1000
 
  bool result=0;
 
718
  bool result= false;
1001
719
 
1002
720
  safe_mutex_assert_owner(&LOCK_open);
1003
721
 
1004
 
  while (locked_named_table(thd,table_list))
 
722
  while (locked_named_table(table_list))
1005
723
  {
1006
 
    if (thd->killed)
 
724
    if (session->killed)
1007
725
    {
1008
726
      result=1;
1009
727
      break;
1010
728
    }
1011
 
    wait_for_condition(thd, &LOCK_open, &COND_refresh);
1012
 
    pthread_mutex_lock(&LOCK_open);
 
729
    session->wait_for_condition(&LOCK_open, &COND_refresh);
 
730
    pthread_mutex_lock(&LOCK_open); /* Wait for a table to unlock and then lock it */
1013
731
  }
1014
 
  return(result);
 
732
  return result;
1015
733
}
1016
734
 
1017
735
 
1021
739
  REQUIREMENTS
1022
740
  - One must have a lock on LOCK_open when calling this
1023
741
 
1024
 
  @param thd                    Thread handle
1025
742
  @param table_list             Names of tables to lock
1026
743
 
1027
 
  @note
1028
 
    If you are just locking one table, you should use
1029
 
    lock_and_wait_for_table_name().
1030
 
 
1031
744
  @retval
1032
745
    0   ok
1033
746
  @retval
1034
747
    1   Fatal error (end of memory ?)
1035
748
*/
1036
749
 
1037
 
bool lock_table_names(THD *thd, TABLE_LIST *table_list)
 
750
bool lock_table_names(Session *session, TableList *table_list)
1038
751
{
1039
752
  bool got_all_locks=1;
1040
 
  TABLE_LIST *lock_table;
 
753
  TableList *lock_table;
1041
754
 
1042
755
  for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
1043
756
  {
1044
757
    int got_lock;
1045
 
    if ((got_lock=lock_table_name(thd,lock_table, true)) < 0)
 
758
    if ((got_lock= lock_table_name(session,lock_table, true)) < 0)
1046
759
      goto end;                                 // Fatal error
1047
760
    if (got_lock)
1048
761
      got_all_locks=0;                          // Someone is using table
1049
762
  }
1050
763
 
1051
764
  /* If some table was in use, wait until we got the lock */
1052
 
  if (!got_all_locks && wait_for_locked_table_names(thd, table_list))
 
765
  if (!got_all_locks && wait_for_locked_table_names(session, table_list))
1053
766
    goto end;
1054
 
  return 0;
 
767
  return false;
1055
768
 
1056
769
end:
1057
 
  unlock_table_names(thd, table_list, lock_table);
1058
 
  return 1;
 
770
  unlock_table_names(table_list, lock_table);
 
771
 
 
772
  return true;
1059
773
}
1060
774
 
1061
775
 
1062
776
/**
1063
777
  Unlock all tables in list with a name lock.
1064
778
 
1065
 
  @param thd        Thread handle.
 
779
  @param session        Thread handle.
1066
780
  @param table_list Names of tables to lock.
1067
781
 
1068
 
  @note 
1069
 
    This function needs to be protected by LOCK_open. If we're 
 
782
  @note
 
783
    This function needs to be protected by LOCK_open. If we're
1070
784
    under LOCK TABLES, this function does not work as advertised. Namely,
1071
785
    it does not exclude other threads from using this table and does not
1072
786
    put an exclusive name lock on this table into the table cache.
1078
792
  @retval FALSE Name lock successfully acquired.
1079
793
*/
1080
794
 
1081
 
bool lock_table_names_exclusively(THD *thd, TABLE_LIST *table_list)
 
795
bool lock_table_names_exclusively(Session *session, TableList *table_list)
1082
796
{
1083
 
  if (lock_table_names(thd, table_list))
 
797
  if (lock_table_names(session, table_list))
1084
798
    return true;
1085
799
 
1086
800
  /*
1087
801
    Upgrade the table name locks from semi-exclusive to exclusive locks.
1088
802
  */
1089
 
  for (TABLE_LIST *table= table_list; table; table= table->next_global)
 
803
  for (TableList *table= table_list; table; table= table->next_global)
1090
804
  {
1091
805
    if (table->table)
1092
806
      table->table->open_placeholder= 1;
1096
810
 
1097
811
 
1098
812
/**
1099
 
  Test is 'table' is protected by an exclusive name lock.
1100
 
 
1101
 
  @param[in] thd        The current thread handler
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
1113
 
is_table_name_exclusively_locked_by_this_thread(THD *thd,
1114
 
                                                TABLE_LIST *table_list)
1115
 
{
1116
 
  char  key[MAX_DBKEY_LENGTH];
1117
 
  uint  key_length;
1118
 
 
1119
 
  key_length= create_table_def_key(thd, key, table_list, 0);
1120
 
 
1121
 
  return is_table_name_exclusively_locked_by_this_thread(thd, (uchar *)key,
1122
 
                                                         key_length);
1123
 
}
1124
 
 
1125
 
 
1126
 
/**
1127
 
  Test is 'table key' is protected by an exclusive name lock.
1128
 
 
1129
 
  @param[in] thd        The current thread handler.
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
1140
 
is_table_name_exclusively_locked_by_this_thread(THD *thd, uchar *key,
1141
 
                                                int key_length)
1142
 
{
1143
 
  HASH_SEARCH_STATE state;
1144
 
  TABLE *table;
1145
 
 
1146
 
  for (table= (TABLE*) hash_first(&open_cache, key,
1147
 
                                  key_length, &state);
1148
 
       table ;
1149
 
       table= (TABLE*) hash_next(&open_cache, key,
1150
 
                                 key_length, &state))
1151
 
  {
1152
 
    if (table->in_use == thd &&
1153
 
        table->open_placeholder == 1 &&
1154
 
        table->s->version == 0)
1155
 
      return true;
1156
 
  }
1157
 
 
1158
 
  return false;
1159
 
}
1160
 
 
1161
 
/**
1162
813
  Unlock all tables in list with a name lock.
1163
814
 
1164
815
  @param
1165
 
    thd                 Thread handle
1166
 
  @param
1167
816
    table_list          Names of tables to unlock
1168
817
  @param
1169
818
    last_table          Don't unlock any tables after this one.
1182
831
    1   Fatal error (end of memory ?)
1183
832
*/
1184
833
 
1185
 
void unlock_table_names(THD *thd, TABLE_LIST *table_list,
1186
 
                        TABLE_LIST *last_table)
 
834
void unlock_table_names(TableList *table_list, TableList *last_table)
1187
835
{
1188
 
  for (TABLE_LIST *table= table_list;
 
836
  for (TableList *table= table_list;
1189
837
       table != last_table;
1190
838
       table= table->next_local)
1191
 
    unlock_table_name(thd,table);
 
839
    unlock_table_name(table);
1192
840
  broadcast_refresh();
1193
 
  return;
1194
841
}
1195
842
 
1196
843
 
1220
867
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), table);
1221
868
  else
1222
869
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error);
1223
 
 
1224
 
  return;
1225
870
}
1226
871
 
1227
872
 
1285
930
  If we have merged 1) and 3) into 1), we would have had this deadlock:
1286
931
  imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
1287
932
  table t.
1288
 
  thd1: SELECT * FROM t FOR UPDATE;
1289
 
  thd2: UPDATE t SET a=1; # blocked by row-level locks of thd1
1290
 
  thd3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
1291
 
  table instance of thd2
1292
 
  thd1: COMMIT; # blocked by thd3.
1293
 
  thd1 blocks thd2 which blocks thd3 which blocks thd1: deadlock.
 
933
  session1: SELECT * FROM t FOR UPDATE;
 
934
  session2: UPDATE t SET a=1; # blocked by row-level locks of session1
 
935
  session3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
 
936
  table instance of session2
 
937
  session1: COMMIT; # blocked by session3.
 
938
  session1 blocks session2 which blocks session3 which blocks session1: deadlock.
1294
939
 
1295
940
  Note that we need to support that one thread does
1296
941
  FLUSH TABLES WITH READ LOCK; and then COMMIT;
1300
945
 
1301
946
****************************************************************************/
1302
947
 
1303
 
volatile uint global_read_lock=0;
1304
 
volatile uint global_read_lock_blocks_commit=0;
1305
 
static volatile uint protect_against_global_read_lock=0;
1306
 
static volatile uint waiting_for_read_lock=0;
 
948
volatile uint32_t global_read_lock=0;
 
949
volatile uint32_t global_read_lock_blocks_commit=0;
 
950
static volatile uint32_t protect_against_global_read_lock=0;
 
951
static volatile uint32_t waiting_for_read_lock=0;
1307
952
 
1308
953
#define GOT_GLOBAL_READ_LOCK               1
1309
954
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
1310
955
 
1311
 
bool lock_global_read_lock(THD *thd)
 
956
bool lock_global_read_lock(Session *session)
1312
957
{
1313
 
  if (!thd->global_read_lock)
 
958
  if (!session->global_read_lock)
1314
959
  {
1315
960
    const char *old_message;
1316
961
    (void) pthread_mutex_lock(&LOCK_global_read_lock);
1317
 
    old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
 
962
    old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1318
963
                                "Waiting to get readlock");
1319
964
 
1320
965
    waiting_for_read_lock++;
1321
 
    while (protect_against_global_read_lock && !thd->killed)
 
966
    while (protect_against_global_read_lock && !session->killed)
1322
967
      pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1323
968
    waiting_for_read_lock--;
1324
 
    if (thd->killed)
 
969
    if (session->killed)
1325
970
    {
1326
 
      thd->exit_cond(old_message);
1327
 
      return(1);
 
971
      session->exit_cond(old_message);
 
972
      return true;
1328
973
    }
1329
 
    thd->global_read_lock= GOT_GLOBAL_READ_LOCK;
 
974
    session->global_read_lock= GOT_GLOBAL_READ_LOCK;
1330
975
    global_read_lock++;
1331
 
    thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
 
976
    session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1332
977
  }
1333
978
  /*
1334
979
    We DON'T set global_read_lock_blocks_commit now, it will be set after
1338
983
    forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
1339
984
    UPDATE and one does FLUSH TABLES WITH READ LOCK).
1340
985
  */
1341
 
  return(0);
 
986
  return false;
1342
987
}
1343
988
 
1344
989
 
1345
 
void unlock_global_read_lock(THD *thd)
 
990
void unlock_global_read_lock(Session *session)
1346
991
{
1347
 
  uint tmp;
 
992
  uint32_t tmp;
1348
993
 
1349
994
  pthread_mutex_lock(&LOCK_global_read_lock);
1350
995
  tmp= --global_read_lock;
1351
 
  if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
 
996
  if (session->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1352
997
    --global_read_lock_blocks_commit;
1353
998
  pthread_mutex_unlock(&LOCK_global_read_lock);
1354
999
  /* Send the signal outside the mutex to avoid a context switch */
1356
1001
  {
1357
1002
    pthread_cond_broadcast(&COND_global_read_lock);
1358
1003
  }
1359
 
  thd->global_read_lock= 0;
1360
 
 
1361
 
  return;
 
1004
  session->global_read_lock= 0;
1362
1005
}
1363
1006
 
1364
1007
#define must_wait (global_read_lock &&                             \
1365
1008
                   (is_not_commit ||                               \
1366
1009
                    global_read_lock_blocks_commit))
1367
1010
 
1368
 
bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
 
1011
bool wait_if_global_read_lock(Session *session, bool abort_on_refresh,
1369
1012
                              bool is_not_commit)
1370
1013
{
1371
1014
  const char *old_message= NULL;
1381
1024
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
1382
1025
  if ((need_exit_cond= must_wait))
1383
1026
  {
1384
 
    if (thd->global_read_lock)          // This thread had the read locks
 
1027
    if (session->global_read_lock)              // This thread had the read locks
1385
1028
    {
1386
1029
      if (is_not_commit)
1387
1030
        my_message(ER_CANT_UPDATE_WITH_READLOCK,
1392
1035
        This allowance is needed to not break existing versions of innobackup
1393
1036
        which do a BEGIN; INSERT; FLUSH TABLES WITH READ LOCK; COMMIT.
1394
1037
      */
1395
 
      return(is_not_commit);
 
1038
      return is_not_commit;
1396
1039
    }
1397
 
    old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
 
1040
    old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1398
1041
                                "Waiting for release of readlock");
1399
 
    while (must_wait && ! thd->killed &&
1400
 
           (!abort_on_refresh || thd->version == refresh_version))
 
1042
    while (must_wait && ! session->killed &&
 
1043
           (!abort_on_refresh || session->version == refresh_version))
1401
1044
    {
1402
1045
      (void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1403
1046
    }
1404
 
    if (thd->killed)
 
1047
    if (session->killed)
1405
1048
      result=1;
1406
1049
  }
1407
1050
  if (!abort_on_refresh && !result)
1411
1054
    and if old_message is set
1412
1055
  */
1413
1056
  if (unlikely(need_exit_cond))
1414
 
    thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
 
1057
    session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1415
1058
  else
1416
1059
    pthread_mutex_unlock(&LOCK_global_read_lock);
1417
 
  return(result);
 
1060
  return result;
1418
1061
}
1419
1062
 
1420
1063
 
1421
 
void start_waiting_global_read_lock(THD *thd)
 
1064
void start_waiting_global_read_lock(Session *session)
1422
1065
{
1423
1066
  bool tmp;
1424
 
  if (unlikely(thd->global_read_lock))
 
1067
  if (unlikely(session->global_read_lock))
1425
1068
    return;
1426
1069
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
1427
1070
  tmp= (!--protect_against_global_read_lock &&
1433
1076
}
1434
1077
 
1435
1078
 
1436
 
bool make_global_read_lock_block_commit(THD *thd)
 
1079
bool make_global_read_lock_block_commit(Session *session)
1437
1080
{
1438
1081
  bool error;
1439
1082
  const char *old_message;
1441
1084
    If we didn't succeed lock_global_read_lock(), or if we already suceeded
1442
1085
    make_global_read_lock_block_commit(), do nothing.
1443
1086
  */
1444
 
  if (thd->global_read_lock != GOT_GLOBAL_READ_LOCK)
1445
 
    return(0);
 
1087
  if (session->global_read_lock != GOT_GLOBAL_READ_LOCK)
 
1088
    return false;
1446
1089
  pthread_mutex_lock(&LOCK_global_read_lock);
1447
1090
  /* increment this BEFORE waiting on cond (otherwise race cond) */
1448
1091
  global_read_lock_blocks_commit++;
1449
 
  /* For testing we set up some blocking, to see if we can be killed */
1450
 
  protect_against_global_read_lock++;
1451
 
  old_message= thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
 
1092
  old_message= session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1452
1093
                               "Waiting for all running commits to finish");
1453
 
  while (protect_against_global_read_lock && !thd->killed)
 
1094
  while (protect_against_global_read_lock && !session->killed)
1454
1095
    pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1455
 
  protect_against_global_read_lock--;
1456
 
  if ((error= test(thd->killed)))
 
1096
  if ((error= test(session->killed)))
1457
1097
    global_read_lock_blocks_commit--; // undo what we did
1458
1098
  else
1459
 
    thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1460
 
  thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1461
 
  return(error);
 
1099
    session->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
 
1100
  session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
 
1101
  return error;
1462
1102
}
1463
1103
 
1464
1104
 
1483
1123
 
1484
1124
void broadcast_refresh(void)
1485
1125
{
1486
 
  VOID(pthread_cond_broadcast(&COND_refresh));
1487
 
  VOID(pthread_cond_broadcast(&COND_global_read_lock));
1488
 
}
1489
 
 
1490
 
 
1491
 
/*
1492
 
  Try to get transactional table locks for the tables in the list.
1493
 
 
1494
 
  SYNOPSIS
1495
 
    try_transactional_lock()
1496
 
      thd                       Thread handle
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
 
 
1509
 
int try_transactional_lock(THD *thd, TABLE_LIST *table_list)
1510
 
{
1511
 
  uint          dummy_counter;
1512
 
  int           error;
1513
 
  int           result= 0;
1514
 
 
1515
 
  /* Need to open the tables to be able to access engine methods. */
1516
 
  if (open_tables(thd, &table_list, &dummy_counter, 0))
1517
 
  {
1518
 
    /* purecov: begin tested */
1519
 
    return(-1);
1520
 
    /* purecov: end */
1521
 
  }
1522
 
 
1523
 
  /* Required by InnoDB. */
1524
 
  thd->in_lock_tables= true;
1525
 
 
1526
 
  if ((error= set_handler_table_locks(thd, table_list, true)))
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. */
1549
 
  (void) ha_autocommit_or_rollback(thd, 0);
1550
 
  /* Close the tables. The locks (if taken) persist in the storage engines. */
1551
 
  close_tables_for_reopen(thd, &table_list);
1552
 
  thd->in_lock_tables= false;
1553
 
  return(result);
1554
 
}
1555
 
 
1556
 
 
1557
 
/*
1558
 
  Check if lock method conversion was done and was allowed.
1559
 
 
1560
 
  SYNOPSIS
1561
 
    check_transactional_lock()
1562
 
      thd                       Thread handle
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
 
 
1582
 
int check_transactional_lock(THD *thd, TABLE_LIST *table_list)
1583
 
{
1584
 
  TABLE_LIST    *tlist;
1585
 
  int           result= 0;
1586
 
  char          warn_buff[DRIZZLE_ERRMSG_SIZE];
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
1594
 
      here. Whenever the definition of TABLE_LIST::placeholder() is
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. */
1611
 
    if (thd->active_transaction())
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. */
1620
 
    snprintf(warn_buff, sizeof(warn_buff), ER(ER_WARN_AUTO_CONVERT_LOCK),
1621
 
             tlist->alias ? tlist->alias : tlist->table_name);
1622
 
    push_warning(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1623
 
                 ER_WARN_AUTO_CONVERT_LOCK, warn_buff);
1624
 
  }
1625
 
 
1626
 
  return(result);
1627
 
}
1628
 
 
1629
 
 
1630
 
/*
1631
 
  Set table locks in the table handler.
1632
 
 
1633
 
  SYNOPSIS
1634
 
    set_handler_table_locks()
1635
 
      thd                       Thread handle
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
 
 
1644
 
int set_handler_table_locks(THD *thd, TABLE_LIST *table_list,
1645
 
                            bool transactional)
1646
 
{
1647
 
  TABLE_LIST    *tlist;
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
 
 
1658
 
    assert((tlist->lock_type == TL_READ) ||
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
1684
 
        method in the TABLE_LIST object. It will be used later by
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
 
      */
1691
 
      tlist->lock_transactional= true;
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
 
    {
1703
 
      error= tlist->table->file->lock_table(thd, lock_type, lock_timeout);
1704
 
      if (error && transactional && (error != HA_ERR_WRONG_COMMAND))
1705
 
        tlist->table->file->print_error(error, MYF(0));
1706
 
    }
1707
 
  }
1708
 
 
1709
 
  return(error);
 
1126
  pthread_cond_broadcast(&COND_refresh);
 
1127
  pthread_cond_broadcast(&COND_global_read_lock);
1710
1128
}
1711
1129
 
1712
1130
 
1713
1131
/**
1714
1132
  @} (end of group Locking)
1715
1133
*/
 
1134
 
 
1135
} /* namespace drizzled */