~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/lock.cc

pandora-build v0.71. Added check for avahi.

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
75
#include <drizzled/server_includes.h>
76
 
#include <drizzled/drizzled_error_messages.h>
 
76
#include <drizzled/error.h>
 
77
#include <mysys/hash.h>
 
78
#include <mysys/thr_lock.h>
 
79
#include <drizzled/session.h>
 
80
#include <drizzled/sql_base.h>
 
81
#include <drizzled/lock.h>
77
82
 
78
83
/**
79
84
  @defgroup Locking Locking
82
87
 
83
88
extern HASH open_cache;
84
89
 
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);
 
90
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table,
 
91
                                   uint32_t count,
 
92
                                   bool should_lock, Table **write_locked);
 
93
static int lock_external(Session *session, Table **table,uint32_t count);
 
94
static int unlock_external(Session *session, Table **table,uint32_t count);
93
95
static void print_lock_error(int error, const char *);
94
96
 
95
97
/*
97
99
 
98
100
  SYNOPSIS
99
101
    mysql_lock_tables()
100
 
    thd                         The current thread.
 
102
    session                         The current thread.
101
103
    tables                      An array of pointers to the tables to lock.
102
104
    count                       The number of tables to lock.
103
105
    flags                       Options:
104
106
      DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK      Ignore a global read lock
105
 
      DRIZZLE_LOCK_IGNORE_GLOBAL_READ_ONLY      Ignore SET GLOBAL READ_ONLY
106
107
      DRIZZLE_LOCK_IGNORE_FLUSH                 Ignore a flush tables.
107
108
      DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN        Instead of reopening altered
108
109
                                              or dropped tables by itself,
155
156
    /* Reset lock type. */
156
157
    (*ldata)->type= TL_UNLOCK;
157
158
  }
158
 
  my_free((uchar*) sql_lock, MYF(0));
 
159
  free((unsigned char*) sql_lock);
159
160
  *mysql_lock= 0;
160
161
}
161
162
 
162
163
 
163
 
DRIZZLE_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
164
 
                              uint flags, bool *need_reopen)
 
164
DRIZZLE_LOCK *mysql_lock_tables(Session *session, Table **tables, uint32_t count,
 
165
                                uint32_t flags, bool *need_reopen)
165
166
{
166
167
  DRIZZLE_LOCK *sql_lock;
167
 
  TABLE *write_lock_used;
 
168
  Table *write_lock_used;
168
169
  int rc;
169
170
 
170
171
  *need_reopen= false;
171
172
 
172
173
  for (;;)
173
174
  {
174
 
    if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS,
 
175
    if (! (sql_lock= get_lock_data(session, tables, count, true,
175
176
                                   &write_lock_used)))
176
177
      break;
177
178
 
182
183
        Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
183
184
        Wait until the lock is gone
184
185
      */
185
 
      if (wait_if_global_read_lock(thd, 1, 1))
 
186
      if (wait_if_global_read_lock(session, 1, 1))
186
187
      {
187
188
        /* Clear the lock type of all lock data to avoid reusage. */
188
189
        reset_lock_data_and_free(&sql_lock);
189
190
        break;
190
191
      }
191
 
      if (thd->version != refresh_version)
 
192
      if (session->version != refresh_version)
192
193
      {
193
194
        /* Clear the lock type of all lock data to avoid reusage. */
194
195
        reset_lock_data_and_free(&sql_lock);
196
197
      }
197
198
    }
198
199
 
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,
 
200
    session->set_proc_info("System lock");
 
201
    if (sql_lock->table_count && lock_external(session, sql_lock->table,
215
202
                                               sql_lock->table_count))
216
203
    {
217
204
      /* Clear the lock type of all lock data to avoid reusage. */
218
205
      reset_lock_data_and_free(&sql_lock);
219
206
      break;
220
207
    }
221
 
    thd_proc_info(thd, "Table lock");
 
208
    session->set_proc_info("Table lock");
222
209
    /* Copy the lock data array. thr_multi_lock() reorders its contens. */
223
210
    memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
224
211
           sql_lock->lock_count * sizeof(*sql_lock->locks));
226
213
    rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
227
214
                                                     sql_lock->lock_count,
228
215
                                                     sql_lock->lock_count,
229
 
                                                     thd->lock_id)];
 
216
                                                     session->lock_id)];
230
217
    if (rc > 1)                                 /* a timeout or a deadlock */
231
218
    {
232
219
      if (sql_lock->table_count)
233
 
        VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
 
220
        unlock_external(session, sql_lock->table, sql_lock->table_count);
234
221
      reset_lock_data_and_free(&sql_lock);
235
222
      my_error(rc, MYF(0));
236
223
      break;
237
224
    }
238
225
    else if (rc == 1)                           /* aborted */
239
226
    {
240
 
      thd->some_tables_deleted=1;               // Try again
 
227
      session->some_tables_deleted=1;           // Try again
241
228
      sql_lock->lock_count= 0;                  // Locks are already freed
242
229
      // Fall through: unlock, reset lock data, free and retry
243
230
    }
244
 
    else if (!thd->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
 
231
    else if (!session->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
245
232
    {
246
233
      /*
247
234
        Thread was killed or lock aborted. Let upper level close all
249
236
      */
250
237
      break;
251
238
    }
252
 
    else if (!thd->open_tables)
 
239
    else if (!session->open_tables)
253
240
    {
254
241
      // Only using temporary tables, no need to unlock
255
 
      thd->some_tables_deleted=0;
 
242
      session->some_tables_deleted= 0;
256
243
      break;
257
244
    }
258
 
    thd_proc_info(thd, 0);
 
245
    session->set_proc_info(0);
259
246
 
260
247
    /* going to retry, unlock all tables */
261
248
    if (sql_lock->lock_count)
262
249
        thr_multi_unlock(sql_lock->locks, sql_lock->lock_count);
263
250
 
264
251
    if (sql_lock->table_count)
265
 
      VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
 
252
      unlock_external(session, sql_lock->table, sql_lock->table_count);
266
253
 
267
254
    /*
268
255
      If thr_multi_lock fails it resets lock type for tables, which
276
263
      *need_reopen= true;
277
264
      break;
278
265
    }
279
 
    if (wait_for_tables(thd))
 
266
    if (wait_for_tables(session))
280
267
      break;                                    // Couldn't open tables
281
268
  }
282
 
  thd_proc_info(thd, 0);
283
 
  if (thd->killed)
 
269
  session->set_proc_info(0);
 
270
  if (session->killed)
284
271
  {
285
 
    thd->send_kill_message();
 
272
    session->send_kill_message();
286
273
    if (sql_lock)
287
274
    {
288
 
      mysql_unlock_tables(thd,sql_lock);
289
 
      sql_lock=0;
 
275
      mysql_unlock_tables(session,sql_lock);
 
276
      sql_lock= NULL;
290
277
    }
291
278
  }
292
279
 
293
 
  thd->set_time_after_lock();
 
280
  session->set_time_after_lock();
294
281
  return (sql_lock);
295
282
}
296
283
 
297
284
 
298
 
static int lock_external(THD *thd, TABLE **tables, uint count)
 
285
static int lock_external(Session *session, Table **tables, uint32_t count)
299
286
{
300
 
  register uint i;
 
287
  register uint32_t i;
301
288
  int lock_type,error;
302
289
  for (i=1 ; i <= count ; i++, tables++)
303
290
  {
308
295
         (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
309
296
      lock_type=F_RDLCK;
310
297
 
311
 
    if ((error=(*tables)->file->ha_external_lock(thd,lock_type)))
 
298
    if ((error=(*tables)->cursor->ha_external_lock(session,lock_type)))
312
299
    {
313
 
      print_lock_error(error, (*tables)->file->table_type());
 
300
      print_lock_error(error, (*tables)->cursor->engine->getName().c_str());
314
301
      while (--i)
315
302
      {
316
303
        tables--;
317
 
        (*tables)->file->ha_external_lock(thd, F_UNLCK);
 
304
        (*tables)->cursor->ha_external_lock(session, F_UNLCK);
318
305
        (*tables)->current_lock=F_UNLCK;
319
306
      }
320
 
      return(error);
 
307
      return error;
321
308
    }
322
309
    else
323
310
    {
325
312
      (*tables)->current_lock= lock_type;
326
313
    }
327
314
  }
328
 
  return(0);
 
315
  return 0;
329
316
}
330
317
 
331
318
 
332
 
void mysql_unlock_tables(THD *thd, DRIZZLE_LOCK *sql_lock)
 
319
void mysql_unlock_tables(Session *session, DRIZZLE_LOCK *sql_lock)
333
320
{
334
321
  if (sql_lock->lock_count)
335
322
    thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
336
323
  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));
 
324
    unlock_external(session,sql_lock->table,sql_lock->table_count);
 
325
  free((unsigned char*) sql_lock);
339
326
  return;
340
327
}
341
328
 
345
332
  This will work even if get_lock_data fails (next unlock will free all)
346
333
*/
347
334
 
348
 
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count)
 
335
void mysql_unlock_some_tables(Session *session, Table **table, uint32_t count)
349
336
{
350
337
  DRIZZLE_LOCK *sql_lock;
351
 
  TABLE *write_lock_used;
352
 
  if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK,
 
338
  Table *write_lock_used;
 
339
  if ((sql_lock= get_lock_data(session, table, count, false,
353
340
                               &write_lock_used)))
354
 
    mysql_unlock_tables(thd, sql_lock);
 
341
    mysql_unlock_tables(session, sql_lock);
355
342
}
356
343
 
357
344
 
359
346
  unlock all tables locked for read.
360
347
*/
361
348
 
362
 
void mysql_unlock_read_tables(THD *thd, DRIZZLE_LOCK *sql_lock)
 
349
void mysql_unlock_read_tables(Session *session, DRIZZLE_LOCK *sql_lock)
363
350
{
364
 
  uint i,found;
 
351
  uint32_t i,found;
365
352
 
366
353
  /* Move all write locks first */
367
354
  THR_LOCK_DATA **lock=sql_lock->locks;
369
356
  {
370
357
    if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_READ)
371
358
    {
372
 
      swap_variables(THR_LOCK_DATA *, *lock, sql_lock->locks[i]);
 
359
      std::swap(*lock, sql_lock->locks[i]);
373
360
      lock++;
374
361
      found++;
375
362
    }
383
370
 
384
371
  /* Then do the same for the external locks */
385
372
  /* Move all write locked tables first */
386
 
  TABLE **table=sql_lock->table;
 
373
  Table **table=sql_lock->table;
387
374
  for (i=found=0 ; i < sql_lock->table_count ; i++)
388
375
  {
389
376
    assert(sql_lock->table[i]->lock_position == i);
390
 
    if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
 
377
    if ((uint32_t) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
391
378
    {
392
 
      swap_variables(TABLE *, *table, sql_lock->table[i]);
 
379
      std::swap(*table, sql_lock->table[i]);
393
380
      table++;
394
381
      found++;
395
382
    }
397
384
  /* Unlock all read locked tables */
398
385
  if (i != found)
399
386
  {
400
 
    VOID(unlock_external(thd,table,i-found));
 
387
    unlock_external(session,table,i-found);
401
388
    sql_lock->table_count=found;
402
389
  }
403
 
  /* Fix the lock positions in TABLE */
 
390
  /* Fix the lock positions in Table */
404
391
  table= sql_lock->table;
405
392
  found= 0;
406
393
  for (i= 0; i < sql_lock->table_count; i++)
407
394
  {
408
 
    TABLE *tbl= *table;
 
395
    Table *tbl= *table;
409
396
    tbl->lock_position= table - sql_lock->table;
410
397
    tbl->lock_data_start= found;
411
398
    found+= tbl->lock_count;
428
415
  unlock_external() we call handler::external_lock(F_UNLCK) only
429
416
  if table->current_lock is not F_UNLCK.
430
417
 
431
 
  @param  thd             thread context
 
418
  @param  session             thread context
432
419
  @param  locked          list of locked tables
433
420
  @param  table           the table to unlock
434
421
  @param  always_unlock   specify explicitly if the legacy side
435
422
                          effect is desired.
436
423
*/
437
424
 
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
 
  }
 
425
void mysql_lock_remove(Session *session, Table *table)
 
426
{
 
427
  mysql_unlock_some_tables(session, &table, /* table count */ 1);
515
428
}
516
429
 
517
430
 
518
431
/** Abort all other threads waiting to get lock in table. */
519
432
 
520
 
void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock)
 
433
void mysql_lock_abort(Session *session, Table *table)
521
434
{
522
435
  DRIZZLE_LOCK *locked;
523
 
  TABLE *write_lock_used;
 
436
  Table *write_lock_used;
524
437
 
525
 
  if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
 
438
  if ((locked= get_lock_data(session, &table, 1, false,
526
439
                             &write_lock_used)))
527
440
  {
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));
 
441
    for (uint32_t x= 0; x < locked->lock_count; x++)
 
442
      thr_abort_locks(locked->locks[x]->lock);
 
443
    free((unsigned char*) locked);
531
444
  }
532
 
  return;
533
445
}
534
446
 
535
447
 
536
448
/**
537
449
  Abort one thread / table combination.
538
450
 
539
 
  @param thd       Thread handler
 
451
  @param session           Thread handler
540
452
  @param table     Table that should be removed from lock queue
541
453
 
542
454
  @retval
545
457
    1  Table was locked by at least one other thread
546
458
*/
547
459
 
548
 
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
 
460
bool mysql_lock_abort_for_thread(Session *session, Table *table)
549
461
{
550
462
  DRIZZLE_LOCK *locked;
551
 
  TABLE *write_lock_used;
 
463
  Table *write_lock_used;
552
464
  bool result= false;
553
465
 
554
 
  if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
 
466
  if ((locked= get_lock_data(session, &table, 1, false,
555
467
                             &write_lock_used)))
556
468
  {
557
 
    for (uint i=0; i < locked->lock_count; i++)
 
469
    for (uint32_t i=0; i < locked->lock_count; i++)
558
470
    {
559
471
      if (thr_abort_locks_for_thread(locked->locks[i]->lock,
560
472
                                     table->in_use->thread_id))
561
473
        result= true;
562
474
    }
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);
 
475
    free((unsigned char*) locked);
 
476
  }
 
477
  return result;
607
478
}
608
479
 
609
480
 
614
485
  get_lock_data(). If we allow two opens on temporary tables later,
615
486
  both functions should be checked.
616
487
 
617
 
  @param thd                 The current thread.
 
488
  @param session                 The current thread.
618
489
  @param needle              The table to check for duplicate lock.
619
490
  @param haystack            The list of tables to search for the dup lock.
620
491
 
630
501
    !NULL   First table from 'haystack' that matches a lock on 'needle'.
631
502
*/
632
503
 
633
 
TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
634
 
                                      TABLE_LIST *haystack)
 
504
TableList *mysql_lock_have_duplicate(Session *session, TableList *needle,
 
505
                                      TableList *haystack)
635
506
{
636
507
  DRIZZLE_LOCK            *mylock;
637
 
  TABLE                 **lock_tables;
638
 
  TABLE                 *table;
639
 
  TABLE                 *table2;
 
508
  Table                 **lock_tables;
 
509
  Table                 *table;
 
510
  Table                 *table2;
640
511
  THR_LOCK_DATA         **lock_locks;
641
512
  THR_LOCK_DATA         **table_lock_data;
642
513
  THR_LOCK_DATA         **end_data;
655
526
    goto end;
656
527
 
657
528
  /* Get command lock or LOCK TABLES lock. Maybe empty for INSERT DELAYED. */
658
 
  if (! (mylock= thd->lock ? thd->lock : thd->locked_tables))
 
529
  if (!(mylock= session->lock))
659
530
    goto end;
660
531
 
661
532
  /* If we have less than two tables, we cannot have duplicates. */
696
567
           lock_data++)
697
568
      {
698
569
        if ((*lock_data)->lock == lock2)
699
 
        {
700
 
          return(haystack);
701
 
        }
 
570
          return haystack;
702
571
      }
703
572
    }
704
573
  }
705
574
 
706
575
 end:
707
 
  return(NULL);
 
576
  return NULL;
708
577
}
709
578
 
710
579
 
711
580
/** Unlock a set of external. */
712
581
 
713
 
static int unlock_external(THD *thd, TABLE **table,uint count)
 
582
static int unlock_external(Session *session, Table **table,uint32_t count)
714
583
{
715
584
  int error,error_code;
716
585
 
720
589
    if ((*table)->current_lock != F_UNLCK)
721
590
    {
722
591
      (*table)->current_lock = F_UNLCK;
723
 
      if ((error=(*table)->file->ha_external_lock(thd, F_UNLCK)))
 
592
      if ((error=(*table)->cursor->ha_external_lock(session, F_UNLCK)))
724
593
      {
725
594
        error_code=error;
726
 
        print_lock_error(error_code, (*table)->file->table_type());
 
595
        print_lock_error(error_code, (*table)->cursor->engine->getName().c_str());
727
596
      }
728
597
    }
729
598
    table++;
730
599
  } while (--count);
731
 
  return(error_code);
 
600
  return error_code;
732
601
}
733
602
 
734
603
 
735
604
/**
736
605
  Get lock structures from table structs and initialize locks.
737
606
 
738
 
  @param thd                Thread handler
 
607
  @param session                    Thread handler
739
608
  @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
 
609
  @param should_lock                One of:
 
610
           - false      : If we should send TL_IGNORE to store lock
 
611
           - true       : Store lock info in Table
743
612
  @param write_lock_used   Store pointer to last table with WRITE_ALLOW_WRITE
744
613
*/
745
614
 
746
 
static DRIZZLE_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
747
 
                                 uint flags, TABLE **write_lock_used)
 
615
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table_ptr, uint32_t count,
 
616
                                 bool should_lock, Table **write_lock_used)
748
617
{
749
 
  uint i,tables,lock_count;
 
618
  uint32_t i,tables,lock_count;
750
619
  DRIZZLE_LOCK *sql_lock;
751
620
  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));
 
621
  Table **to, **table_buf;
755
622
 
756
623
  *write_lock_used=0;
757
 
  for (i=tables=lock_count=0 ; i < count ; i++)
 
624
  for (i= tables= lock_count= 0 ; i < count ; i++)
758
625
  {
759
 
    TABLE *t= table_ptr[i];
 
626
    Table *t= table_ptr[i];
760
627
 
761
628
    if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE)
762
629
    {
763
 
      tables+= t->file->lock_count();
 
630
      tables++;
764
631
      lock_count++;
765
632
    }
766
633
  }
772
639
    from the first part immediately before calling thr_multi_lock().
773
640
  */
774
641
  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);
 
642
        malloc(sizeof(*sql_lock) +
 
643
               sizeof(THR_LOCK_DATA*) * tables * 2 +
 
644
               sizeof(table_ptr) * lock_count)))
 
645
    return NULL;
780
646
  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;
 
647
  to= table_buf= sql_lock->table= (Table**) (locks + tables * 2);
 
648
  sql_lock->table_count= lock_count;
783
649
 
784
650
  for (i=0 ; i < count ; i++)
785
651
  {
786
 
    TABLE *table;
 
652
    Table *table;
787
653
    enum thr_lock_type lock_type;
788
654
 
789
655
    if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
799
665
        /* Clear the lock type of the lock data that are stored already. */
800
666
        sql_lock->lock_count= locks - sql_lock->locks;
801
667
        reset_lock_data_and_free(&sql_lock);
802
 
        return(0);
 
668
        return NULL;
803
669
      }
804
670
    }
805
671
    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)
 
672
    locks= table->cursor->store_lock(session, locks,
 
673
                                   should_lock == false ? TL_IGNORE : lock_type);
 
674
    if (should_lock)
810
675
    {
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);
 
676
      table->lock_position=   (uint32_t) (to - table_buf);
 
677
      table->lock_data_start= (uint32_t) (locks_start - locks_buf);
 
678
      table->lock_count=      (uint32_t) (locks - locks_start);
 
679
      assert(table->lock_count == 1);
814
680
    }
815
681
    *to++= table;
816
682
  }
829
695
    And in the FLUSH case, the memory is released quickly anyway.
830
696
  */
831
697
  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);
 
698
 
 
699
  return sql_lock;
878
700
}
879
701
 
880
702
 
881
703
/**
882
704
  Put a not open table with an old refresh version in the table cache.
883
705
 
884
 
  @param thd                    Thread handler
 
706
  @param session                        Thread handler
885
707
  @param table_list             Lock first table in this list
886
708
  @param check_in_use           Do we need to check if table already in use by us
887
709
 
890
712
 
891
713
  @warning
892
714
    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
 
715
    lock_and_wait_for_table_name(removed) instead of this function as this works
894
716
    together with 'FLUSH TABLES WITH READ LOCK'
895
717
 
896
718
  @note
905
727
    > 0  table locked, but someone is using it
906
728
*/
907
729
 
908
 
int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use)
 
730
int lock_table_name(Session *session, TableList *table_list, bool check_in_use)
909
731
{
910
 
  TABLE *table;
 
732
  Table *table;
911
733
  char  key[MAX_DBKEY_LENGTH];
912
734
  char *db= table_list->db;
913
 
  uint  key_length;
 
735
  uint32_t  key_length;
914
736
  bool  found_locked_table= false;
915
737
  HASH_SEARCH_STATE state;
916
738
 
917
 
  key_length= create_table_def_key(thd, key, table_list, 0);
 
739
  key_length= table_list->create_table_def_key(key);
918
740
 
919
741
  if (check_in_use)
920
742
  {
921
743
    /* Only insert the table if we haven't insert it already */
922
 
    for (table=(TABLE*) hash_first(&open_cache, (uchar*)key,
 
744
    for (table=(Table*) hash_first(&open_cache, (unsigned char*)key,
923
745
                                   key_length, &state);
924
746
         table ;
925
 
         table = (TABLE*) hash_next(&open_cache,(uchar*) key,
 
747
         table = (Table*) hash_next(&open_cache,(unsigned char*) key,
926
748
                                    key_length, &state))
927
749
    {
928
750
      if (table->reginfo.lock_type < TL_WRITE)
929
751
      {
930
 
        if (table->in_use == thd)
 
752
        if (table->in_use == session)
931
753
          found_locked_table= true;
932
754
        continue;
933
755
      }
934
756
 
935
 
      if (table->in_use == thd)
 
757
      if (table->in_use == session)
936
758
      {
937
759
        table->s->version= 0;                  // Ensure no one can use this
938
760
        table->locked_by_name= 1;
939
 
        return(0);
 
761
        return 0;
940
762
      }
941
763
    }
942
764
  }
943
765
 
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);
 
766
  if (!(table= session->table_cache_insert_placeholder(key, key_length)))
 
767
    return -1;
957
768
 
958
769
  table_list->table=table;
959
770
 
960
771
  /* Return 1 if table is in use */
961
 
  return(test(remove_table_from_cache(thd, db, table_list->table_name,
 
772
  return(test(remove_table_from_cache(session, db, table_list->table_name,
962
773
             check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG)));
963
774
}
964
775
 
965
776
 
966
 
void unlock_table_name(THD *thd __attribute__((unused)),
967
 
                       TABLE_LIST *table_list)
 
777
void unlock_table_name(TableList *table_list)
968
778
{
969
779
  if (table_list->table)
970
780
  {
971
 
    hash_delete(&open_cache, (uchar*) table_list->table);
 
781
    hash_delete(&open_cache, (unsigned char*) table_list->table);
972
782
    broadcast_refresh();
973
783
  }
974
784
}
975
785
 
976
786
 
977
 
static bool locked_named_table(THD *thd __attribute__((unused)),
978
 
                               TABLE_LIST *table_list)
 
787
static bool locked_named_table(TableList *table_list)
979
788
{
980
789
  for (; table_list ; table_list=table_list->next_local)
981
790
  {
982
 
    TABLE *table= table_list->table;
 
791
    Table *table= table_list->table;
983
792
    if (table)
984
793
    {
985
 
      TABLE *save_next= table->next;
 
794
      Table *save_next= table->next;
986
795
      bool result;
987
796
      table->next= 0;
988
797
      result= table_is_used(table_list->table, 0);
995
804
}
996
805
 
997
806
 
998
 
bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list)
 
807
bool wait_for_locked_table_names(Session *session, TableList *table_list)
999
808
{
1000
 
  bool result=0;
 
809
  bool result= false;
1001
810
 
1002
811
  safe_mutex_assert_owner(&LOCK_open);
1003
812
 
1004
 
  while (locked_named_table(thd,table_list))
 
813
  while (locked_named_table(table_list))
1005
814
  {
1006
 
    if (thd->killed)
 
815
    if (session->killed)
1007
816
    {
1008
817
      result=1;
1009
818
      break;
1010
819
    }
1011
 
    wait_for_condition(thd, &LOCK_open, &COND_refresh);
1012
 
    pthread_mutex_lock(&LOCK_open);
 
820
    session->wait_for_condition(&LOCK_open, &COND_refresh);
 
821
    pthread_mutex_lock(&LOCK_open); /* Wait for a table to unlock and then lock it */
1013
822
  }
1014
 
  return(result);
 
823
  return result;
1015
824
}
1016
825
 
1017
826
 
1021
830
  REQUIREMENTS
1022
831
  - One must have a lock on LOCK_open when calling this
1023
832
 
1024
 
  @param thd                    Thread handle
1025
833
  @param table_list             Names of tables to lock
1026
834
 
1027
 
  @note
1028
 
    If you are just locking one table, you should use
1029
 
    lock_and_wait_for_table_name().
1030
 
 
1031
835
  @retval
1032
836
    0   ok
1033
837
  @retval
1034
838
    1   Fatal error (end of memory ?)
1035
839
*/
1036
840
 
1037
 
bool lock_table_names(THD *thd, TABLE_LIST *table_list)
 
841
bool lock_table_names(Session *session, TableList *table_list)
1038
842
{
1039
843
  bool got_all_locks=1;
1040
 
  TABLE_LIST *lock_table;
 
844
  TableList *lock_table;
1041
845
 
1042
846
  for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
1043
847
  {
1044
848
    int got_lock;
1045
 
    if ((got_lock=lock_table_name(thd,lock_table, true)) < 0)
 
849
    if ((got_lock= lock_table_name(session,lock_table, true)) < 0)
1046
850
      goto end;                                 // Fatal error
1047
851
    if (got_lock)
1048
852
      got_all_locks=0;                          // Someone is using table
1049
853
  }
1050
854
 
1051
855
  /* 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))
 
856
  if (!got_all_locks && wait_for_locked_table_names(session, table_list))
1053
857
    goto end;
1054
 
  return 0;
 
858
  return false;
1055
859
 
1056
860
end:
1057
 
  unlock_table_names(thd, table_list, lock_table);
1058
 
  return 1;
 
861
  unlock_table_names(table_list, lock_table);
 
862
 
 
863
  return true;
1059
864
}
1060
865
 
1061
866
 
1062
867
/**
1063
868
  Unlock all tables in list with a name lock.
1064
869
 
1065
 
  @param thd        Thread handle.
 
870
  @param session        Thread handle.
1066
871
  @param table_list Names of tables to lock.
1067
872
 
1068
 
  @note 
1069
 
    This function needs to be protected by LOCK_open. If we're 
 
873
  @note
 
874
    This function needs to be protected by LOCK_open. If we're
1070
875
    under LOCK TABLES, this function does not work as advertised. Namely,
1071
876
    it does not exclude other threads from using this table and does not
1072
877
    put an exclusive name lock on this table into the table cache.
1078
883
  @retval FALSE Name lock successfully acquired.
1079
884
*/
1080
885
 
1081
 
bool lock_table_names_exclusively(THD *thd, TABLE_LIST *table_list)
 
886
bool lock_table_names_exclusively(Session *session, TableList *table_list)
1082
887
{
1083
 
  if (lock_table_names(thd, table_list))
 
888
  if (lock_table_names(session, table_list))
1084
889
    return true;
1085
890
 
1086
891
  /*
1087
892
    Upgrade the table name locks from semi-exclusive to exclusive locks.
1088
893
  */
1089
 
  for (TABLE_LIST *table= table_list; table; table= table->next_global)
 
894
  for (TableList *table= table_list; table; table= table->next_global)
1090
895
  {
1091
896
    if (table->table)
1092
897
      table->table->open_placeholder= 1;
1096
901
 
1097
902
 
1098
903
/**
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
904
  Unlock all tables in list with a name lock.
1163
905
 
1164
906
  @param
1165
 
    thd                 Thread handle
1166
 
  @param
1167
907
    table_list          Names of tables to unlock
1168
908
  @param
1169
909
    last_table          Don't unlock any tables after this one.
1182
922
    1   Fatal error (end of memory ?)
1183
923
*/
1184
924
 
1185
 
void unlock_table_names(THD *thd, TABLE_LIST *table_list,
1186
 
                        TABLE_LIST *last_table)
 
925
void unlock_table_names(TableList *table_list, TableList *last_table)
1187
926
{
1188
 
  for (TABLE_LIST *table= table_list;
 
927
  for (TableList *table= table_list;
1189
928
       table != last_table;
1190
929
       table= table->next_local)
1191
 
    unlock_table_name(thd,table);
 
930
    unlock_table_name(table);
1192
931
  broadcast_refresh();
1193
 
  return;
1194
932
}
1195
933
 
1196
934
 
1220
958
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), table);
1221
959
  else
1222
960
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error);
1223
 
 
1224
 
  return;
1225
961
}
1226
962
 
1227
963
 
1285
1021
  If we have merged 1) and 3) into 1), we would have had this deadlock:
1286
1022
  imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
1287
1023
  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.
 
1024
  session1: SELECT * FROM t FOR UPDATE;
 
1025
  session2: UPDATE t SET a=1; # blocked by row-level locks of session1
 
1026
  session3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
 
1027
  table instance of session2
 
1028
  session1: COMMIT; # blocked by session3.
 
1029
  session1 blocks session2 which blocks session3 which blocks session1: deadlock.
1294
1030
 
1295
1031
  Note that we need to support that one thread does
1296
1032
  FLUSH TABLES WITH READ LOCK; and then COMMIT;
1300
1036
 
1301
1037
****************************************************************************/
1302
1038
 
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;
 
1039
volatile uint32_t global_read_lock=0;
 
1040
volatile uint32_t global_read_lock_blocks_commit=0;
 
1041
static volatile uint32_t protect_against_global_read_lock=0;
 
1042
static volatile uint32_t waiting_for_read_lock=0;
1307
1043
 
1308
1044
#define GOT_GLOBAL_READ_LOCK               1
1309
1045
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
1310
1046
 
1311
 
bool lock_global_read_lock(THD *thd)
 
1047
bool lock_global_read_lock(Session *session)
1312
1048
{
1313
 
  if (!thd->global_read_lock)
 
1049
  if (!session->global_read_lock)
1314
1050
  {
1315
1051
    const char *old_message;
1316
1052
    (void) pthread_mutex_lock(&LOCK_global_read_lock);
1317
 
    old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
 
1053
    old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1318
1054
                                "Waiting to get readlock");
1319
1055
 
1320
1056
    waiting_for_read_lock++;
1321
 
    while (protect_against_global_read_lock && !thd->killed)
 
1057
    while (protect_against_global_read_lock && !session->killed)
1322
1058
      pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1323
1059
    waiting_for_read_lock--;
1324
 
    if (thd->killed)
 
1060
    if (session->killed)
1325
1061
    {
1326
 
      thd->exit_cond(old_message);
1327
 
      return(1);
 
1062
      session->exit_cond(old_message);
 
1063
      return true;
1328
1064
    }
1329
 
    thd->global_read_lock= GOT_GLOBAL_READ_LOCK;
 
1065
    session->global_read_lock= GOT_GLOBAL_READ_LOCK;
1330
1066
    global_read_lock++;
1331
 
    thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
 
1067
    session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1332
1068
  }
1333
1069
  /*
1334
1070
    We DON'T set global_read_lock_blocks_commit now, it will be set after
1338
1074
    forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
1339
1075
    UPDATE and one does FLUSH TABLES WITH READ LOCK).
1340
1076
  */
1341
 
  return(0);
 
1077
  return false;
1342
1078
}
1343
1079
 
1344
1080
 
1345
 
void unlock_global_read_lock(THD *thd)
 
1081
void unlock_global_read_lock(Session *session)
1346
1082
{
1347
 
  uint tmp;
 
1083
  uint32_t tmp;
1348
1084
 
1349
1085
  pthread_mutex_lock(&LOCK_global_read_lock);
1350
1086
  tmp= --global_read_lock;
1351
 
  if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
 
1087
  if (session->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1352
1088
    --global_read_lock_blocks_commit;
1353
1089
  pthread_mutex_unlock(&LOCK_global_read_lock);
1354
1090
  /* Send the signal outside the mutex to avoid a context switch */
1356
1092
  {
1357
1093
    pthread_cond_broadcast(&COND_global_read_lock);
1358
1094
  }
1359
 
  thd->global_read_lock= 0;
1360
 
 
1361
 
  return;
 
1095
  session->global_read_lock= 0;
1362
1096
}
1363
1097
 
1364
1098
#define must_wait (global_read_lock &&                             \
1365
1099
                   (is_not_commit ||                               \
1366
1100
                    global_read_lock_blocks_commit))
1367
1101
 
1368
 
bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
 
1102
bool wait_if_global_read_lock(Session *session, bool abort_on_refresh,
1369
1103
                              bool is_not_commit)
1370
1104
{
1371
1105
  const char *old_message= NULL;
1381
1115
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
1382
1116
  if ((need_exit_cond= must_wait))
1383
1117
  {
1384
 
    if (thd->global_read_lock)          // This thread had the read locks
 
1118
    if (session->global_read_lock)              // This thread had the read locks
1385
1119
    {
1386
1120
      if (is_not_commit)
1387
1121
        my_message(ER_CANT_UPDATE_WITH_READLOCK,
1392
1126
        This allowance is needed to not break existing versions of innobackup
1393
1127
        which do a BEGIN; INSERT; FLUSH TABLES WITH READ LOCK; COMMIT.
1394
1128
      */
1395
 
      return(is_not_commit);
 
1129
      return is_not_commit;
1396
1130
    }
1397
 
    old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
 
1131
    old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1398
1132
                                "Waiting for release of readlock");
1399
 
    while (must_wait && ! thd->killed &&
1400
 
           (!abort_on_refresh || thd->version == refresh_version))
 
1133
    while (must_wait && ! session->killed &&
 
1134
           (!abort_on_refresh || session->version == refresh_version))
1401
1135
    {
1402
1136
      (void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1403
1137
    }
1404
 
    if (thd->killed)
 
1138
    if (session->killed)
1405
1139
      result=1;
1406
1140
  }
1407
1141
  if (!abort_on_refresh && !result)
1411
1145
    and if old_message is set
1412
1146
  */
1413
1147
  if (unlikely(need_exit_cond))
1414
 
    thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
 
1148
    session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1415
1149
  else
1416
1150
    pthread_mutex_unlock(&LOCK_global_read_lock);
1417
 
  return(result);
 
1151
  return result;
1418
1152
}
1419
1153
 
1420
1154
 
1421
 
void start_waiting_global_read_lock(THD *thd)
 
1155
void start_waiting_global_read_lock(Session *session)
1422
1156
{
1423
1157
  bool tmp;
1424
 
  if (unlikely(thd->global_read_lock))
 
1158
  if (unlikely(session->global_read_lock))
1425
1159
    return;
1426
1160
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
1427
1161
  tmp= (!--protect_against_global_read_lock &&
1433
1167
}
1434
1168
 
1435
1169
 
1436
 
bool make_global_read_lock_block_commit(THD *thd)
 
1170
bool make_global_read_lock_block_commit(Session *session)
1437
1171
{
1438
1172
  bool error;
1439
1173
  const char *old_message;
1441
1175
    If we didn't succeed lock_global_read_lock(), or if we already suceeded
1442
1176
    make_global_read_lock_block_commit(), do nothing.
1443
1177
  */
1444
 
  if (thd->global_read_lock != GOT_GLOBAL_READ_LOCK)
1445
 
    return(0);
 
1178
  if (session->global_read_lock != GOT_GLOBAL_READ_LOCK)
 
1179
    return false;
1446
1180
  pthread_mutex_lock(&LOCK_global_read_lock);
1447
1181
  /* increment this BEFORE waiting on cond (otherwise race cond) */
1448
1182
  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,
 
1183
  old_message= session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1452
1184
                               "Waiting for all running commits to finish");
1453
 
  while (protect_against_global_read_lock && !thd->killed)
 
1185
  while (protect_against_global_read_lock && !session->killed)
1454
1186
    pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1455
 
  protect_against_global_read_lock--;
1456
 
  if ((error= test(thd->killed)))
 
1187
  if ((error= test(session->killed)))
1457
1188
    global_read_lock_blocks_commit--; // undo what we did
1458
1189
  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);
 
1190
    session->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
 
1191
  session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
 
1192
  return error;
1462
1193
}
1463
1194
 
1464
1195
 
1483
1214
 
1484
1215
void broadcast_refresh(void)
1485
1216
{
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);
 
1217
  pthread_cond_broadcast(&COND_refresh);
 
1218
  pthread_cond_broadcast(&COND_global_read_lock);
1710
1219
}
1711
1220
 
1712
1221