~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to drizzled/lock.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-03-18 12:12:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100318121231-k6g1xe6cshbwa0f8
Tags: upstream-2010.03.1347
ImportĀ upstreamĀ versionĀ 2010.03.1347

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