~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/lock.cc

  • Committer: Brian Aker
  • Date: 2008-10-06 06:47:29 UTC
  • Revision ID: brian@tangent.org-20081006064729-2i9mhjkzyvow9xsm
RemoveĀ uint.

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(session,locktype) for each table.
 
33
      table_handler->external_lock(thd,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(session, F_UNLCK) for each table.
 
38
    table_handler->external_lock(thd, 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(session, F_UNLOCK) on these.
 
46
    and we never call external_lock(thd, F_UNLOCK) on these.
47
47
 
48
48
  When using LOCK TABLES:
49
49
 
50
50
  - LOCK Table will call mysql_lock_tables() for all tables.
51
51
    mysql_lock_tables() will call
52
 
    table_handler->external_lock(session,locktype) for each table.
 
52
    table_handler->external_lock(thd,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(Session)
 
55
  - For each statement, we will call table_handler->start_stmt(THD)
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(session);
 
61
  - When statement is done, we will call ha_commit_stmt(thd);
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(session, locktype) fails, we call
67
 
  table_handler->external_lock(session, F_UNLCK) for each table that was locked,
 
66
  If table_handler->external_lock(thd, locktype) fails, we call
 
67
  table_handler->external_lock(thd, F_UNLCK) for each table that was locked,
68
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 malloc() ONLY when using LOCK TABLES command or when
 
72
  Change to use my_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/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>
 
76
#include <drizzled/drizzled_error_messages.h>
82
77
 
83
78
/**
84
79
  @defgroup Locking Locking
91
86
#define GET_LOCK_UNLOCK         1
92
87
#define GET_LOCK_STORE_LOCKS    2
93
88
 
94
 
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table,
95
 
                                   uint32_t count,
96
 
                                   uint32_t flags, Table **write_locked);
97
 
static int lock_external(Session *session, Table **table,uint32_t count);
98
 
static int unlock_external(Session *session, Table **table,uint32_t count);
 
89
static DRIZZLE_LOCK *get_lock_data(THD *thd, Table **table,uint32_t count,
 
90
                                 uint32_t flags, Table **write_locked);
 
91
static int lock_external(THD *thd, Table **table,uint32_t count);
 
92
static int unlock_external(THD *thd, Table **table,uint32_t count);
99
93
static void print_lock_error(int error, const char *);
100
94
 
101
95
/*
103
97
 
104
98
  SYNOPSIS
105
99
    mysql_lock_tables()
106
 
    session                         The current thread.
 
100
    thd                         The current thread.
107
101
    tables                      An array of pointers to the tables to lock.
108
102
    count                       The number of tables to lock.
109
103
    flags                       Options:
110
104
      DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK      Ignore a global read lock
 
105
      DRIZZLE_LOCK_IGNORE_GLOBAL_READ_ONLY      Ignore SET GLOBAL READ_ONLY
111
106
      DRIZZLE_LOCK_IGNORE_FLUSH                 Ignore a flush tables.
112
107
      DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN        Instead of reopening altered
113
108
                                              or dropped tables by itself,
165
160
}
166
161
 
167
162
 
168
 
DRIZZLE_LOCK *mysql_lock_tables(Session *session, Table **tables, uint32_t count,
 
163
DRIZZLE_LOCK *mysql_lock_tables(THD *thd, Table **tables, uint32_t count,
169
164
                              uint32_t flags, bool *need_reopen)
170
165
{
171
166
  DRIZZLE_LOCK *sql_lock;
176
171
 
177
172
  for (;;)
178
173
  {
179
 
    if (! (sql_lock= get_lock_data(session, tables, count, GET_LOCK_STORE_LOCKS,
 
174
    if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS,
180
175
                                   &write_lock_used)))
181
176
      break;
182
177
 
187
182
        Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
188
183
        Wait until the lock is gone
189
184
      */
190
 
      if (wait_if_global_read_lock(session, 1, 1))
 
185
      if (wait_if_global_read_lock(thd, 1, 1))
191
186
      {
192
187
        /* Clear the lock type of all lock data to avoid reusage. */
193
188
        reset_lock_data_and_free(&sql_lock);
194
189
        break;
195
190
      }
196
 
      if (session->version != refresh_version)
 
191
      if (thd->version != refresh_version)
197
192
      {
198
193
        /* Clear the lock type of all lock data to avoid reusage. */
199
194
        reset_lock_data_and_free(&sql_lock);
201
196
      }
202
197
    }
203
198
 
204
 
    session->set_proc_info("System lock");
205
 
    if (sql_lock->table_count && lock_external(session, sql_lock->table,
 
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
215
                                               sql_lock->table_count))
207
216
    {
208
217
      /* Clear the lock type of all lock data to avoid reusage. */
209
218
      reset_lock_data_and_free(&sql_lock);
210
219
      break;
211
220
    }
212
 
    session->set_proc_info("Table lock");
 
221
    thd_proc_info(thd, "Table lock");
213
222
    /* Copy the lock data array. thr_multi_lock() reorders its contens. */
214
223
    memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
215
224
           sql_lock->lock_count * sizeof(*sql_lock->locks));
217
226
    rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
218
227
                                                     sql_lock->lock_count,
219
228
                                                     sql_lock->lock_count,
220
 
                                                     session->lock_id)];
 
229
                                                     thd->lock_id)];
221
230
    if (rc > 1)                                 /* a timeout or a deadlock */
222
231
    {
223
232
      if (sql_lock->table_count)
224
 
        unlock_external(session, sql_lock->table, sql_lock->table_count);
 
233
        unlock_external(thd, sql_lock->table, sql_lock->table_count);
225
234
      reset_lock_data_and_free(&sql_lock);
226
235
      my_error(rc, MYF(0));
227
236
      break;
228
237
    }
229
238
    else if (rc == 1)                           /* aborted */
230
239
    {
231
 
      session->some_tables_deleted=1;           // Try again
 
240
      thd->some_tables_deleted=1;               // Try again
232
241
      sql_lock->lock_count= 0;                  // Locks are already freed
233
242
      // Fall through: unlock, reset lock data, free and retry
234
243
    }
235
 
    else if (!session->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
 
244
    else if (!thd->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
236
245
    {
237
246
      /*
238
247
        Thread was killed or lock aborted. Let upper level close all
240
249
      */
241
250
      break;
242
251
    }
243
 
    else if (!session->open_tables)
 
252
    else if (!thd->open_tables)
244
253
    {
245
254
      // Only using temporary tables, no need to unlock
246
 
      session->some_tables_deleted=0;
 
255
      thd->some_tables_deleted=0;
247
256
      break;
248
257
    }
249
 
    session->set_proc_info(0);
 
258
    thd_proc_info(thd, 0);
250
259
 
251
260
    /* going to retry, unlock all tables */
252
261
    if (sql_lock->lock_count)
253
262
        thr_multi_unlock(sql_lock->locks, sql_lock->lock_count);
254
263
 
255
264
    if (sql_lock->table_count)
256
 
      unlock_external(session, sql_lock->table, sql_lock->table_count);
 
265
      unlock_external(thd, sql_lock->table, sql_lock->table_count);
257
266
 
258
267
    /*
259
268
      If thr_multi_lock fails it resets lock type for tables, which
267
276
      *need_reopen= true;
268
277
      break;
269
278
    }
270
 
    if (wait_for_tables(session))
 
279
    if (wait_for_tables(thd))
271
280
      break;                                    // Couldn't open tables
272
281
  }
273
 
  session->set_proc_info(0);
274
 
  if (session->killed)
 
282
  thd_proc_info(thd, 0);
 
283
  if (thd->killed)
275
284
  {
276
 
    session->send_kill_message();
 
285
    thd->send_kill_message();
277
286
    if (sql_lock)
278
287
    {
279
 
      mysql_unlock_tables(session,sql_lock);
 
288
      mysql_unlock_tables(thd,sql_lock);
280
289
      sql_lock=0;
281
290
    }
282
291
  }
283
292
 
284
 
  session->set_time_after_lock();
 
293
  thd->set_time_after_lock();
285
294
  return (sql_lock);
286
295
}
287
296
 
288
297
 
289
 
static int lock_external(Session *session, Table **tables, uint32_t count)
 
298
static int lock_external(THD *thd, Table **tables, uint32_t count)
290
299
{
291
300
  register uint32_t i;
292
301
  int lock_type,error;
299
308
         (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
300
309
      lock_type=F_RDLCK;
301
310
 
302
 
    if ((error=(*tables)->file->ha_external_lock(session,lock_type)))
 
311
    if ((error=(*tables)->file->ha_external_lock(thd,lock_type)))
303
312
    {
304
313
      print_lock_error(error, (*tables)->file->table_type());
305
314
      while (--i)
306
315
      {
307
316
        tables--;
308
 
        (*tables)->file->ha_external_lock(session, F_UNLCK);
 
317
        (*tables)->file->ha_external_lock(thd, F_UNLCK);
309
318
        (*tables)->current_lock=F_UNLCK;
310
319
      }
311
320
      return(error);
320
329
}
321
330
 
322
331
 
323
 
void mysql_unlock_tables(Session *session, DRIZZLE_LOCK *sql_lock)
 
332
void mysql_unlock_tables(THD *thd, DRIZZLE_LOCK *sql_lock)
324
333
{
325
334
  if (sql_lock->lock_count)
326
335
    thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
327
336
  if (sql_lock->table_count)
328
 
    unlock_external(session,sql_lock->table,sql_lock->table_count);
 
337
    unlock_external(thd,sql_lock->table,sql_lock->table_count);
329
338
  free((unsigned char*) sql_lock);
330
339
  return;
331
340
}
336
345
  This will work even if get_lock_data fails (next unlock will free all)
337
346
*/
338
347
 
339
 
void mysql_unlock_some_tables(Session *session, Table **table,uint32_t count)
 
348
void mysql_unlock_some_tables(THD *thd, Table **table,uint32_t count)
340
349
{
341
350
  DRIZZLE_LOCK *sql_lock;
342
351
  Table *write_lock_used;
343
 
  if ((sql_lock= get_lock_data(session, table, count, GET_LOCK_UNLOCK,
 
352
  if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK,
344
353
                               &write_lock_used)))
345
 
    mysql_unlock_tables(session, sql_lock);
 
354
    mysql_unlock_tables(thd, sql_lock);
346
355
}
347
356
 
348
357
 
350
359
  unlock all tables locked for read.
351
360
*/
352
361
 
353
 
void mysql_unlock_read_tables(Session *session, DRIZZLE_LOCK *sql_lock)
 
362
void mysql_unlock_read_tables(THD *thd, DRIZZLE_LOCK *sql_lock)
354
363
{
355
364
  uint32_t i,found;
356
365
 
388
397
  /* Unlock all read locked tables */
389
398
  if (i != found)
390
399
  {
391
 
    unlock_external(session,table,i-found);
 
400
    unlock_external(thd,table,i-found);
392
401
    sql_lock->table_count=found;
393
402
  }
394
403
  /* Fix the lock positions in Table */
419
428
  unlock_external() we call handler::external_lock(F_UNLCK) only
420
429
  if table->current_lock is not F_UNLCK.
421
430
 
422
 
  @param  session             thread context
 
431
  @param  thd             thread context
423
432
  @param  locked          list of locked tables
424
433
  @param  table           the table to unlock
425
434
  @param  always_unlock   specify explicitly if the legacy side
426
435
                          effect is desired.
427
436
*/
428
437
 
429
 
void mysql_lock_remove(Session *session, DRIZZLE_LOCK *locked,Table *table,
 
438
void mysql_lock_remove(THD *thd, DRIZZLE_LOCK *locked,Table *table,
430
439
                       bool always_unlock)
431
440
{
432
441
  if (always_unlock == true)
433
 
    mysql_unlock_some_tables(session, &table, /* table count */ 1);
 
442
    mysql_unlock_some_tables(thd, &table, /* table count */ 1);
434
443
  if (locked)
435
444
  {
436
445
    register uint32_t i;
446
455
 
447
456
        /* Unlock if not yet unlocked */
448
457
        if (always_unlock == false)
449
 
          mysql_unlock_some_tables(session, &table, /* table count */ 1);
 
458
          mysql_unlock_some_tables(thd, &table, /* table count */ 1);
450
459
 
451
460
        /* Decrement table_count in advance, making below expressions easier */
452
461
        old_tables= --locked->table_count;
455
464
        removed_locks= table->lock_count;
456
465
 
457
466
        /* Move down all table pointers above 'i'. */
458
 
        memmove((locked->table+i), (locked->table+i+1),
459
 
                (old_tables - i) * sizeof(Table*));
 
467
        memcpy((locked->table+i), (locked->table+i+1),
 
468
               (old_tables - i) * sizeof(Table*));
460
469
 
461
470
        lock_data_end= table->lock_data_start + table->lock_count;
462
471
        /* Move down all lock data pointers above 'table->lock_data_end-1' */
463
 
        memmove((locked->locks + table->lock_data_start),
464
 
                (locked->locks + lock_data_end),
465
 
                (locked->lock_count - lock_data_end) *
466
 
                sizeof(THR_LOCK_DATA*));
 
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*));
467
476
 
468
477
        /*
469
478
          Fix moved table elements.
491
500
 
492
501
/* Downgrade all locks on a table to new WRITE level from WRITE_ONLY */
493
502
 
494
 
void mysql_lock_downgrade_write(Session *session, Table *table,
 
503
void mysql_lock_downgrade_write(THD *thd, Table *table,
495
504
                                thr_lock_type new_lock_type)
496
505
{
497
506
  DRIZZLE_LOCK *locked;
498
507
  Table *write_lock_used;
499
 
  if ((locked = get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
 
508
  if ((locked = get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
500
509
                              &write_lock_used)))
501
510
  {
502
511
    for (uint32_t i=0; i < locked->lock_count; i++)
508
517
 
509
518
/** Abort all other threads waiting to get lock in table. */
510
519
 
511
 
void mysql_lock_abort(Session *session, Table *table, bool upgrade_lock)
 
520
void mysql_lock_abort(THD *thd, Table *table, bool upgrade_lock)
512
521
{
513
522
  DRIZZLE_LOCK *locked;
514
523
  Table *write_lock_used;
515
524
 
516
 
  if ((locked= get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
 
525
  if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
517
526
                             &write_lock_used)))
518
527
  {
519
528
    for (uint32_t i=0; i < locked->lock_count; i++)
527
536
/**
528
537
  Abort one thread / table combination.
529
538
 
530
 
  @param session           Thread handler
 
539
  @param thd       Thread handler
531
540
  @param table     Table that should be removed from lock queue
532
541
 
533
542
  @retval
536
545
    1  Table was locked by at least one other thread
537
546
*/
538
547
 
539
 
bool mysql_lock_abort_for_thread(Session *session, Table *table)
 
548
bool mysql_lock_abort_for_thread(THD *thd, Table *table)
540
549
{
541
550
  DRIZZLE_LOCK *locked;
542
551
  Table *write_lock_used;
543
552
  bool result= false;
544
553
 
545
 
  if ((locked= get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
 
554
  if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
546
555
                             &write_lock_used)))
547
556
  {
548
557
    for (uint32_t i=0; i < locked->lock_count; i++)
563
572
  Table **table, **end_table;
564
573
 
565
574
  if (!(sql_lock= (DRIZZLE_LOCK*)
566
 
        malloc(sizeof(*sql_lock)+
567
 
               sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+
568
 
               sizeof(Table*)*(a->table_count+b->table_count))))
 
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))))
569
578
    return(0);                          // Fatal error
570
579
  sql_lock->lock_count=a->lock_count+b->lock_count;
571
580
  sql_lock->table_count=a->table_count+b->table_count;
605
614
  get_lock_data(). If we allow two opens on temporary tables later,
606
615
  both functions should be checked.
607
616
 
608
 
  @param session                 The current thread.
 
617
  @param thd                 The current thread.
609
618
  @param needle              The table to check for duplicate lock.
610
619
  @param haystack            The list of tables to search for the dup lock.
611
620
 
621
630
    !NULL   First table from 'haystack' that matches a lock on 'needle'.
622
631
*/
623
632
 
624
 
TableList *mysql_lock_have_duplicate(Session *session, TableList *needle,
 
633
TableList *mysql_lock_have_duplicate(THD *thd, TableList *needle,
625
634
                                      TableList *haystack)
626
635
{
627
636
  DRIZZLE_LOCK            *mylock;
646
655
    goto end;
647
656
 
648
657
  /* Get command lock or LOCK TABLES lock. Maybe empty for INSERT DELAYED. */
649
 
  if (! (mylock= session->lock ? session->lock : session->locked_tables))
 
658
  if (! (mylock= thd->lock ? thd->lock : thd->locked_tables))
650
659
    goto end;
651
660
 
652
661
  /* If we have less than two tables, we cannot have duplicates. */
701
710
 
702
711
/** Unlock a set of external. */
703
712
 
704
 
static int unlock_external(Session *session, Table **table,uint32_t count)
 
713
static int unlock_external(THD *thd, Table **table,uint32_t count)
705
714
{
706
715
  int error,error_code;
707
716
 
711
720
    if ((*table)->current_lock != F_UNLCK)
712
721
    {
713
722
      (*table)->current_lock = F_UNLCK;
714
 
      if ((error=(*table)->file->ha_external_lock(session, F_UNLCK)))
 
723
      if ((error=(*table)->file->ha_external_lock(thd, F_UNLCK)))
715
724
      {
716
725
        error_code=error;
717
726
        print_lock_error(error_code, (*table)->file->table_type());
726
735
/**
727
736
  Get lock structures from table structs and initialize locks.
728
737
 
729
 
  @param session                    Thread handler
 
738
  @param thd                Thread handler
730
739
  @param table_ptr          Pointer to tables that should be locks
731
740
  @param flags              One of:
732
741
           - GET_LOCK_UNLOCK      : If we should send TL_IGNORE to store lock
734
743
  @param write_lock_used   Store pointer to last table with WRITE_ALLOW_WRITE
735
744
*/
736
745
 
737
 
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table_ptr, uint32_t count,
 
746
static DRIZZLE_LOCK *get_lock_data(THD *thd, Table **table_ptr, uint32_t count,
738
747
                                 uint32_t flags, Table **write_lock_used)
739
748
{
740
749
  uint32_t i,tables,lock_count;
763
772
    from the first part immediately before calling thr_multi_lock().
764
773
  */
765
774
  if (!(sql_lock= (DRIZZLE_LOCK*)
766
 
        malloc(sizeof(*sql_lock) +
767
 
               sizeof(THR_LOCK_DATA*) * tables * 2 +
768
 
               sizeof(table_ptr) * lock_count)))
 
775
        my_malloc(sizeof(*sql_lock) +
 
776
                  sizeof(THR_LOCK_DATA*) * tables * 2 +
 
777
                  sizeof(table_ptr) * lock_count,
 
778
                  MYF(0))))
769
779
    return(0);
770
780
  locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
771
781
  to= table_buf= sql_lock->table= (Table**) (locks + tables * 2);
793
803
      }
794
804
    }
795
805
    locks_start= locks;
796
 
    locks= table->file->store_lock(session, locks,
 
806
    locks= table->file->store_lock(thd, locks,
797
807
                                   (flags & GET_LOCK_UNLOCK) ? TL_IGNORE :
798
808
                                   lock_type);
799
809
    if (flags & GET_LOCK_STORE_LOCKS)
831
841
/**
832
842
  Lock and wait for the named lock.
833
843
 
834
 
  @param session                        Thread handler
 
844
  @param thd                    Thread handler
835
845
  @param table_list             Lock first table in this list
836
846
 
837
847
 
844
854
    1   error
845
855
*/
846
856
 
847
 
int lock_and_wait_for_table_name(Session *session, TableList *table_list)
 
857
int lock_and_wait_for_table_name(THD *thd, TableList *table_list)
848
858
{
849
859
  int lock_retcode;
850
860
  int error= -1;
851
861
 
852
 
  if (wait_if_global_read_lock(session, 0, 1))
 
862
  if (wait_if_global_read_lock(thd, 0, 1))
853
863
    return(1);
854
864
  pthread_mutex_lock(&LOCK_open);
855
 
  if ((lock_retcode = lock_table_name(session, table_list, true)) < 0)
 
865
  if ((lock_retcode = lock_table_name(thd, table_list, true)) < 0)
856
866
    goto end;
857
 
  if (lock_retcode && wait_for_locked_table_names(session, table_list))
 
867
  if (lock_retcode && wait_for_locked_table_names(thd, table_list))
858
868
  {
859
 
    unlock_table_name(session, table_list);
 
869
    unlock_table_name(thd, table_list);
860
870
    goto end;
861
871
  }
862
872
  error=0;
863
873
 
864
874
end:
865
875
  pthread_mutex_unlock(&LOCK_open);
866
 
  start_waiting_global_read_lock(session);
 
876
  start_waiting_global_read_lock(thd);
867
877
  return(error);
868
878
}
869
879
 
871
881
/**
872
882
  Put a not open table with an old refresh version in the table cache.
873
883
 
874
 
  @param session                        Thread handler
 
884
  @param thd                    Thread handler
875
885
  @param table_list             Lock first table in this list
876
886
  @param check_in_use           Do we need to check if table already in use by us
877
887
 
895
905
    > 0  table locked, but someone is using it
896
906
*/
897
907
 
898
 
int lock_table_name(Session *session, TableList *table_list, bool check_in_use)
 
908
int lock_table_name(THD *thd, TableList *table_list, bool check_in_use)
899
909
{
900
910
  Table *table;
901
911
  char  key[MAX_DBKEY_LENGTH];
904
914
  bool  found_locked_table= false;
905
915
  HASH_SEARCH_STATE state;
906
916
 
907
 
  key_length= create_table_def_key(session, key, table_list, 0);
 
917
  key_length= create_table_def_key(thd, key, table_list, 0);
908
918
 
909
919
  if (check_in_use)
910
920
  {
917
927
    {
918
928
      if (table->reginfo.lock_type < TL_WRITE)
919
929
      {
920
 
        if (table->in_use == session)
 
930
        if (table->in_use == thd)
921
931
          found_locked_table= true;
922
932
        continue;
923
933
      }
924
934
 
925
 
      if (table->in_use == session)
 
935
      if (table->in_use == thd)
926
936
      {
927
937
        table->s->version= 0;                  // Ensure no one can use this
928
938
        table->locked_by_name= 1;
931
941
    }
932
942
  }
933
943
 
934
 
  if (session->locked_tables && session->locked_tables->table_count &&
935
 
      ! find_temporary_table(session, table_list->db, table_list->table_name))
 
944
  if (thd->locked_tables && thd->locked_tables->table_count &&
 
945
      ! find_temporary_table(thd, table_list->db, table_list->table_name))
936
946
  {
937
947
    if (found_locked_table)
938
948
      my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_list->alias);
942
952
    return(-1);
943
953
  }
944
954
 
945
 
  if (!(table= table_cache_insert_placeholder(session, key, key_length)))
 
955
  if (!(table= table_cache_insert_placeholder(thd, key, key_length)))
946
956
    return(-1);
947
957
 
948
958
  table_list->table=table;
949
959
 
950
960
  /* Return 1 if table is in use */
951
 
  return(test(remove_table_from_cache(session, db, table_list->table_name,
 
961
  return(test(remove_table_from_cache(thd, db, table_list->table_name,
952
962
             check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG)));
953
963
}
954
964
 
955
965
 
956
 
void unlock_table_name(Session *,
 
966
void unlock_table_name(THD *thd __attribute__((unused)),
957
967
                       TableList *table_list)
958
968
{
959
969
  if (table_list->table)
964
974
}
965
975
 
966
976
 
967
 
static bool locked_named_table(Session *,
 
977
static bool locked_named_table(THD *thd __attribute__((unused)),
968
978
                               TableList *table_list)
969
979
{
970
980
  for (; table_list ; table_list=table_list->next_local)
985
995
}
986
996
 
987
997
 
988
 
bool wait_for_locked_table_names(Session *session, TableList *table_list)
 
998
bool wait_for_locked_table_names(THD *thd, TableList *table_list)
989
999
{
990
1000
  bool result=0;
991
1001
 
992
1002
  safe_mutex_assert_owner(&LOCK_open);
993
1003
 
994
 
  while (locked_named_table(session,table_list))
 
1004
  while (locked_named_table(thd,table_list))
995
1005
  {
996
 
    if (session->killed)
 
1006
    if (thd->killed)
997
1007
    {
998
1008
      result=1;
999
1009
      break;
1000
1010
    }
1001
 
    wait_for_condition(session, &LOCK_open, &COND_refresh);
 
1011
    wait_for_condition(thd, &LOCK_open, &COND_refresh);
1002
1012
    pthread_mutex_lock(&LOCK_open);
1003
1013
  }
1004
1014
  return(result);
1011
1021
  REQUIREMENTS
1012
1022
  - One must have a lock on LOCK_open when calling this
1013
1023
 
1014
 
  @param session                        Thread handle
 
1024
  @param thd                    Thread handle
1015
1025
  @param table_list             Names of tables to lock
1016
1026
 
1017
1027
  @note
1024
1034
    1   Fatal error (end of memory ?)
1025
1035
*/
1026
1036
 
1027
 
bool lock_table_names(Session *session, TableList *table_list)
 
1037
bool lock_table_names(THD *thd, TableList *table_list)
1028
1038
{
1029
1039
  bool got_all_locks=1;
1030
1040
  TableList *lock_table;
1032
1042
  for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
1033
1043
  {
1034
1044
    int got_lock;
1035
 
    if ((got_lock=lock_table_name(session,lock_table, true)) < 0)
 
1045
    if ((got_lock=lock_table_name(thd,lock_table, true)) < 0)
1036
1046
      goto end;                                 // Fatal error
1037
1047
    if (got_lock)
1038
1048
      got_all_locks=0;                          // Someone is using table
1039
1049
  }
1040
1050
 
1041
1051
  /* If some table was in use, wait until we got the lock */
1042
 
  if (!got_all_locks && wait_for_locked_table_names(session, table_list))
 
1052
  if (!got_all_locks && wait_for_locked_table_names(thd, table_list))
1043
1053
    goto end;
1044
1054
  return 0;
1045
1055
 
1046
1056
end:
1047
 
  unlock_table_names(session, table_list, lock_table);
 
1057
  unlock_table_names(thd, table_list, lock_table);
1048
1058
  return 1;
1049
1059
}
1050
1060
 
1052
1062
/**
1053
1063
  Unlock all tables in list with a name lock.
1054
1064
 
1055
 
  @param session        Thread handle.
 
1065
  @param thd        Thread handle.
1056
1066
  @param table_list Names of tables to lock.
1057
1067
 
1058
 
  @note
1059
 
    This function needs to be protected by LOCK_open. If we're
 
1068
  @note 
 
1069
    This function needs to be protected by LOCK_open. If we're 
1060
1070
    under LOCK TABLES, this function does not work as advertised. Namely,
1061
1071
    it does not exclude other threads from using this table and does not
1062
1072
    put an exclusive name lock on this table into the table cache.
1068
1078
  @retval FALSE Name lock successfully acquired.
1069
1079
*/
1070
1080
 
1071
 
bool lock_table_names_exclusively(Session *session, TableList *table_list)
 
1081
bool lock_table_names_exclusively(THD *thd, TableList *table_list)
1072
1082
{
1073
 
  if (lock_table_names(session, table_list))
 
1083
  if (lock_table_names(thd, table_list))
1074
1084
    return true;
1075
1085
 
1076
1086
  /*
1088
1098
/**
1089
1099
  Test is 'table' is protected by an exclusive name lock.
1090
1100
 
1091
 
  @param[in] session        The current thread handler
 
1101
  @param[in] thd        The current thread handler
1092
1102
  @param[in] table_list Table container containing the single table to be
1093
1103
                        tested
1094
1104
 
1100
1110
*/
1101
1111
 
1102
1112
bool
1103
 
is_table_name_exclusively_locked_by_this_thread(Session *session,
 
1113
is_table_name_exclusively_locked_by_this_thread(THD *thd,
1104
1114
                                                TableList *table_list)
1105
1115
{
1106
1116
  char  key[MAX_DBKEY_LENGTH];
1107
1117
  uint32_t  key_length;
1108
1118
 
1109
 
  key_length= create_table_def_key(session, key, table_list, 0);
 
1119
  key_length= create_table_def_key(thd, key, table_list, 0);
1110
1120
 
1111
 
  return is_table_name_exclusively_locked_by_this_thread(session, (unsigned char *)key,
 
1121
  return is_table_name_exclusively_locked_by_this_thread(thd, (unsigned char *)key,
1112
1122
                                                         key_length);
1113
1123
}
1114
1124
 
1116
1126
/**
1117
1127
  Test is 'table key' is protected by an exclusive name lock.
1118
1128
 
1119
 
  @param[in] session        The current thread handler.
 
1129
  @param[in] thd        The current thread handler.
1120
1130
  @param[in] key
1121
1131
  @param[in] key_length
1122
1132
 
1127
1137
 */
1128
1138
 
1129
1139
bool
1130
 
is_table_name_exclusively_locked_by_this_thread(Session *session, unsigned char *key,
 
1140
is_table_name_exclusively_locked_by_this_thread(THD *thd, unsigned char *key,
1131
1141
                                                int key_length)
1132
1142
{
1133
1143
  HASH_SEARCH_STATE state;
1139
1149
       table= (Table*) hash_next(&open_cache, key,
1140
1150
                                 key_length, &state))
1141
1151
  {
1142
 
    if (table->in_use == session &&
 
1152
    if (table->in_use == thd &&
1143
1153
        table->open_placeholder == 1 &&
1144
1154
        table->s->version == 0)
1145
1155
      return true;
1152
1162
  Unlock all tables in list with a name lock.
1153
1163
 
1154
1164
  @param
1155
 
    session                     Thread handle
 
1165
    thd                 Thread handle
1156
1166
  @param
1157
1167
    table_list          Names of tables to unlock
1158
1168
  @param
1172
1182
    1   Fatal error (end of memory ?)
1173
1183
*/
1174
1184
 
1175
 
void unlock_table_names(Session *session, TableList *table_list,
 
1185
void unlock_table_names(THD *thd, TableList *table_list,
1176
1186
                        TableList *last_table)
1177
1187
{
1178
1188
  for (TableList *table= table_list;
1179
1189
       table != last_table;
1180
1190
       table= table->next_local)
1181
 
    unlock_table_name(session,table);
 
1191
    unlock_table_name(thd,table);
1182
1192
  broadcast_refresh();
1183
1193
  return;
1184
1194
}
1275
1285
  If we have merged 1) and 3) into 1), we would have had this deadlock:
1276
1286
  imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
1277
1287
  table t.
1278
 
  session1: SELECT * FROM t FOR UPDATE;
1279
 
  session2: UPDATE t SET a=1; # blocked by row-level locks of session1
1280
 
  session3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
1281
 
  table instance of session2
1282
 
  session1: COMMIT; # blocked by session3.
1283
 
  session1 blocks session2 which blocks session3 which blocks session1: deadlock.
 
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.
1284
1294
 
1285
1295
  Note that we need to support that one thread does
1286
1296
  FLUSH TABLES WITH READ LOCK; and then COMMIT;
1298
1308
#define GOT_GLOBAL_READ_LOCK               1
1299
1309
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
1300
1310
 
1301
 
bool lock_global_read_lock(Session *session)
 
1311
bool lock_global_read_lock(THD *thd)
1302
1312
{
1303
 
  if (!session->global_read_lock)
 
1313
  if (!thd->global_read_lock)
1304
1314
  {
1305
1315
    const char *old_message;
1306
1316
    (void) pthread_mutex_lock(&LOCK_global_read_lock);
1307
 
    old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
 
1317
    old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1308
1318
                                "Waiting to get readlock");
1309
1319
 
1310
1320
    waiting_for_read_lock++;
1311
 
    while (protect_against_global_read_lock && !session->killed)
 
1321
    while (protect_against_global_read_lock && !thd->killed)
1312
1322
      pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1313
1323
    waiting_for_read_lock--;
1314
 
    if (session->killed)
 
1324
    if (thd->killed)
1315
1325
    {
1316
 
      session->exit_cond(old_message);
 
1326
      thd->exit_cond(old_message);
1317
1327
      return(1);
1318
1328
    }
1319
 
    session->global_read_lock= GOT_GLOBAL_READ_LOCK;
 
1329
    thd->global_read_lock= GOT_GLOBAL_READ_LOCK;
1320
1330
    global_read_lock++;
1321
 
    session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
 
1331
    thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1322
1332
  }
1323
1333
  /*
1324
1334
    We DON'T set global_read_lock_blocks_commit now, it will be set after
1332
1342
}
1333
1343
 
1334
1344
 
1335
 
void unlock_global_read_lock(Session *session)
 
1345
void unlock_global_read_lock(THD *thd)
1336
1346
{
1337
1347
  uint32_t tmp;
1338
1348
 
1339
1349
  pthread_mutex_lock(&LOCK_global_read_lock);
1340
1350
  tmp= --global_read_lock;
1341
 
  if (session->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
 
1351
  if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1342
1352
    --global_read_lock_blocks_commit;
1343
1353
  pthread_mutex_unlock(&LOCK_global_read_lock);
1344
1354
  /* Send the signal outside the mutex to avoid a context switch */
1346
1356
  {
1347
1357
    pthread_cond_broadcast(&COND_global_read_lock);
1348
1358
  }
1349
 
  session->global_read_lock= 0;
 
1359
  thd->global_read_lock= 0;
1350
1360
 
1351
1361
  return;
1352
1362
}
1355
1365
                   (is_not_commit ||                               \
1356
1366
                    global_read_lock_blocks_commit))
1357
1367
 
1358
 
bool wait_if_global_read_lock(Session *session, bool abort_on_refresh,
 
1368
bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
1359
1369
                              bool is_not_commit)
1360
1370
{
1361
1371
  const char *old_message= NULL;
1371
1381
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
1372
1382
  if ((need_exit_cond= must_wait))
1373
1383
  {
1374
 
    if (session->global_read_lock)              // This thread had the read locks
 
1384
    if (thd->global_read_lock)          // This thread had the read locks
1375
1385
    {
1376
1386
      if (is_not_commit)
1377
1387
        my_message(ER_CANT_UPDATE_WITH_READLOCK,
1384
1394
      */
1385
1395
      return(is_not_commit);
1386
1396
    }
1387
 
    old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
 
1397
    old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1388
1398
                                "Waiting for release of readlock");
1389
 
    while (must_wait && ! session->killed &&
1390
 
           (!abort_on_refresh || session->version == refresh_version))
 
1399
    while (must_wait && ! thd->killed &&
 
1400
           (!abort_on_refresh || thd->version == refresh_version))
1391
1401
    {
1392
1402
      (void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1393
1403
    }
1394
 
    if (session->killed)
 
1404
    if (thd->killed)
1395
1405
      result=1;
1396
1406
  }
1397
1407
  if (!abort_on_refresh && !result)
1401
1411
    and if old_message is set
1402
1412
  */
1403
1413
  if (unlikely(need_exit_cond))
1404
 
    session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
 
1414
    thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1405
1415
  else
1406
1416
    pthread_mutex_unlock(&LOCK_global_read_lock);
1407
1417
  return(result);
1408
1418
}
1409
1419
 
1410
1420
 
1411
 
void start_waiting_global_read_lock(Session *session)
 
1421
void start_waiting_global_read_lock(THD *thd)
1412
1422
{
1413
1423
  bool tmp;
1414
 
  if (unlikely(session->global_read_lock))
 
1424
  if (unlikely(thd->global_read_lock))
1415
1425
    return;
1416
1426
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
1417
1427
  tmp= (!--protect_against_global_read_lock &&
1423
1433
}
1424
1434
 
1425
1435
 
1426
 
bool make_global_read_lock_block_commit(Session *session)
 
1436
bool make_global_read_lock_block_commit(THD *thd)
1427
1437
{
1428
1438
  bool error;
1429
1439
  const char *old_message;
1431
1441
    If we didn't succeed lock_global_read_lock(), or if we already suceeded
1432
1442
    make_global_read_lock_block_commit(), do nothing.
1433
1443
  */
1434
 
  if (session->global_read_lock != GOT_GLOBAL_READ_LOCK)
 
1444
  if (thd->global_read_lock != GOT_GLOBAL_READ_LOCK)
1435
1445
    return(0);
1436
1446
  pthread_mutex_lock(&LOCK_global_read_lock);
1437
1447
  /* increment this BEFORE waiting on cond (otherwise race cond) */
1438
1448
  global_read_lock_blocks_commit++;
1439
 
  old_message= session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
 
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,
1440
1452
                               "Waiting for all running commits to finish");
1441
 
  while (protect_against_global_read_lock && !session->killed)
 
1453
  while (protect_against_global_read_lock && !thd->killed)
1442
1454
    pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1443
 
  if ((error= test(session->killed)))
 
1455
  protect_against_global_read_lock--;
 
1456
  if ((error= test(thd->killed)))
1444
1457
    global_read_lock_blocks_commit--; // undo what we did
1445
1458
  else
1446
 
    session->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1447
 
  session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
 
1459
    thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
 
1460
  thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1448
1461
  return(error);
1449
1462
}
1450
1463
 
1480
1493
 
1481
1494
  SYNOPSIS
1482
1495
    try_transactional_lock()
1483
 
      session                       Thread handle
 
1496
      thd                       Thread handle
1484
1497
      table_list                List of tables to lock
1485
1498
 
1486
1499
  DESCRIPTION
1493
1506
    -1                  Error: no recovery possible.
1494
1507
*/
1495
1508
 
1496
 
int try_transactional_lock(Session *session, TableList *table_list)
 
1509
int try_transactional_lock(THD *thd, TableList *table_list)
1497
1510
{
1498
1511
  uint32_t          dummy_counter;
1499
1512
  int           error;
1500
1513
  int           result= 0;
1501
1514
 
1502
1515
  /* Need to open the tables to be able to access engine methods. */
1503
 
  if (open_tables(session, &table_list, &dummy_counter, 0))
 
1516
  if (open_tables(thd, &table_list, &dummy_counter, 0))
1504
1517
  {
1505
1518
    /* purecov: begin tested */
1506
1519
    return(-1);
1508
1521
  }
1509
1522
 
1510
1523
  /* Required by InnoDB. */
1511
 
  session->in_lock_tables= true;
 
1524
  thd->in_lock_tables= true;
1512
1525
 
1513
 
  if ((error= set_handler_table_locks(session, table_list, true)))
 
1526
  if ((error= set_handler_table_locks(thd, table_list, true)))
1514
1527
  {
1515
1528
    /*
1516
1529
      Not all transactional locks could be taken. If the error was
1533
1546
 
1534
1547
 err:
1535
1548
  /* We need to explicitly commit if autocommit mode is active. */
1536
 
  (void) ha_autocommit_or_rollback(session, 0);
 
1549
  (void) ha_autocommit_or_rollback(thd, 0);
1537
1550
  /* Close the tables. The locks (if taken) persist in the storage engines. */
1538
 
  close_tables_for_reopen(session, &table_list);
1539
 
  session->in_lock_tables= false;
 
1551
  close_tables_for_reopen(thd, &table_list);
 
1552
  thd->in_lock_tables= false;
1540
1553
  return(result);
1541
1554
}
1542
1555
 
1546
1559
 
1547
1560
  SYNOPSIS
1548
1561
    check_transactional_lock()
1549
 
      session                       Thread handle
 
1562
      thd                       Thread handle
1550
1563
      table_list                List of tables to lock
1551
1564
 
1552
1565
  DESCRIPTION
1566
1579
    -1                  Error: Lock conversion is prohibited.
1567
1580
*/
1568
1581
 
1569
 
int check_transactional_lock(Session *session, TableList *table_list)
 
1582
int check_transactional_lock(THD *thd, TableList *table_list)
1570
1583
{
1571
1584
  TableList    *tlist;
1572
1585
  int           result= 0;
1595
1608
    }
1596
1609
 
1597
1610
    /* We must not convert the lock method within an active transaction. */
1598
 
    if (session->active_transaction())
 
1611
    if (thd->active_transaction())
1599
1612
    {
1600
1613
      my_error(ER_NO_AUTO_CONVERT_LOCK_TRANSACTION, MYF(0),
1601
1614
               tlist->alias ? tlist->alias : tlist->table_name);
1606
1619
    /* Warn about the conversion. */
1607
1620
    snprintf(warn_buff, sizeof(warn_buff), ER(ER_WARN_AUTO_CONVERT_LOCK),
1608
1621
             tlist->alias ? tlist->alias : tlist->table_name);
1609
 
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
1622
    push_warning(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1610
1623
                 ER_WARN_AUTO_CONVERT_LOCK, warn_buff);
1611
1624
  }
1612
1625
 
1619
1632
 
1620
1633
  SYNOPSIS
1621
1634
    set_handler_table_locks()
1622
 
      session                       Thread handle
 
1635
      thd                       Thread handle
1623
1636
      table_list                List of tables to lock
1624
1637
      transactional             If to lock transactional or non-transactional
1625
1638
 
1628
1641
    != 0                Error code from handler::lock_table().
1629
1642
*/
1630
1643
 
1631
 
int set_handler_table_locks(Session *session, TableList *table_list,
 
1644
int set_handler_table_locks(THD *thd, TableList *table_list,
1632
1645
                            bool transactional)
1633
1646
{
1634
1647
  TableList    *tlist;
1687
1700
    */
1688
1701
    if (!error || !transactional)
1689
1702
    {
1690
 
      error= tlist->table->file->lock_table(session, lock_type, lock_timeout);
 
1703
      error= tlist->table->file->lock_table(thd, lock_type, lock_timeout);
1691
1704
      if (error && transactional && (error != HA_ERR_WRONG_COMMAND))
1692
1705
        tlist->table->file->print_error(error, MYF(0));
1693
1706
    }