~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/lock.cc

  • Committer: Brian Aker
  • Date: 2008-07-28 18:01:38 UTC
  • Revision ID: brian@tangent.org-20080728180138-q2pxlq0qiapvqsdn
Remove YEAR field type

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2006 MySQL AB
2
 
 
3
 
   This program is free software; you can redistribute it and/or modify
4
 
   it under the terms of the GNU General Public License as published by
5
 
   the Free Software Foundation; version 2 of the License.
6
 
 
7
 
   This program is distributed in the hope that it will be useful,
8
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 
   GNU General Public License for more details.
11
 
 
12
 
   You should have received a copy of the GNU General Public License
13
 
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
 
 
16
 
 
17
 
/**
18
 
  @file
19
 
 
20
 
  Locking functions for mysql.
21
 
 
22
 
  Because of the new concurrent inserts, we must first get external locks
23
 
  before getting internal locks.  If we do it in the other order, the status
24
 
  information is not up to date when called from the lock handler.
25
 
 
26
 
  GENERAL DESCRIPTION OF LOCKING
27
 
 
28
 
  When not using LOCK TABLES:
29
 
 
30
 
  - For each SQL statement mysql_lock_tables() is called for all involved
31
 
    tables.
32
 
    - mysql_lock_tables() will call
33
 
      table_handler->external_lock(session,locktype) for each table.
34
 
      This is followed by a call to thr_multi_lock() for all tables.
35
 
 
36
 
  - When statement is done, we call mysql_unlock_tables().
37
 
    This will call thr_multi_unlock() followed by
38
 
    table_handler->external_lock(session, F_UNLCK) for each table.
39
 
 
40
 
  - Note that mysql_unlock_tables() may be called several times as
41
 
    MySQL in some cases can free some tables earlier than others.
42
 
 
43
 
  - The above is true both for normal and temporary tables.
44
 
 
45
 
  - Temporary non transactional tables are never passed to thr_multi_lock()
46
 
    and we never call external_lock(session, F_UNLOCK) on these.
47
 
 
48
 
  When using LOCK TABLES:
49
 
 
50
 
  - LOCK Table will call mysql_lock_tables() for all tables.
51
 
    mysql_lock_tables() will call
52
 
    table_handler->external_lock(session,locktype) for each table.
53
 
    This is followed by a call to thr_multi_lock() for all tables.
54
 
 
55
 
  - For each statement, we will call table_handler->start_stmt(Session)
56
 
    to inform the table handler that we are using the table.
57
 
 
58
 
    The tables used can only be tables used in LOCK TABLES or a
59
 
    temporary table.
60
 
 
61
 
  - When statement is done, we will call ha_commit_stmt(session);
62
 
 
63
 
  - When calling UNLOCK TABLES we call mysql_unlock_tables() for all
64
 
    tables used in LOCK TABLES
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,
68
 
  excluding one that caused failure. That means handler must cleanup itself
69
 
  in case external_lock() fails.
70
 
 
71
 
  @todo
72
 
  Change to use malloc() ONLY when using LOCK TABLES command or when
73
 
  we are forced to use mysql_lock_merge.
74
 
*/
75
 
#include "config.h"
76
 
#include <fcntl.h>
77
 
#include <drizzled/error.h>
78
 
#include <drizzled/my_hash.h>
79
 
#include <drizzled/thr_lock.h>
80
 
#include <drizzled/session.h>
81
 
#include <drizzled/sql_base.h>
82
 
#include <drizzled/lock.h>
83
 
#include "drizzled/pthread_globals.h"
84
 
#include "drizzled/internal/my_sys.h"
85
 
 
86
 
 
87
 
/**
88
 
  @defgroup Locking Locking
89
 
  @{
90
 
*/
91
 
 
92
 
extern HASH open_cache;
93
 
 
94
 
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table,
95
 
                                   uint32_t count,
96
 
                                   bool should_lock, 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);
99
 
static void print_lock_error(int error, const char *);
100
 
 
101
 
/*
102
 
  Lock tables.
103
 
 
104
 
  SYNOPSIS
105
 
    mysql_lock_tables()
106
 
    session                         The current thread.
107
 
    tables                      An array of pointers to the tables to lock.
108
 
    count                       The number of tables to lock.
109
 
    flags                       Options:
110
 
      DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK      Ignore a global read lock
111
 
      DRIZZLE_LOCK_IGNORE_FLUSH                 Ignore a flush tables.
112
 
      DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN        Instead of reopening altered
113
 
                                              or dropped tables by itself,
114
 
                                              mysql_lock_tables() should
115
 
                                              notify upper level and rely
116
 
                                              on caller doing this.
117
 
    need_reopen                 Out parameter, TRUE if some tables were altered
118
 
                                or deleted and should be reopened by caller.
119
 
 
120
 
  RETURN
121
 
    A lock structure pointer on success.
122
 
    NULL on error or if some tables should be reopen.
123
 
*/
124
 
 
125
 
/* Map the return value of thr_lock to an error from errmsg.txt */
126
 
static int thr_lock_errno_to_mysql[]=
127
 
{ 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };
128
 
 
129
 
 
130
 
/**
131
 
  Reset lock type in lock data and free.
132
 
 
133
 
  @param mysql_lock Lock structures to reset.
134
 
 
135
 
  @note After a locking error we want to quit the locking of the table(s).
136
 
        The test case in the bug report for Bug #18544 has the following
137
 
        cases: 1. Locking error in lock_external() due to InnoDB timeout.
138
 
        2. Locking error in get_lock_data() due to missing write permission.
139
 
        3. Locking error in wait_if_global_read_lock() due to lock conflict.
140
 
 
141
 
  @note In all these cases we have already set the lock type into the lock
142
 
        data of the open table(s). If the table(s) are in the open table
143
 
        cache, they could be reused with the non-zero lock type set. This
144
 
        could lead to ignoring a different lock type with the next lock.
145
 
 
146
 
  @note Clear the lock type of all lock data. This ensures that the next
147
 
        lock request will set its lock type properly.
148
 
*/
149
 
 
150
 
static void reset_lock_data_and_free(DRIZZLE_LOCK **mysql_lock)
151
 
{
152
 
  DRIZZLE_LOCK *sql_lock= *mysql_lock;
153
 
  THR_LOCK_DATA **ldata, **ldata_end;
154
 
 
155
 
  /* Clear the lock type of all lock data to avoid reusage. */
156
 
  for (ldata= sql_lock->locks, ldata_end= ldata + sql_lock->lock_count;
157
 
       ldata < ldata_end;
158
 
       ldata++)
159
 
  {
160
 
    /* Reset lock type. */
161
 
    (*ldata)->type= TL_UNLOCK;
162
 
  }
163
 
  free((unsigned char*) sql_lock);
164
 
  *mysql_lock= 0;
165
 
}
166
 
 
167
 
 
168
 
DRIZZLE_LOCK *mysql_lock_tables(Session *session, Table **tables, uint32_t count,
169
 
                                uint32_t flags, bool *need_reopen)
170
 
{
171
 
  DRIZZLE_LOCK *sql_lock;
172
 
  Table *write_lock_used;
173
 
  int rc;
174
 
 
175
 
  *need_reopen= false;
176
 
 
177
 
  for (;;)
178
 
  {
179
 
    if (! (sql_lock= get_lock_data(session, tables, count, true,
180
 
                                   &write_lock_used)))
181
 
      break;
182
 
 
183
 
    if (global_read_lock && write_lock_used &&
184
 
        ! (flags & DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK))
185
 
    {
186
 
      /*
187
 
        Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
188
 
        Wait until the lock is gone
189
 
      */
190
 
      if (wait_if_global_read_lock(session, 1, 1))
191
 
      {
192
 
        /* Clear the lock type of all lock data to avoid reusage. */
193
 
        reset_lock_data_and_free(&sql_lock);
194
 
        break;
195
 
      }
196
 
      if (session->version != refresh_version)
197
 
      {
198
 
        /* Clear the lock type of all lock data to avoid reusage. */
199
 
        reset_lock_data_and_free(&sql_lock);
200
 
        goto retry;
201
 
      }
202
 
    }
203
 
 
204
 
    session->set_proc_info("System lock");
205
 
    if (sql_lock->table_count && lock_external(session, sql_lock->table,
206
 
                                               sql_lock->table_count))
207
 
    {
208
 
      /* Clear the lock type of all lock data to avoid reusage. */
209
 
      reset_lock_data_and_free(&sql_lock);
210
 
      break;
211
 
    }
212
 
    session->set_proc_info("Table lock");
213
 
    /* Copy the lock data array. thr_multi_lock() reorders its contens. */
214
 
    memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
215
 
           sql_lock->lock_count * sizeof(*sql_lock->locks));
216
 
    /* Lock on the copied half of the lock data array. */
217
 
    rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
218
 
                                                     sql_lock->lock_count,
219
 
                                                     sql_lock->lock_count,
220
 
                                                     session->lock_id)];
221
 
    if (rc > 1)                                 /* a timeout or a deadlock */
222
 
    {
223
 
      if (sql_lock->table_count)
224
 
        unlock_external(session, sql_lock->table, sql_lock->table_count);
225
 
      reset_lock_data_and_free(&sql_lock);
226
 
      my_error(rc, MYF(0));
227
 
      break;
228
 
    }
229
 
    else if (rc == 1)                           /* aborted */
230
 
    {
231
 
      session->some_tables_deleted=1;           // Try again
232
 
      sql_lock->lock_count= 0;                  // Locks are already freed
233
 
      // Fall through: unlock, reset lock data, free and retry
234
 
    }
235
 
    else if (!session->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
236
 
    {
237
 
      /*
238
 
        Thread was killed or lock aborted. Let upper level close all
239
 
        used tables and retry or give error.
240
 
      */
241
 
      break;
242
 
    }
243
 
    else if (!session->open_tables)
244
 
    {
245
 
      // Only using temporary tables, no need to unlock
246
 
      session->some_tables_deleted= 0;
247
 
      break;
248
 
    }
249
 
    session->set_proc_info(0);
250
 
 
251
 
    /* going to retry, unlock all tables */
252
 
    if (sql_lock->lock_count)
253
 
        thr_multi_unlock(sql_lock->locks, sql_lock->lock_count);
254
 
 
255
 
    if (sql_lock->table_count)
256
 
      unlock_external(session, sql_lock->table, sql_lock->table_count);
257
 
 
258
 
    /*
259
 
      If thr_multi_lock fails it resets lock type for tables, which
260
 
      were locked before (and including) one that caused error. Lock
261
 
      type for other tables preserved.
262
 
    */
263
 
    reset_lock_data_and_free(&sql_lock);
264
 
retry:
265
 
    if (flags & DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN)
266
 
    {
267
 
      *need_reopen= true;
268
 
      break;
269
 
    }
270
 
    if (wait_for_tables(session))
271
 
      break;                                    // Couldn't open tables
272
 
  }
273
 
  session->set_proc_info(0);
274
 
  if (session->killed)
275
 
  {
276
 
    session->send_kill_message();
277
 
    if (sql_lock)
278
 
    {
279
 
      mysql_unlock_tables(session,sql_lock);
280
 
      sql_lock= NULL;
281
 
    }
282
 
  }
283
 
 
284
 
  session->set_time_after_lock();
285
 
  return (sql_lock);
286
 
}
287
 
 
288
 
 
289
 
static int lock_external(Session *session, Table **tables, uint32_t count)
290
 
{
291
 
  register uint32_t i;
292
 
  int lock_type,error;
293
 
  for (i=1 ; i <= count ; i++, tables++)
294
 
  {
295
 
    assert((*tables)->reginfo.lock_type >= TL_READ);
296
 
    lock_type=F_WRLCK;                          /* Lock exclusive */
297
 
    if ((*tables)->db_stat & HA_READ_ONLY ||
298
 
        ((*tables)->reginfo.lock_type >= TL_READ &&
299
 
         (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
300
 
      lock_type=F_RDLCK;
301
 
 
302
 
    if ((error=(*tables)->cursor->ha_external_lock(session,lock_type)))
303
 
    {
304
 
      print_lock_error(error, (*tables)->cursor->engine->getName().c_str());
305
 
      while (--i)
306
 
      {
307
 
        tables--;
308
 
        (*tables)->cursor->ha_external_lock(session, F_UNLCK);
309
 
        (*tables)->current_lock=F_UNLCK;
310
 
      }
311
 
      return error;
312
 
    }
313
 
    else
314
 
    {
315
 
      (*tables)->db_stat &= ~ HA_BLOCK_LOCK;
316
 
      (*tables)->current_lock= lock_type;
317
 
    }
318
 
  }
319
 
  return 0;
320
 
}
321
 
 
322
 
 
323
 
void mysql_unlock_tables(Session *session, DRIZZLE_LOCK *sql_lock)
324
 
{
325
 
  if (sql_lock->lock_count)
326
 
    thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
327
 
  if (sql_lock->table_count)
328
 
    unlock_external(session,sql_lock->table,sql_lock->table_count);
329
 
  free((unsigned char*) sql_lock);
330
 
  return;
331
 
}
332
 
 
333
 
/**
334
 
  Unlock some of the tables locked by mysql_lock_tables.
335
 
 
336
 
  This will work even if get_lock_data fails (next unlock will free all)
337
 
*/
338
 
 
339
 
void mysql_unlock_some_tables(Session *session, Table **table, uint32_t count)
340
 
{
341
 
  DRIZZLE_LOCK *sql_lock;
342
 
  Table *write_lock_used;
343
 
  if ((sql_lock= get_lock_data(session, table, count, false,
344
 
                               &write_lock_used)))
345
 
    mysql_unlock_tables(session, sql_lock);
346
 
}
347
 
 
348
 
 
349
 
/**
350
 
  unlock all tables locked for read.
351
 
*/
352
 
 
353
 
void mysql_unlock_read_tables(Session *session, DRIZZLE_LOCK *sql_lock)
354
 
{
355
 
  uint32_t i,found;
356
 
 
357
 
  /* Move all write locks first */
358
 
  THR_LOCK_DATA **lock=sql_lock->locks;
359
 
  for (i=found=0 ; i < sql_lock->lock_count ; i++)
360
 
  {
361
 
    if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_READ)
362
 
    {
363
 
      std::swap(*lock, sql_lock->locks[i]);
364
 
      lock++;
365
 
      found++;
366
 
    }
367
 
  }
368
 
  /* unlock the read locked tables */
369
 
  if (i != found)
370
 
  {
371
 
    thr_multi_unlock(lock,i-found);
372
 
    sql_lock->lock_count= found;
373
 
  }
374
 
 
375
 
  /* Then do the same for the external locks */
376
 
  /* Move all write locked tables first */
377
 
  Table **table=sql_lock->table;
378
 
  for (i=found=0 ; i < sql_lock->table_count ; i++)
379
 
  {
380
 
    assert(sql_lock->table[i]->lock_position == i);
381
 
    if ((uint32_t) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
382
 
    {
383
 
      std::swap(*table, sql_lock->table[i]);
384
 
      table++;
385
 
      found++;
386
 
    }
387
 
  }
388
 
  /* Unlock all read locked tables */
389
 
  if (i != found)
390
 
  {
391
 
    unlock_external(session,table,i-found);
392
 
    sql_lock->table_count=found;
393
 
  }
394
 
  /* Fix the lock positions in Table */
395
 
  table= sql_lock->table;
396
 
  found= 0;
397
 
  for (i= 0; i < sql_lock->table_count; i++)
398
 
  {
399
 
    Table *tbl= *table;
400
 
    tbl->lock_position= table - sql_lock->table;
401
 
    tbl->lock_data_start= found;
402
 
    found+= tbl->lock_count;
403
 
    table++;
404
 
  }
405
 
  return;
406
 
}
407
 
 
408
 
 
409
 
/**
410
 
  Try to find the table in the list of locked tables.
411
 
  In case of success, unlock the table and remove it from this list.
412
 
 
413
 
  @note This function has a legacy side effect: the table is
414
 
  unlocked even if it is not found in the locked list.
415
 
  It's not clear if this side effect is intentional or still
416
 
  desirable. It might lead to unmatched calls to
417
 
  unlock_external(). Moreover, a discrepancy can be left
418
 
  unnoticed by the storage engine, because in
419
 
  unlock_external() we call handler::external_lock(F_UNLCK) only
420
 
  if table->current_lock is not F_UNLCK.
421
 
 
422
 
  @param  session             thread context
423
 
  @param  locked          list of locked tables
424
 
  @param  table           the table to unlock
425
 
  @param  always_unlock   specify explicitly if the legacy side
426
 
                          effect is desired.
427
 
*/
428
 
 
429
 
void mysql_lock_remove(Session *session, Table *table)
430
 
{
431
 
  mysql_unlock_some_tables(session, &table, /* table count */ 1);
432
 
}
433
 
 
434
 
 
435
 
/** Abort all other threads waiting to get lock in table. */
436
 
 
437
 
void mysql_lock_abort(Session *session, Table *table)
438
 
{
439
 
  DRIZZLE_LOCK *locked;
440
 
  Table *write_lock_used;
441
 
 
442
 
  if ((locked= get_lock_data(session, &table, 1, false,
443
 
                             &write_lock_used)))
444
 
  {
445
 
    for (uint32_t x= 0; x < locked->lock_count; x++)
446
 
      thr_abort_locks(locked->locks[x]->lock);
447
 
    free((unsigned char*) locked);
448
 
  }
449
 
}
450
 
 
451
 
 
452
 
/**
453
 
  Abort one thread / table combination.
454
 
 
455
 
  @param session           Thread handler
456
 
  @param table     Table that should be removed from lock queue
457
 
 
458
 
  @retval
459
 
    0  Table was not locked by another thread
460
 
  @retval
461
 
    1  Table was locked by at least one other thread
462
 
*/
463
 
 
464
 
bool mysql_lock_abort_for_thread(Session *session, Table *table)
465
 
{
466
 
  DRIZZLE_LOCK *locked;
467
 
  Table *write_lock_used;
468
 
  bool result= false;
469
 
 
470
 
  if ((locked= get_lock_data(session, &table, 1, false,
471
 
                             &write_lock_used)))
472
 
  {
473
 
    for (uint32_t i=0; i < locked->lock_count; i++)
474
 
    {
475
 
      if (thr_abort_locks_for_thread(locked->locks[i]->lock,
476
 
                                     table->in_use->thread_id))
477
 
        result= true;
478
 
    }
479
 
    free((unsigned char*) locked);
480
 
  }
481
 
  return result;
482
 
}
483
 
 
484
 
 
485
 
/** Unlock a set of external. */
486
 
 
487
 
static int unlock_external(Session *session, Table **table,uint32_t count)
488
 
{
489
 
  int error,error_code;
490
 
 
491
 
  error_code=0;
492
 
  do
493
 
  {
494
 
    if ((*table)->current_lock != F_UNLCK)
495
 
    {
496
 
      (*table)->current_lock = F_UNLCK;
497
 
      if ((error=(*table)->cursor->ha_external_lock(session, F_UNLCK)))
498
 
      {
499
 
        error_code=error;
500
 
        print_lock_error(error_code, (*table)->cursor->engine->getName().c_str());
501
 
      }
502
 
    }
503
 
    table++;
504
 
  } while (--count);
505
 
  return error_code;
506
 
}
507
 
 
508
 
 
509
 
/**
510
 
  Get lock structures from table structs and initialize locks.
511
 
 
512
 
  @param session                    Thread handler
513
 
  @param table_ptr          Pointer to tables that should be locks
514
 
  @param should_lock                One of:
515
 
           - false      : If we should send TL_IGNORE to store lock
516
 
           - true       : Store lock info in Table
517
 
  @param write_lock_used   Store pointer to last table with WRITE_ALLOW_WRITE
518
 
*/
519
 
 
520
 
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table_ptr, uint32_t count,
521
 
                                 bool should_lock, Table **write_lock_used)
522
 
{
523
 
  uint32_t i,tables,lock_count;
524
 
  DRIZZLE_LOCK *sql_lock;
525
 
  THR_LOCK_DATA **locks, **locks_buf, **locks_start;
526
 
  Table **to, **table_buf;
527
 
 
528
 
  *write_lock_used=0;
529
 
  for (i= tables= lock_count= 0 ; i < count ; i++)
530
 
  {
531
 
    Table *t= table_ptr[i];
532
 
 
533
 
    if (! (t->getEngine()->check_flag(HTON_BIT_SKIP_STORE_LOCK)))
534
 
    {
535
 
      tables++;
536
 
      lock_count++;
537
 
    }
538
 
  }
539
 
 
540
 
  /*
541
 
    Allocating twice the number of pointers for lock data for use in
542
 
    thr_mulit_lock(). This function reorders the lock data, but cannot
543
 
    update the table values. So the second part of the array is copied
544
 
    from the first part immediately before calling thr_multi_lock().
545
 
  */
546
 
  if (!(sql_lock= (DRIZZLE_LOCK*)
547
 
        malloc(sizeof(*sql_lock) +
548
 
               sizeof(THR_LOCK_DATA*) * tables * 2 +
549
 
               sizeof(table_ptr) * lock_count)))
550
 
    return NULL;
551
 
  locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
552
 
  to= table_buf= sql_lock->table= (Table**) (locks + tables * 2);
553
 
  sql_lock->table_count= lock_count;
554
 
 
555
 
  for (i=0 ; i < count ; i++)
556
 
  {
557
 
    Table *table;
558
 
    enum thr_lock_type lock_type;
559
 
 
560
 
    if (table_ptr[i]->getEngine()->check_flag(HTON_BIT_SKIP_STORE_LOCK))
561
 
      continue;
562
 
 
563
 
    table= table_ptr[i];
564
 
    lock_type= table->reginfo.lock_type;
565
 
    assert (lock_type != TL_WRITE_DEFAULT);
566
 
    if (lock_type >= TL_WRITE_ALLOW_WRITE)
567
 
    {
568
 
      *write_lock_used=table;
569
 
      if (table->db_stat & HA_READ_ONLY)
570
 
      {
571
 
        my_error(ER_OPEN_AS_READONLY,MYF(0),table->alias);
572
 
        /* Clear the lock type of the lock data that are stored already. */
573
 
        sql_lock->lock_count= locks - sql_lock->locks;
574
 
        reset_lock_data_and_free(&sql_lock);
575
 
        return NULL;
576
 
      }
577
 
    }
578
 
    locks_start= locks;
579
 
    locks= table->cursor->store_lock(session, locks,
580
 
                                   should_lock == false ? TL_IGNORE : lock_type);
581
 
    if (should_lock)
582
 
    {
583
 
      table->lock_position=   (uint32_t) (to - table_buf);
584
 
      table->lock_data_start= (uint32_t) (locks_start - locks_buf);
585
 
      table->lock_count=      (uint32_t) (locks - locks_start);
586
 
      assert(table->lock_count == 1);
587
 
    }
588
 
    *to++= table;
589
 
  }
590
 
  /*
591
 
    We do not use 'tables', because there are cases where store_lock()
592
 
    returns less locks than lock_count() claimed. This can happen when
593
 
    a FLUSH TABLES tries to abort locks from a MERGE table of another
594
 
    thread. When that thread has just opened the table, but not yet
595
 
    attached its children, it cannot return the locks. lock_count()
596
 
    always returns the number of locks that an attached table has.
597
 
    This is done to avoid the reverse situation: If lock_count() would
598
 
    return 0 for a non-attached MERGE table, and that table becomes
599
 
    attached between the calls to lock_count() and store_lock(), then
600
 
    we would have allocated too little memory for the lock data. Now
601
 
    we may allocate too much, but better safe than memory overrun.
602
 
    And in the FLUSH case, the memory is released quickly anyway.
603
 
  */
604
 
  sql_lock->lock_count= locks - locks_buf;
605
 
 
606
 
  return sql_lock;
607
 
}
608
 
 
609
 
 
610
 
/**
611
 
  Put a not open table with an old refresh version in the table cache.
612
 
 
613
 
  @param session                        Thread handler
614
 
  @param table_list             Lock first table in this list
615
 
  @param check_in_use           Do we need to check if table already in use by us
616
 
 
617
 
  @note
618
 
    One must have a lock on LOCK_open!
619
 
 
620
 
  @warning
621
 
    If you are going to update the table, you should use
622
 
    lock_and_wait_for_table_name(removed) instead of this function as this works
623
 
    together with 'FLUSH TABLES WITH READ LOCK'
624
 
 
625
 
  @note
626
 
    This will force any other threads that uses the table to release it
627
 
    as soon as possible.
628
 
 
629
 
  @return
630
 
    < 0 error
631
 
  @return
632
 
    == 0 table locked
633
 
  @return
634
 
    > 0  table locked, but someone is using it
635
 
*/
636
 
 
637
 
int lock_table_name(Session *session, TableList *table_list, bool check_in_use)
638
 
{
639
 
  Table *table;
640
 
  char  key[MAX_DBKEY_LENGTH];
641
 
  char *db= table_list->db;
642
 
  uint32_t  key_length;
643
 
  bool  found_locked_table= false;
644
 
  HASH_SEARCH_STATE state;
645
 
 
646
 
  key_length= table_list->create_table_def_key(key);
647
 
 
648
 
  if (check_in_use)
649
 
  {
650
 
    /* Only insert the table if we haven't insert it already */
651
 
    for (table=(Table*) hash_first(&open_cache, (unsigned char*)key,
652
 
                                   key_length, &state);
653
 
         table ;
654
 
         table = (Table*) hash_next(&open_cache,(unsigned char*) key,
655
 
                                    key_length, &state))
656
 
    {
657
 
      if (table->reginfo.lock_type < TL_WRITE)
658
 
      {
659
 
        if (table->in_use == session)
660
 
          found_locked_table= true;
661
 
        continue;
662
 
      }
663
 
 
664
 
      if (table->in_use == session)
665
 
      {
666
 
        table->s->version= 0;                  // Ensure no one can use this
667
 
        table->locked_by_name= 1;
668
 
        return 0;
669
 
      }
670
 
    }
671
 
  }
672
 
 
673
 
  if (!(table= session->table_cache_insert_placeholder(key, key_length)))
674
 
    return -1;
675
 
 
676
 
  table_list->table=table;
677
 
 
678
 
  /* Return 1 if table is in use */
679
 
  return(test(remove_table_from_cache(session, db, table_list->table_name,
680
 
             check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG)));
681
 
}
682
 
 
683
 
 
684
 
void unlock_table_name(TableList *table_list)
685
 
{
686
 
  if (table_list->table)
687
 
  {
688
 
    hash_delete(&open_cache, (unsigned char*) table_list->table);
689
 
    broadcast_refresh();
690
 
  }
691
 
}
692
 
 
693
 
 
694
 
static bool locked_named_table(TableList *table_list)
695
 
{
696
 
  for (; table_list ; table_list=table_list->next_local)
697
 
  {
698
 
    Table *table= table_list->table;
699
 
    if (table)
700
 
    {
701
 
      Table *save_next= table->next;
702
 
      bool result;
703
 
      table->next= 0;
704
 
      result= table_is_used(table_list->table, 0);
705
 
      table->next= save_next;
706
 
      if (result)
707
 
        return 1;
708
 
    }
709
 
  }
710
 
  return 0;                                     // All tables are locked
711
 
}
712
 
 
713
 
 
714
 
bool wait_for_locked_table_names(Session *session, TableList *table_list)
715
 
{
716
 
  bool result= false;
717
 
 
718
 
  safe_mutex_assert_owner(&LOCK_open);
719
 
 
720
 
  while (locked_named_table(table_list))
721
 
  {
722
 
    if (session->killed)
723
 
    {
724
 
      result=1;
725
 
      break;
726
 
    }
727
 
    session->wait_for_condition(&LOCK_open, &COND_refresh);
728
 
    pthread_mutex_lock(&LOCK_open); /* Wait for a table to unlock and then lock it */
729
 
  }
730
 
  return result;
731
 
}
732
 
 
733
 
 
734
 
/**
735
 
  Lock all tables in list with a name lock.
736
 
 
737
 
  REQUIREMENTS
738
 
  - One must have a lock on LOCK_open when calling this
739
 
 
740
 
  @param table_list             Names of tables to lock
741
 
 
742
 
  @retval
743
 
    0   ok
744
 
  @retval
745
 
    1   Fatal error (end of memory ?)
746
 
*/
747
 
 
748
 
bool lock_table_names(Session *session, TableList *table_list)
749
 
{
750
 
  bool got_all_locks=1;
751
 
  TableList *lock_table;
752
 
 
753
 
  for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
754
 
  {
755
 
    int got_lock;
756
 
    if ((got_lock= lock_table_name(session,lock_table, true)) < 0)
757
 
      goto end;                                 // Fatal error
758
 
    if (got_lock)
759
 
      got_all_locks=0;                          // Someone is using table
760
 
  }
761
 
 
762
 
  /* If some table was in use, wait until we got the lock */
763
 
  if (!got_all_locks && wait_for_locked_table_names(session, table_list))
764
 
    goto end;
765
 
  return false;
766
 
 
767
 
end:
768
 
  unlock_table_names(table_list, lock_table);
769
 
 
770
 
  return true;
771
 
}
772
 
 
773
 
 
774
 
/**
775
 
  Unlock all tables in list with a name lock.
776
 
 
777
 
  @param session        Thread handle.
778
 
  @param table_list Names of tables to lock.
779
 
 
780
 
  @note
781
 
    This function needs to be protected by LOCK_open. If we're
782
 
    under LOCK TABLES, this function does not work as advertised. Namely,
783
 
    it does not exclude other threads from using this table and does not
784
 
    put an exclusive name lock on this table into the table cache.
785
 
 
786
 
  @see lock_table_names
787
 
  @see unlock_table_names
788
 
 
789
 
  @retval TRUE An error occured.
790
 
  @retval FALSE Name lock successfully acquired.
791
 
*/
792
 
 
793
 
bool lock_table_names_exclusively(Session *session, TableList *table_list)
794
 
{
795
 
  if (lock_table_names(session, table_list))
796
 
    return true;
797
 
 
798
 
  /*
799
 
    Upgrade the table name locks from semi-exclusive to exclusive locks.
800
 
  */
801
 
  for (TableList *table= table_list; table; table= table->next_global)
802
 
  {
803
 
    if (table->table)
804
 
      table->table->open_placeholder= 1;
805
 
  }
806
 
  return false;
807
 
}
808
 
 
809
 
 
810
 
/**
811
 
  Unlock all tables in list with a name lock.
812
 
 
813
 
  @param
814
 
    table_list          Names of tables to unlock
815
 
  @param
816
 
    last_table          Don't unlock any tables after this one.
817
 
                                (default 0, which will unlock all tables)
818
 
 
819
 
  @note
820
 
    One must have a lock on LOCK_open when calling this.
821
 
 
822
 
  @note
823
 
    This function will broadcast refresh signals to inform other threads
824
 
    that the name locks are removed.
825
 
 
826
 
  @retval
827
 
    0   ok
828
 
  @retval
829
 
    1   Fatal error (end of memory ?)
830
 
*/
831
 
 
832
 
void unlock_table_names(TableList *table_list, TableList *last_table)
833
 
{
834
 
  for (TableList *table= table_list;
835
 
       table != last_table;
836
 
       table= table->next_local)
837
 
    unlock_table_name(table);
838
 
  broadcast_refresh();
839
 
}
840
 
 
841
 
 
842
 
static void print_lock_error(int error, const char *table)
843
 
{
844
 
  int textno;
845
 
 
846
 
  switch (error) {
847
 
  case HA_ERR_LOCK_WAIT_TIMEOUT:
848
 
    textno=ER_LOCK_WAIT_TIMEOUT;
849
 
    break;
850
 
  case HA_ERR_READ_ONLY_TRANSACTION:
851
 
    textno=ER_READ_ONLY_TRANSACTION;
852
 
    break;
853
 
  case HA_ERR_LOCK_DEADLOCK:
854
 
    textno=ER_LOCK_DEADLOCK;
855
 
    break;
856
 
  case HA_ERR_WRONG_COMMAND:
857
 
    textno=ER_ILLEGAL_HA;
858
 
    break;
859
 
  default:
860
 
    textno=ER_CANT_LOCK;
861
 
    break;
862
 
  }
863
 
 
864
 
  if ( textno == ER_ILLEGAL_HA )
865
 
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), table);
866
 
  else
867
 
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error);
868
 
}
869
 
 
870
 
 
871
 
/****************************************************************************
872
 
  Handling of global read locks
873
 
 
874
 
  Taking the global read lock is TWO steps (2nd step is optional; without
875
 
  it, COMMIT of existing transactions will be allowed):
876
 
  lock_global_read_lock() THEN make_global_read_lock_block_commit().
877
 
 
878
 
  The global locks are handled through the global variables:
879
 
  global_read_lock
880
 
    count of threads which have the global read lock (i.e. have completed at
881
 
    least the first step above)
882
 
  global_read_lock_blocks_commit
883
 
    count of threads which have the global read lock and block
884
 
    commits (i.e. are in or have completed the second step above)
885
 
  waiting_for_read_lock
886
 
    count of threads which want to take a global read lock but cannot
887
 
  protect_against_global_read_lock
888
 
    count of threads which have set protection against global read lock.
889
 
 
890
 
  access to them is protected with a mutex LOCK_global_read_lock
891
 
 
892
 
  (XXX: one should never take LOCK_open if LOCK_global_read_lock is
893
 
  taken, otherwise a deadlock may occur. Other mutexes could be a
894
 
  problem too - grep the code for global_read_lock if you want to use
895
 
  any other mutex here) Also one must not hold LOCK_open when calling
896
 
  wait_if_global_read_lock(). When the thread with the global read lock
897
 
  tries to close its tables, it needs to take LOCK_open in
898
 
  close_thread_table().
899
 
 
900
 
  How blocking of threads by global read lock is achieved: that's
901
 
  advisory. Any piece of code which should be blocked by global read lock must
902
 
  be designed like this:
903
 
  - call to wait_if_global_read_lock(). When this returns 0, no global read
904
 
  lock is owned; if argument abort_on_refresh was 0, none can be obtained.
905
 
  - job
906
 
  - if abort_on_refresh was 0, call to start_waiting_global_read_lock() to
907
 
  allow other threads to get the global read lock. I.e. removal of the
908
 
  protection.
909
 
  (Note: it's a bit like an implementation of rwlock).
910
 
 
911
 
  [ I am sorry to mention some SQL syntaxes below I know I shouldn't but found
912
 
  no better descriptive way ]
913
 
 
914
 
  Why does FLUSH TABLES WITH READ LOCK need to block COMMIT: because it's used
915
 
  to read a non-moving SHOW MASTER STATUS, and a COMMIT writes to the binary
916
 
  log.
917
 
 
918
 
  Why getting the global read lock is two steps and not one. Because FLUSH
919
 
  TABLES WITH READ LOCK needs to insert one other step between the two:
920
 
  flushing tables. So the order is
921
 
  1) lock_global_read_lock() (prevents any new table write locks, i.e. stalls
922
 
  all new updates)
923
 
  2) close_cached_tables() (the FLUSH TABLES), which will wait for tables
924
 
  currently opened and being updated to close (so it's possible that there is
925
 
  a moment where all new updates of server are stalled *and* FLUSH TABLES WITH
926
 
  READ LOCK is, too).
927
 
  3) make_global_read_lock_block_commit().
928
 
  If we have merged 1) and 3) into 1), we would have had this deadlock:
929
 
  imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
930
 
  table t.
931
 
  session1: SELECT * FROM t FOR UPDATE;
932
 
  session2: UPDATE t SET a=1; # blocked by row-level locks of session1
933
 
  session3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
934
 
  table instance of session2
935
 
  session1: COMMIT; # blocked by session3.
936
 
  session1 blocks session2 which blocks session3 which blocks session1: deadlock.
937
 
 
938
 
  Note that we need to support that one thread does
939
 
  FLUSH TABLES WITH READ LOCK; and then COMMIT;
940
 
  (that's what innobackup does, for some good reason).
941
 
  So in this exceptional case the COMMIT should not be blocked by the FLUSH
942
 
  TABLES WITH READ LOCK.
943
 
 
944
 
****************************************************************************/
945
 
 
946
 
volatile uint32_t global_read_lock=0;
947
 
volatile uint32_t global_read_lock_blocks_commit=0;
948
 
static volatile uint32_t protect_against_global_read_lock=0;
949
 
static volatile uint32_t waiting_for_read_lock=0;
950
 
 
951
 
#define GOT_GLOBAL_READ_LOCK               1
952
 
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
953
 
 
954
 
bool lock_global_read_lock(Session *session)
955
 
{
956
 
  if (!session->global_read_lock)
957
 
  {
958
 
    const char *old_message;
959
 
    (void) pthread_mutex_lock(&LOCK_global_read_lock);
960
 
    old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
961
 
                                "Waiting to get readlock");
962
 
 
963
 
    waiting_for_read_lock++;
964
 
    while (protect_against_global_read_lock && !session->killed)
965
 
      pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
966
 
    waiting_for_read_lock--;
967
 
    if (session->killed)
968
 
    {
969
 
      session->exit_cond(old_message);
970
 
      return true;
971
 
    }
972
 
    session->global_read_lock= GOT_GLOBAL_READ_LOCK;
973
 
    global_read_lock++;
974
 
    session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
975
 
  }
976
 
  /*
977
 
    We DON'T set global_read_lock_blocks_commit now, it will be set after
978
 
    tables are flushed (as the present function serves for FLUSH TABLES WITH
979
 
    READ LOCK only). Doing things in this order is necessary to avoid
980
 
    deadlocks (we must allow COMMIT until all tables are closed; we should not
981
 
    forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
982
 
    UPDATE and one does FLUSH TABLES WITH READ LOCK).
983
 
  */
984
 
  return false;
985
 
}
986
 
 
987
 
 
988
 
void unlock_global_read_lock(Session *session)
989
 
{
990
 
  uint32_t tmp;
991
 
 
992
 
  pthread_mutex_lock(&LOCK_global_read_lock);
993
 
  tmp= --global_read_lock;
994
 
  if (session->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
995
 
    --global_read_lock_blocks_commit;
996
 
  pthread_mutex_unlock(&LOCK_global_read_lock);
997
 
  /* Send the signal outside the mutex to avoid a context switch */
998
 
  if (!tmp)
999
 
  {
1000
 
    pthread_cond_broadcast(&COND_global_read_lock);
1001
 
  }
1002
 
  session->global_read_lock= 0;
1003
 
}
1004
 
 
1005
 
#define must_wait (global_read_lock &&                             \
1006
 
                   (is_not_commit ||                               \
1007
 
                    global_read_lock_blocks_commit))
1008
 
 
1009
 
bool wait_if_global_read_lock(Session *session, bool abort_on_refresh,
1010
 
                              bool is_not_commit)
1011
 
{
1012
 
  const char *old_message= NULL;
1013
 
  bool result= 0, need_exit_cond;
1014
 
 
1015
 
  /*
1016
 
    Assert that we do not own LOCK_open. If we would own it, other
1017
 
    threads could not close their tables. This would make a pretty
1018
 
    deadlock.
1019
 
  */
1020
 
  safe_mutex_assert_not_owner(&LOCK_open);
1021
 
 
1022
 
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
1023
 
  if ((need_exit_cond= must_wait))
1024
 
  {
1025
 
    if (session->global_read_lock)              // This thread had the read locks
1026
 
    {
1027
 
      if (is_not_commit)
1028
 
        my_message(ER_CANT_UPDATE_WITH_READLOCK,
1029
 
                   ER(ER_CANT_UPDATE_WITH_READLOCK), MYF(0));
1030
 
      (void) pthread_mutex_unlock(&LOCK_global_read_lock);
1031
 
      /*
1032
 
        We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
1033
 
        This allowance is needed to not break existing versions of innobackup
1034
 
        which do a BEGIN; INSERT; FLUSH TABLES WITH READ LOCK; COMMIT.
1035
 
      */
1036
 
      return is_not_commit;
1037
 
    }
1038
 
    old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1039
 
                                "Waiting for release of readlock");
1040
 
    while (must_wait && ! session->killed &&
1041
 
           (!abort_on_refresh || session->version == refresh_version))
1042
 
    {
1043
 
      (void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1044
 
    }
1045
 
    if (session->killed)
1046
 
      result=1;
1047
 
  }
1048
 
  if (!abort_on_refresh && !result)
1049
 
    protect_against_global_read_lock++;
1050
 
  /*
1051
 
    The following is only true in case of a global read locks (which is rare)
1052
 
    and if old_message is set
1053
 
  */
1054
 
  if (unlikely(need_exit_cond))
1055
 
    session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1056
 
  else
1057
 
    pthread_mutex_unlock(&LOCK_global_read_lock);
1058
 
  return result;
1059
 
}
1060
 
 
1061
 
 
1062
 
void start_waiting_global_read_lock(Session *session)
1063
 
{
1064
 
  bool tmp;
1065
 
  if (unlikely(session->global_read_lock))
1066
 
    return;
1067
 
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
1068
 
  tmp= (!--protect_against_global_read_lock &&
1069
 
        (waiting_for_read_lock || global_read_lock_blocks_commit));
1070
 
  (void) pthread_mutex_unlock(&LOCK_global_read_lock);
1071
 
  if (tmp)
1072
 
    pthread_cond_broadcast(&COND_global_read_lock);
1073
 
  return;
1074
 
}
1075
 
 
1076
 
 
1077
 
bool make_global_read_lock_block_commit(Session *session)
1078
 
{
1079
 
  bool error;
1080
 
  const char *old_message;
1081
 
  /*
1082
 
    If we didn't succeed lock_global_read_lock(), or if we already suceeded
1083
 
    make_global_read_lock_block_commit(), do nothing.
1084
 
  */
1085
 
  if (session->global_read_lock != GOT_GLOBAL_READ_LOCK)
1086
 
    return false;
1087
 
  pthread_mutex_lock(&LOCK_global_read_lock);
1088
 
  /* increment this BEFORE waiting on cond (otherwise race cond) */
1089
 
  global_read_lock_blocks_commit++;
1090
 
  old_message= session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1091
 
                               "Waiting for all running commits to finish");
1092
 
  while (protect_against_global_read_lock && !session->killed)
1093
 
    pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1094
 
  if ((error= test(session->killed)))
1095
 
    global_read_lock_blocks_commit--; // undo what we did
1096
 
  else
1097
 
    session->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1098
 
  session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1099
 
  return error;
1100
 
}
1101
 
 
1102
 
 
1103
 
/**
1104
 
  Broadcast COND_refresh and COND_global_read_lock.
1105
 
 
1106
 
    Due to a bug in a threading library it could happen that a signal
1107
 
    did not reach its target. A condition for this was that the same
1108
 
    condition variable was used with different mutexes in
1109
 
    pthread_cond_wait(). Some time ago we changed LOCK_open to
1110
 
    LOCK_global_read_lock in global read lock handling. So COND_refresh
1111
 
    was used with LOCK_open and LOCK_global_read_lock.
1112
 
 
1113
 
    We did now also change from COND_refresh to COND_global_read_lock
1114
 
    in global read lock handling. But now it is necessary to signal
1115
 
    both conditions at the same time.
1116
 
 
1117
 
  @note
1118
 
    When signalling COND_global_read_lock within the global read lock
1119
 
    handling, it is not necessary to also signal COND_refresh.
1120
 
*/
1121
 
 
1122
 
void broadcast_refresh(void)
1123
 
{
1124
 
  pthread_cond_broadcast(&COND_refresh);
1125
 
  pthread_cond_broadcast(&COND_global_read_lock);
1126
 
}
1127
 
 
1128
 
 
1129
 
/**
1130
 
  @} (end of group Locking)
1131
 
*/