~drizzle-trunk/drizzle/development

1 by brian
clean slate
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
520.1.22 by Brian Aker
Second pass of thd cleanup
33
      table_handler->external_lock(session,locktype) for each table.
1 by brian
clean slate
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
520.1.22 by Brian Aker
Second pass of thd cleanup
38
    table_handler->external_lock(session, F_UNLCK) for each table.
1 by brian
clean slate
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()
520.1.22 by Brian Aker
Second pass of thd cleanup
46
    and we never call external_lock(session, F_UNLOCK) on these.
1 by brian
clean slate
47
48
  When using LOCK TABLES:
49
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
50
  - LOCK Table will call mysql_lock_tables() for all tables.
1 by brian
clean slate
51
    mysql_lock_tables() will call
520.1.22 by Brian Aker
Second pass of thd cleanup
52
    table_handler->external_lock(session,locktype) for each table.
1 by brian
clean slate
53
    This is followed by a call to thr_multi_lock() for all tables.
54
520.1.21 by Brian Aker
THD -> Session rename
55
  - For each statement, we will call table_handler->start_stmt(Session)
1 by brian
clean slate
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
520.1.22 by Brian Aker
Second pass of thd cleanup
61
  - When statement is done, we will call ha_commit_stmt(session);
1 by brian
clean slate
62
63
  - When calling UNLOCK TABLES we call mysql_unlock_tables() for all
64
    tables used in LOCK TABLES
65
520.1.22 by Brian Aker
Second pass of thd cleanup
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,
1 by brian
clean slate
68
  excluding one that caused failure. That means handler must cleanup itself
69
  in case external_lock() fails.
70
71
  @todo
641.3.8 by Monty Taylor
Removed my_malloc from drizzled.
72
  Change to use malloc() ONLY when using LOCK TABLES command or when
1 by brian
clean slate
73
  we are forced to use mysql_lock_merge.
74
*/
243.1.17 by Jay Pipes
FINAL PHASE removal of mysql_priv.h (Bye, bye my friend.)
75
#include <drizzled/server_includes.h>
549 by Monty Taylor
Took gettext.h out of header files.
76
#include <drizzled/error.h>
584.1.15 by Monty Taylor
The mega-patch from hell. Renamed sql_class to session (since that's what it is) and removed it and field and table from common_includes.
77
#include <mysys/hash.h>
78
#include <mysys/thr_lock.h>
79
#include <drizzled/session.h>
80
#include <drizzled/sql_base.h>
670.2.4 by Monty Taylor
Removed more stuff from the headers.
81
#include <drizzled/lock.h>
1 by brian
clean slate
82
83
/**
84
  @defgroup Locking Locking
85
  @{
86
*/
87
88
extern HASH open_cache;
89
90
/* flags for get_lock_data */
91
#define GET_LOCK_UNLOCK         1
92
#define GET_LOCK_STORE_LOCKS    2
93
584.1.15 by Monty Taylor
The mega-patch from hell. Renamed sql_class to session (since that's what it is) and removed it and field and table from common_includes.
94
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table,
95
                                   uint32_t count,
96
                                   uint32_t flags, Table **write_locked);
520.1.22 by Brian Aker
Second pass of thd cleanup
97
static int lock_external(Session *session, Table **table,uint32_t count);
98
static int unlock_external(Session *session, Table **table,uint32_t count);
1 by brian
clean slate
99
static void print_lock_error(int error, const char *);
100
101
/*
102
  Lock tables.
103
104
  SYNOPSIS
105
    mysql_lock_tables()
520.1.22 by Brian Aker
Second pass of thd cleanup
106
    session                         The current thread.
1 by brian
clean slate
107
    tables                      An array of pointers to the tables to lock.
108
    count                       The number of tables to lock.
109
    flags                       Options:
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
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
1 by brian
clean slate
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
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
150
static void reset_lock_data_and_free(DRIZZLE_LOCK **mysql_lock)
1 by brian
clean slate
151
{
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
152
  DRIZZLE_LOCK *sql_lock= *mysql_lock;
1 by brian
clean slate
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
  }
481 by Brian Aker
Remove all of uchar.
163
  free((unsigned char*) sql_lock);
1 by brian
clean slate
164
  *mysql_lock= 0;
165
}
166
167
520.1.22 by Brian Aker
Second pass of thd cleanup
168
DRIZZLE_LOCK *mysql_lock_tables(Session *session, Table **tables, uint32_t count,
482 by Brian Aker
Remove uint.
169
                              uint32_t flags, bool *need_reopen)
1 by brian
clean slate
170
{
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
171
  DRIZZLE_LOCK *sql_lock;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
172
  Table *write_lock_used;
1 by brian
clean slate
173
  int rc;
174
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
175
  *need_reopen= false;
1 by brian
clean slate
176
177
  for (;;)
178
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
179
    if (! (sql_lock= get_lock_data(session, tables, count, GET_LOCK_STORE_LOCKS,
1 by brian
clean slate
180
                                   &write_lock_used)))
181
      break;
182
183
    if (global_read_lock && write_lock_used &&
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
184
        ! (flags & DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK))
1 by brian
clean slate
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
      */
520.1.22 by Brian Aker
Second pass of thd cleanup
190
      if (wait_if_global_read_lock(session, 1, 1))
1 by brian
clean slate
191
      {
192
        /* Clear the lock type of all lock data to avoid reusage. */
193
        reset_lock_data_and_free(&sql_lock);
194
	break;
195
      }
520.1.22 by Brian Aker
Second pass of thd cleanup
196
      if (session->version != refresh_version)
1 by brian
clean slate
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
520.1.22 by Brian Aker
Second pass of thd cleanup
204
    session->set_proc_info("System lock");
205
    if (sql_lock->table_count && lock_external(session, sql_lock->table,
1 by brian
clean slate
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
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
212
    session->set_proc_info("Table lock");
1 by brian
clean slate
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,
520.1.22 by Brian Aker
Second pass of thd cleanup
220
                                                     session->lock_id)];
1 by brian
clean slate
221
    if (rc > 1)                                 /* a timeout or a deadlock */
222
    {
223
      if (sql_lock->table_count)
520.1.22 by Brian Aker
Second pass of thd cleanup
224
        unlock_external(session, sql_lock->table, sql_lock->table_count);
1 by brian
clean slate
225
      reset_lock_data_and_free(&sql_lock);
226
      my_error(rc, MYF(0));
227
      break;
228
    }
229
    else if (rc == 1)                           /* aborted */
230
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
231
      session->some_tables_deleted=1;		// Try again
1 by brian
clean slate
232
      sql_lock->lock_count= 0;                  // Locks are already freed
233
      // Fall through: unlock, reset lock data, free and retry
234
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
235
    else if (!session->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
1 by brian
clean slate
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
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
243
    else if (!session->open_tables)
1 by brian
clean slate
244
    {
245
      // Only using temporary tables, no need to unlock
520.1.22 by Brian Aker
Second pass of thd cleanup
246
      session->some_tables_deleted=0;
1 by brian
clean slate
247
      break;
248
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
249
    session->set_proc_info(0);
1 by brian
clean slate
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)
520.1.22 by Brian Aker
Second pass of thd cleanup
256
      unlock_external(session, sql_lock->table, sql_lock->table_count);
1 by brian
clean slate
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:
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
265
    if (flags & DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN)
1 by brian
clean slate
266
    {
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
267
      *need_reopen= true;
1 by brian
clean slate
268
      break;
269
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
270
    if (wait_for_tables(session))
1 by brian
clean slate
271
      break;					// Couldn't open tables
272
  }
520.1.22 by Brian Aker
Second pass of thd cleanup
273
  session->set_proc_info(0);
274
  if (session->killed)
1 by brian
clean slate
275
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
276
    session->send_kill_message();
1 by brian
clean slate
277
    if (sql_lock)
278
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
279
      mysql_unlock_tables(session,sql_lock);
1 by brian
clean slate
280
      sql_lock=0;
281
    }
282
  }
283
520.1.22 by Brian Aker
Second pass of thd cleanup
284
  session->set_time_after_lock();
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
285
  return (sql_lock);
1 by brian
clean slate
286
}
287
288
520.1.22 by Brian Aker
Second pass of thd cleanup
289
static int lock_external(Session *session, Table **tables, uint32_t count)
1 by brian
clean slate
290
{
482 by Brian Aker
Remove uint.
291
  register uint32_t i;
1 by brian
clean slate
292
  int lock_type,error;
293
  for (i=1 ; i <= count ; i++, tables++)
294
  {
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
295
    assert((*tables)->reginfo.lock_type >= TL_READ);
1 by brian
clean slate
296
    lock_type=F_WRLCK;				/* Lock exclusive */
784.1.6 by Stewart Smith
merge
297
    if ((*tables)->db_stat & HA_READ_ONLY ||
1 by brian
clean slate
298
	((*tables)->reginfo.lock_type >= TL_READ &&
299
	 (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
300
      lock_type=F_RDLCK;
301
520.1.22 by Brian Aker
Second pass of thd cleanup
302
    if ((error=(*tables)->file->ha_external_lock(session,lock_type)))
1 by brian
clean slate
303
    {
304
      print_lock_error(error, (*tables)->file->table_type());
305
      while (--i)
306
      {
307
        tables--;
520.1.22 by Brian Aker
Second pass of thd cleanup
308
	(*tables)->file->ha_external_lock(session, F_UNLCK);
1 by brian
clean slate
309
	(*tables)->current_lock=F_UNLCK;
310
      }
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
311
      return(error);
1 by brian
clean slate
312
    }
313
    else
314
    {
315
      (*tables)->db_stat &= ~ HA_BLOCK_LOCK;
316
      (*tables)->current_lock= lock_type;
317
    }
318
  }
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
319
  return(0);
1 by brian
clean slate
320
}
321
322
520.1.22 by Brian Aker
Second pass of thd cleanup
323
void mysql_unlock_tables(Session *session, DRIZZLE_LOCK *sql_lock)
1 by brian
clean slate
324
{
325
  if (sql_lock->lock_count)
326
    thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
327
  if (sql_lock->table_count)
520.1.22 by Brian Aker
Second pass of thd cleanup
328
    unlock_external(session,sql_lock->table,sql_lock->table_count);
481 by Brian Aker
Remove all of uchar.
329
  free((unsigned char*) sql_lock);
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
330
  return;
1 by brian
clean slate
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
520.1.22 by Brian Aker
Second pass of thd cleanup
339
void mysql_unlock_some_tables(Session *session, Table **table,uint32_t count)
1 by brian
clean slate
340
{
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
341
  DRIZZLE_LOCK *sql_lock;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
342
  Table *write_lock_used;
520.1.22 by Brian Aker
Second pass of thd cleanup
343
  if ((sql_lock= get_lock_data(session, table, count, GET_LOCK_UNLOCK,
1 by brian
clean slate
344
                               &write_lock_used)))
520.1.22 by Brian Aker
Second pass of thd cleanup
345
    mysql_unlock_tables(session, sql_lock);
1 by brian
clean slate
346
}
347
348
349
/**
350
  unlock all tables locked for read.
351
*/
352
520.1.22 by Brian Aker
Second pass of thd cleanup
353
void mysql_unlock_read_tables(Session *session, DRIZZLE_LOCK *sql_lock)
1 by brian
clean slate
354
{
482 by Brian Aker
Remove uint.
355
  uint32_t i,found;
1 by brian
clean slate
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
    {
322.2.2 by Mats Kindahl
Hiding THD::proc_info field and providing a setter and getter.
363
      std::swap(*lock, sql_lock->locks[i]);
1 by brian
clean slate
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 */
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
377
  Table **table=sql_lock->table;
1 by brian
clean slate
378
  for (i=found=0 ; i < sql_lock->table_count ; i++)
379
  {
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
380
    assert(sql_lock->table[i]->lock_position == i);
1 by brian
clean slate
381
    if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
382
    {
322.2.2 by Mats Kindahl
Hiding THD::proc_info field and providing a setter and getter.
383
      std::swap(*table, sql_lock->table[i]);
1 by brian
clean slate
384
      table++;
385
      found++;
386
    }
387
  }
388
  /* Unlock all read locked tables */
389
  if (i != found)
390
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
391
    unlock_external(session,table,i-found);
1 by brian
clean slate
392
    sql_lock->table_count=found;
393
  }
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
394
  /* Fix the lock positions in Table */
1 by brian
clean slate
395
  table= sql_lock->table;
396
  found= 0;
397
  for (i= 0; i < sql_lock->table_count; i++)
398
  {
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
399
    Table *tbl= *table;
1 by brian
clean slate
400
    tbl->lock_position= table - sql_lock->table;
401
    tbl->lock_data_start= found;
402
    found+= tbl->lock_count;
403
    table++;
404
  }
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
405
  return;
1 by brian
clean slate
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
520.1.22 by Brian Aker
Second pass of thd cleanup
422
  @param  session             thread context
1 by brian
clean slate
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
520.1.22 by Brian Aker
Second pass of thd cleanup
429
void mysql_lock_remove(Session *session, DRIZZLE_LOCK *locked,Table *table,
1 by brian
clean slate
430
                       bool always_unlock)
431
{
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
432
  if (always_unlock == true)
520.1.22 by Brian Aker
Second pass of thd cleanup
433
    mysql_unlock_some_tables(session, &table, /* table count */ 1);
1 by brian
clean slate
434
  if (locked)
435
  {
482 by Brian Aker
Remove uint.
436
    register uint32_t i;
1 by brian
clean slate
437
    for (i=0; i < locked->table_count; i++)
438
    {
439
      if (locked->table[i] == table)
440
      {
482 by Brian Aker
Remove uint.
441
        uint32_t  j, removed_locks, old_tables;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
442
        Table *tbl;
482 by Brian Aker
Remove uint.
443
        uint32_t lock_data_end;
1 by brian
clean slate
444
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
445
        assert(table->lock_position == i);
1 by brian
clean slate
446
447
        /* Unlock if not yet unlocked */
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
448
        if (always_unlock == false)
520.1.22 by Brian Aker
Second pass of thd cleanup
449
          mysql_unlock_some_tables(session, &table, /* table count */ 1);
1 by brian
clean slate
450
451
        /* Decrement table_count in advance, making below expressions easier */
452
        old_tables= --locked->table_count;
453
454
        /* The table has 'removed_locks' lock data elements in locked->locks */
455
        removed_locks= table->lock_count;
456
457
        /* Move down all table pointers above 'i'. */
629.3.2 by Kristian Nielsen
Fix a couple of memcpy() that should be memmove() (caused by wrong
458
        memmove((locked->table+i), (locked->table+i+1),
459
                (old_tables - i) * sizeof(Table*));
1 by brian
clean slate
460
461
        lock_data_end= table->lock_data_start + table->lock_count;
462
        /* Move down all lock data pointers above 'table->lock_data_end-1' */
629.3.2 by Kristian Nielsen
Fix a couple of memcpy() that should be memmove() (caused by wrong
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*));
1 by brian
clean slate
467
468
        /*
469
          Fix moved table elements.
470
          lock_position is the index in the 'locked->table' array,
471
          it must be fixed by one.
472
          table->lock_data_start is pointer to the lock data for this table
473
          in the 'locked->locks' array, they must be fixed by 'removed_locks',
474
          the lock data count of the removed table.
475
        */
476
        for (j= i ; j < old_tables; j++)
477
        {
478
          tbl= locked->table[j];
479
          tbl->lock_position--;
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
480
          assert(tbl->lock_position == j);
1 by brian
clean slate
481
          tbl->lock_data_start-= removed_locks;
482
        }
483
484
        /* Finally adjust lock_count. */
485
        locked->lock_count-= removed_locks;
486
	break;
487
      }
488
    }
489
  }
490
}
491
492
/* Downgrade all locks on a table to new WRITE level from WRITE_ONLY */
493
520.1.22 by Brian Aker
Second pass of thd cleanup
494
void mysql_lock_downgrade_write(Session *session, Table *table,
1 by brian
clean slate
495
                                thr_lock_type new_lock_type)
496
{
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
497
  DRIZZLE_LOCK *locked;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
498
  Table *write_lock_used;
520.1.22 by Brian Aker
Second pass of thd cleanup
499
  if ((locked = get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
1 by brian
clean slate
500
                              &write_lock_used)))
501
  {
482 by Brian Aker
Remove uint.
502
    for (uint32_t i=0; i < locked->lock_count; i++)
1 by brian
clean slate
503
      thr_downgrade_write_lock(locked->locks[i], new_lock_type);
481 by Brian Aker
Remove all of uchar.
504
    free((unsigned char*) locked);
1 by brian
clean slate
505
  }
506
}
507
508
509
/** Abort all other threads waiting to get lock in table. */
510
520.1.22 by Brian Aker
Second pass of thd cleanup
511
void mysql_lock_abort(Session *session, Table *table, bool upgrade_lock)
1 by brian
clean slate
512
{
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
513
  DRIZZLE_LOCK *locked;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
514
  Table *write_lock_used;
1 by brian
clean slate
515
520.1.22 by Brian Aker
Second pass of thd cleanup
516
  if ((locked= get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
1 by brian
clean slate
517
                             &write_lock_used)))
518
  {
482 by Brian Aker
Remove uint.
519
    for (uint32_t i=0; i < locked->lock_count; i++)
1 by brian
clean slate
520
      thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
481 by Brian Aker
Remove all of uchar.
521
    free((unsigned char*) locked);
1 by brian
clean slate
522
  }
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
523
  return;
1 by brian
clean slate
524
}
525
526
527
/**
528
  Abort one thread / table combination.
529
520.1.22 by Brian Aker
Second pass of thd cleanup
530
  @param session	   Thread handler
1 by brian
clean slate
531
  @param table	   Table that should be removed from lock queue
532
533
  @retval
534
    0  Table was not locked by another thread
535
  @retval
536
    1  Table was locked by at least one other thread
537
*/
538
520.1.22 by Brian Aker
Second pass of thd cleanup
539
bool mysql_lock_abort_for_thread(Session *session, Table *table)
1 by brian
clean slate
540
{
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
541
  DRIZZLE_LOCK *locked;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
542
  Table *write_lock_used;
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
543
  bool result= false;
1 by brian
clean slate
544
520.1.22 by Brian Aker
Second pass of thd cleanup
545
  if ((locked= get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
1 by brian
clean slate
546
                             &write_lock_used)))
547
  {
482 by Brian Aker
Remove uint.
548
    for (uint32_t i=0; i < locked->lock_count; i++)
1 by brian
clean slate
549
    {
550
      if (thr_abort_locks_for_thread(locked->locks[i]->lock,
551
                                     table->in_use->thread_id))
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
552
        result= true;
1 by brian
clean slate
553
    }
481 by Brian Aker
Remove all of uchar.
554
    free((unsigned char*) locked);
1 by brian
clean slate
555
  }
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
556
  return(result);
1 by brian
clean slate
557
}
558
559
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
560
DRIZZLE_LOCK *mysql_lock_merge(DRIZZLE_LOCK *a,DRIZZLE_LOCK *b)
1 by brian
clean slate
561
{
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
562
  DRIZZLE_LOCK *sql_lock;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
563
  Table **table, **end_table;
1 by brian
clean slate
564
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
565
  if (!(sql_lock= (DRIZZLE_LOCK*)
641.3.8 by Monty Taylor
Removed my_malloc from drizzled.
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))))
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
569
    return(0);				// Fatal error
1 by brian
clean slate
570
  sql_lock->lock_count=a->lock_count+b->lock_count;
571
  sql_lock->table_count=a->table_count+b->table_count;
572
  sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
573
  sql_lock->table=(Table**) (sql_lock->locks+sql_lock->lock_count);
1 by brian
clean slate
574
  memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
575
  memcpy(sql_lock->locks+a->lock_count,b->locks,
576
	 b->lock_count*sizeof(*b->locks));
577
  memcpy(sql_lock->table,a->table,a->table_count*sizeof(*a->table));
578
  memcpy(sql_lock->table+a->table_count,b->table,
212.6.6 by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove().
579
         b->table_count*sizeof(*b->table));
1 by brian
clean slate
580
581
  /*
582
    Now adjust lock_position and lock_data_start for all objects that was
583
    moved in 'b' (as there is now all objects in 'a' before these).
584
  */
585
  for (table= sql_lock->table + a->table_count,
586
         end_table= table + b->table_count;
587
       table < end_table;
588
       table++)
589
  {
590
    (*table)->lock_position+=   a->table_count;
591
    (*table)->lock_data_start+= a->lock_count;
592
  }
593
594
  /* Delete old, not needed locks */
481 by Brian Aker
Remove all of uchar.
595
  free((unsigned char*) a);
596
  free((unsigned char*) b);
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
597
  return(sql_lock);
1 by brian
clean slate
598
}
599
600
601
/**
602
  Find duplicate lock in tables.
603
604
  Temporary tables are ignored here like they are ignored in
605
  get_lock_data(). If we allow two opens on temporary tables later,
606
  both functions should be checked.
607
520.1.22 by Brian Aker
Second pass of thd cleanup
608
  @param session                 The current thread.
1 by brian
clean slate
609
  @param needle              The table to check for duplicate lock.
610
  @param haystack            The list of tables to search for the dup lock.
611
612
  @note
613
    This is mainly meant for MERGE tables in INSERT ... SELECT
614
    situations. The 'real', underlying tables can be found only after
615
    the MERGE tables are opened. This function assumes that the tables are
616
    already locked.
617
618
  @retval
619
    NULL    No duplicate lock found.
620
  @retval
621
    !NULL   First table from 'haystack' that matches a lock on 'needle'.
622
*/
623
520.1.22 by Brian Aker
Second pass of thd cleanup
624
TableList *mysql_lock_have_duplicate(Session *session, TableList *needle,
327.2.4 by Brian Aker
Refactoring table.h
625
                                      TableList *haystack)
1 by brian
clean slate
626
{
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
627
  DRIZZLE_LOCK            *mylock;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
628
  Table                 **lock_tables;
629
  Table                 *table;
630
  Table                 *table2;
1 by brian
clean slate
631
  THR_LOCK_DATA         **lock_locks;
632
  THR_LOCK_DATA         **table_lock_data;
633
  THR_LOCK_DATA         **end_data;
634
  THR_LOCK_DATA         **lock_data2;
635
  THR_LOCK_DATA         **end_data2;
636
637
  /*
638
    Table may not be defined for derived or view tables.
639
    Table may not be part of a lock for delayed operations.
640
  */
641
  if (! (table= needle->table) || ! table->lock_count)
642
    goto end;
643
644
  /* A temporary table does not have locks. */
645
  if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
646
    goto end;
647
648
  /* Get command lock or LOCK TABLES lock. Maybe empty for INSERT DELAYED. */
520.1.22 by Brian Aker
Second pass of thd cleanup
649
  if (! (mylock= session->lock ? session->lock : session->locked_tables))
1 by brian
clean slate
650
    goto end;
651
652
  /* If we have less than two tables, we cannot have duplicates. */
653
  if (mylock->table_count < 2)
654
    goto end;
655
656
  lock_locks=  mylock->locks;
657
  lock_tables= mylock->table;
658
659
  /* Prepare table related variables that don't change in loop. */
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
660
  assert((table->lock_position < mylock->table_count) &&
1 by brian
clean slate
661
              (table == lock_tables[table->lock_position]));
662
  table_lock_data= lock_locks + table->lock_data_start;
663
  end_data= table_lock_data + table->lock_count;
664
665
  for (; haystack; haystack= haystack->next_global)
666
  {
667
    if (haystack->placeholder())
668
      continue;
669
    table2= haystack->table;
670
    if (table2->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
671
      continue;
672
673
    /* All tables in list must be in lock. */
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
674
    assert((table2->lock_position < mylock->table_count) &&
1 by brian
clean slate
675
                (table2 == lock_tables[table2->lock_position]));
676
677
    for (lock_data2=  lock_locks + table2->lock_data_start,
678
           end_data2= lock_data2 + table2->lock_count;
679
         lock_data2 < end_data2;
680
         lock_data2++)
681
    {
682
      THR_LOCK_DATA **lock_data;
683
      THR_LOCK *lock2= (*lock_data2)->lock;
684
685
      for (lock_data= table_lock_data;
686
           lock_data < end_data;
687
           lock_data++)
688
      {
689
        if ((*lock_data)->lock == lock2)
690
        {
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
691
          return(haystack);
1 by brian
clean slate
692
        }
693
      }
694
    }
695
  }
696
697
 end:
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
698
  return(NULL);
1 by brian
clean slate
699
}
700
701
702
/** Unlock a set of external. */
703
520.1.22 by Brian Aker
Second pass of thd cleanup
704
static int unlock_external(Session *session, Table **table,uint32_t count)
1 by brian
clean slate
705
{
706
  int error,error_code;
707
708
  error_code=0;
709
  do
710
  {
711
    if ((*table)->current_lock != F_UNLCK)
712
    {
713
      (*table)->current_lock = F_UNLCK;
520.1.22 by Brian Aker
Second pass of thd cleanup
714
      if ((error=(*table)->file->ha_external_lock(session, F_UNLCK)))
1 by brian
clean slate
715
      {
716
	error_code=error;
717
	print_lock_error(error_code, (*table)->file->table_type());
718
      }
719
    }
720
    table++;
721
  } while (--count);
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
722
  return(error_code);
1 by brian
clean slate
723
}
724
725
726
/**
727
  Get lock structures from table structs and initialize locks.
728
520.1.22 by Brian Aker
Second pass of thd cleanup
729
  @param session		    Thread handler
1 by brian
clean slate
730
  @param table_ptr	    Pointer to tables that should be locks
731
  @param flags		    One of:
732
           - GET_LOCK_UNLOCK      : If we should send TL_IGNORE to store lock
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
733
           - GET_LOCK_STORE_LOCKS : Store lock info in Table
1 by brian
clean slate
734
  @param write_lock_used   Store pointer to last table with WRITE_ALLOW_WRITE
735
*/
736
520.1.22 by Brian Aker
Second pass of thd cleanup
737
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table_ptr, uint32_t count,
482 by Brian Aker
Remove uint.
738
				 uint32_t flags, Table **write_lock_used)
1 by brian
clean slate
739
{
482 by Brian Aker
Remove uint.
740
  uint32_t i,tables,lock_count;
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
741
  DRIZZLE_LOCK *sql_lock;
1 by brian
clean slate
742
  THR_LOCK_DATA **locks, **locks_buf, **locks_start;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
743
  Table **to, **table_buf;
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
744
745
  assert((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS));
746
1 by brian
clean slate
747
  *write_lock_used=0;
748
  for (i=tables=lock_count=0 ; i < count ; i++)
749
  {
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
750
    Table *t= table_ptr[i];
1 by brian
clean slate
751
752
    if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE)
753
    {
754
      tables+= t->file->lock_count();
755
      lock_count++;
756
    }
757
  }
758
759
  /*
760
    Allocating twice the number of pointers for lock data for use in
761
    thr_mulit_lock(). This function reorders the lock data, but cannot
762
    update the table values. So the second part of the array is copied
763
    from the first part immediately before calling thr_multi_lock().
764
  */
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
765
  if (!(sql_lock= (DRIZZLE_LOCK*)
641.3.8 by Monty Taylor
Removed my_malloc from drizzled.
766
	malloc(sizeof(*sql_lock) +
767
               sizeof(THR_LOCK_DATA*) * tables * 2 +
768
               sizeof(table_ptr) * lock_count)))
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
769
    return(0);
1 by brian
clean slate
770
  locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
771
  to= table_buf= sql_lock->table= (Table**) (locks + tables * 2);
1 by brian
clean slate
772
  sql_lock->table_count=lock_count;
773
774
  for (i=0 ; i < count ; i++)
775
  {
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
776
    Table *table;
1 by brian
clean slate
777
    enum thr_lock_type lock_type;
778
779
    if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
780
      continue;
781
    lock_type= table->reginfo.lock_type;
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
782
    assert (lock_type != TL_WRITE_DEFAULT);
1 by brian
clean slate
783
    if (lock_type >= TL_WRITE_ALLOW_WRITE)
784
    {
785
      *write_lock_used=table;
784.1.6 by Stewart Smith
merge
786
      if (table->db_stat & HA_READ_ONLY)
1 by brian
clean slate
787
      {
788
	my_error(ER_OPEN_AS_READONLY,MYF(0),table->alias);
789
        /* Clear the lock type of the lock data that are stored already. */
790
        sql_lock->lock_count= locks - sql_lock->locks;
791
        reset_lock_data_and_free(&sql_lock);
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
792
	return(0);
1 by brian
clean slate
793
      }
794
    }
795
    locks_start= locks;
520.1.22 by Brian Aker
Second pass of thd cleanup
796
    locks= table->file->store_lock(session, locks,
1 by brian
clean slate
797
                                   (flags & GET_LOCK_UNLOCK) ? TL_IGNORE :
798
                                   lock_type);
799
    if (flags & GET_LOCK_STORE_LOCKS)
800
    {
801
      table->lock_position=   (uint) (to - table_buf);
802
      table->lock_data_start= (uint) (locks_start - locks_buf);
803
      table->lock_count=      (uint) (locks - locks_start);
804
    }
805
    *to++= table;
806
  }
807
  /*
808
    We do not use 'tables', because there are cases where store_lock()
809
    returns less locks than lock_count() claimed. This can happen when
810
    a FLUSH TABLES tries to abort locks from a MERGE table of another
811
    thread. When that thread has just opened the table, but not yet
812
    attached its children, it cannot return the locks. lock_count()
813
    always returns the number of locks that an attached table has.
814
    This is done to avoid the reverse situation: If lock_count() would
815
    return 0 for a non-attached MERGE table, and that table becomes
816
    attached between the calls to lock_count() and store_lock(), then
817
    we would have allocated too little memory for the lock data. Now
818
    we may allocate too much, but better safe than memory overrun.
819
    And in the FLUSH case, the memory is released quickly anyway.
820
  */
821
  sql_lock->lock_count= locks - locks_buf;
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
822
  return(sql_lock);
1 by brian
clean slate
823
}
824
825
826
/*****************************************************************************
827
  Lock table based on the name.
828
  This is used when we need total access to a closed, not open table
829
*****************************************************************************/
830
831
/**
832
  Lock and wait for the named lock.
833
520.1.22 by Brian Aker
Second pass of thd cleanup
834
  @param session			Thread handler
1 by brian
clean slate
835
  @param table_list		Lock first table in this list
836
837
838
  @note
839
    Works together with global read lock.
840
841
  @retval
842
    0	ok
843
  @retval
844
    1	error
845
*/
846
520.1.22 by Brian Aker
Second pass of thd cleanup
847
int lock_and_wait_for_table_name(Session *session, TableList *table_list)
1 by brian
clean slate
848
{
849
  int lock_retcode;
850
  int error= -1;
851
520.1.22 by Brian Aker
Second pass of thd cleanup
852
  if (wait_if_global_read_lock(session, 0, 1))
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
853
    return(1);
398.1.10 by Monty Taylor
Actually removed VOID() this time.
854
  pthread_mutex_lock(&LOCK_open);
520.1.22 by Brian Aker
Second pass of thd cleanup
855
  if ((lock_retcode = lock_table_name(session, table_list, true)) < 0)
1 by brian
clean slate
856
    goto end;
520.1.22 by Brian Aker
Second pass of thd cleanup
857
  if (lock_retcode && wait_for_locked_table_names(session, table_list))
1 by brian
clean slate
858
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
859
    unlock_table_name(session, table_list);
1 by brian
clean slate
860
    goto end;
861
  }
862
  error=0;
863
864
end:
865
  pthread_mutex_unlock(&LOCK_open);
520.1.22 by Brian Aker
Second pass of thd cleanup
866
  start_waiting_global_read_lock(session);
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
867
  return(error);
1 by brian
clean slate
868
}
869
870
871
/**
872
  Put a not open table with an old refresh version in the table cache.
873
520.1.22 by Brian Aker
Second pass of thd cleanup
874
  @param session			Thread handler
1 by brian
clean slate
875
  @param table_list		Lock first table in this list
876
  @param check_in_use           Do we need to check if table already in use by us
877
878
  @note
879
    One must have a lock on LOCK_open!
880
881
  @warning
882
    If you are going to update the table, you should use
883
    lock_and_wait_for_table_name instead of this function as this works
884
    together with 'FLUSH TABLES WITH READ LOCK'
885
886
  @note
887
    This will force any other threads that uses the table to release it
888
    as soon as possible.
889
890
  @return
891
    < 0 error
892
  @return
893
    == 0 table locked
894
  @return
895
    > 0  table locked, but someone is using it
896
*/
897
520.1.22 by Brian Aker
Second pass of thd cleanup
898
int lock_table_name(Session *session, TableList *table_list, bool check_in_use)
1 by brian
clean slate
899
{
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
900
  Table *table;
1 by brian
clean slate
901
  char  key[MAX_DBKEY_LENGTH];
902
  char *db= table_list->db;
482 by Brian Aker
Remove uint.
903
  uint32_t  key_length;
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
904
  bool  found_locked_table= false;
1 by brian
clean slate
905
  HASH_SEARCH_STATE state;
906
520.1.22 by Brian Aker
Second pass of thd cleanup
907
  key_length= create_table_def_key(session, key, table_list, 0);
1 by brian
clean slate
908
909
  if (check_in_use)
910
  {
911
    /* Only insert the table if we haven't insert it already */
481 by Brian Aker
Remove all of uchar.
912
    for (table=(Table*) hash_first(&open_cache, (unsigned char*)key,
1 by brian
clean slate
913
                                   key_length, &state);
914
         table ;
481 by Brian Aker
Remove all of uchar.
915
         table = (Table*) hash_next(&open_cache,(unsigned char*) key,
1 by brian
clean slate
916
                                    key_length, &state))
917
    {
918
      if (table->reginfo.lock_type < TL_WRITE)
919
      {
520.1.22 by Brian Aker
Second pass of thd cleanup
920
        if (table->in_use == session)
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
921
          found_locked_table= true;
1 by brian
clean slate
922
        continue;
923
      }
924
520.1.22 by Brian Aker
Second pass of thd cleanup
925
      if (table->in_use == session)
1 by brian
clean slate
926
      {
927
        table->s->version= 0;                  // Ensure no one can use this
928
        table->locked_by_name= 1;
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
929
        return(0);
1 by brian
clean slate
930
      }
931
    }
932
  }
933
520.1.22 by Brian Aker
Second pass of thd cleanup
934
  if (session->locked_tables && session->locked_tables->table_count &&
935
      ! find_temporary_table(session, table_list->db, table_list->table_name))
1 by brian
clean slate
936
  {
937
    if (found_locked_table)
938
      my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_list->alias);
939
    else
940
      my_error(ER_TABLE_NOT_LOCKED, MYF(0), table_list->alias);
941
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
942
    return(-1);
1 by brian
clean slate
943
  }
944
520.1.22 by Brian Aker
Second pass of thd cleanup
945
  if (!(table= table_cache_insert_placeholder(session, key, key_length)))
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
946
    return(-1);
1 by brian
clean slate
947
948
  table_list->table=table;
949
950
  /* Return 1 if table is in use */
520.1.22 by Brian Aker
Second pass of thd cleanup
951
  return(test(remove_table_from_cache(session, db, table_list->table_name,
1 by brian
clean slate
952
             check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG)));
953
}
954
955
779.1.27 by Monty Taylor
Got rid of __attribute__((unused)) and the like from the .cc files.
956
void unlock_table_name(Session *,
327.2.4 by Brian Aker
Refactoring table.h
957
                       TableList *table_list)
1 by brian
clean slate
958
{
959
  if (table_list->table)
960
  {
481 by Brian Aker
Remove all of uchar.
961
    hash_delete(&open_cache, (unsigned char*) table_list->table);
1 by brian
clean slate
962
    broadcast_refresh();
963
  }
964
}
965
966
779.1.27 by Monty Taylor
Got rid of __attribute__((unused)) and the like from the .cc files.
967
static bool locked_named_table(Session *,
327.2.4 by Brian Aker
Refactoring table.h
968
                               TableList *table_list)
1 by brian
clean slate
969
{
970
  for (; table_list ; table_list=table_list->next_local)
971
  {
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
972
    Table *table= table_list->table;
1 by brian
clean slate
973
    if (table)
974
    {
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
975
      Table *save_next= table->next;
1 by brian
clean slate
976
      bool result;
977
      table->next= 0;
978
      result= table_is_used(table_list->table, 0);
979
      table->next= save_next;
980
      if (result)
981
        return 1;
982
    }
983
  }
984
  return 0;					// All tables are locked
985
}
986
987
520.1.22 by Brian Aker
Second pass of thd cleanup
988
bool wait_for_locked_table_names(Session *session, TableList *table_list)
1 by brian
clean slate
989
{
990
  bool result=0;
991
992
  safe_mutex_assert_owner(&LOCK_open);
993
520.1.22 by Brian Aker
Second pass of thd cleanup
994
  while (locked_named_table(session,table_list))
1 by brian
clean slate
995
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
996
    if (session->killed)
1 by brian
clean slate
997
    {
998
      result=1;
999
      break;
1000
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
1001
    wait_for_condition(session, &LOCK_open, &COND_refresh);
1 by brian
clean slate
1002
    pthread_mutex_lock(&LOCK_open);
1003
  }
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1004
  return(result);
1 by brian
clean slate
1005
}
1006
1007
1008
/**
1009
  Lock all tables in list with a name lock.
1010
1011
  REQUIREMENTS
1012
  - One must have a lock on LOCK_open when calling this
1013
520.1.22 by Brian Aker
Second pass of thd cleanup
1014
  @param session			Thread handle
1 by brian
clean slate
1015
  @param table_list		Names of tables to lock
1016
1017
  @note
1018
    If you are just locking one table, you should use
1019
    lock_and_wait_for_table_name().
1020
1021
  @retval
1022
    0	ok
1023
  @retval
1024
    1	Fatal error (end of memory ?)
1025
*/
1026
520.1.22 by Brian Aker
Second pass of thd cleanup
1027
bool lock_table_names(Session *session, TableList *table_list)
1 by brian
clean slate
1028
{
1029
  bool got_all_locks=1;
327.2.4 by Brian Aker
Refactoring table.h
1030
  TableList *lock_table;
1 by brian
clean slate
1031
1032
  for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
1033
  {
1034
    int got_lock;
520.1.22 by Brian Aker
Second pass of thd cleanup
1035
    if ((got_lock=lock_table_name(session,lock_table, true)) < 0)
1 by brian
clean slate
1036
      goto end;					// Fatal error
1037
    if (got_lock)
1038
      got_all_locks=0;				// Someone is using table
1039
  }
1040
1041
  /* If some table was in use, wait until we got the lock */
520.1.22 by Brian Aker
Second pass of thd cleanup
1042
  if (!got_all_locks && wait_for_locked_table_names(session, table_list))
1 by brian
clean slate
1043
    goto end;
1044
  return 0;
1045
1046
end:
520.1.22 by Brian Aker
Second pass of thd cleanup
1047
  unlock_table_names(session, table_list, lock_table);
1 by brian
clean slate
1048
  return 1;
1049
}
1050
1051
1052
/**
1053
  Unlock all tables in list with a name lock.
1054
520.1.22 by Brian Aker
Second pass of thd cleanup
1055
  @param session        Thread handle.
1 by brian
clean slate
1056
  @param table_list Names of tables to lock.
1057
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
1058
  @note
1059
    This function needs to be protected by LOCK_open. If we're
1 by brian
clean slate
1060
    under LOCK TABLES, this function does not work as advertised. Namely,
1061
    it does not exclude other threads from using this table and does not
1062
    put an exclusive name lock on this table into the table cache.
1063
1064
  @see lock_table_names
1065
  @see unlock_table_names
1066
1067
  @retval TRUE An error occured.
1068
  @retval FALSE Name lock successfully acquired.
1069
*/
1070
520.1.22 by Brian Aker
Second pass of thd cleanup
1071
bool lock_table_names_exclusively(Session *session, TableList *table_list)
1 by brian
clean slate
1072
{
520.1.22 by Brian Aker
Second pass of thd cleanup
1073
  if (lock_table_names(session, table_list))
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1074
    return true;
1 by brian
clean slate
1075
1076
  /*
1077
    Upgrade the table name locks from semi-exclusive to exclusive locks.
1078
  */
327.2.4 by Brian Aker
Refactoring table.h
1079
  for (TableList *table= table_list; table; table= table->next_global)
1 by brian
clean slate
1080
  {
1081
    if (table->table)
1082
      table->table->open_placeholder= 1;
1083
  }
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1084
  return false;
1 by brian
clean slate
1085
}
1086
1087
1088
/**
1089
  Test is 'table' is protected by an exclusive name lock.
1090
520.1.22 by Brian Aker
Second pass of thd cleanup
1091
  @param[in] session        The current thread handler
1 by brian
clean slate
1092
  @param[in] table_list Table container containing the single table to be
1093
                        tested
1094
1095
  @note Needs to be protected by LOCK_open mutex.
1096
1097
  @return Error status code
1098
    @retval TRUE Table is protected
1099
    @retval FALSE Table is not protected
1100
*/
1101
1102
bool
520.1.22 by Brian Aker
Second pass of thd cleanup
1103
is_table_name_exclusively_locked_by_this_thread(Session *session,
327.2.4 by Brian Aker
Refactoring table.h
1104
                                                TableList *table_list)
1 by brian
clean slate
1105
{
1106
  char  key[MAX_DBKEY_LENGTH];
482 by Brian Aker
Remove uint.
1107
  uint32_t  key_length;
1 by brian
clean slate
1108
520.1.22 by Brian Aker
Second pass of thd cleanup
1109
  key_length= create_table_def_key(session, key, table_list, 0);
1 by brian
clean slate
1110
520.1.22 by Brian Aker
Second pass of thd cleanup
1111
  return is_table_name_exclusively_locked_by_this_thread(session, (unsigned char *)key,
1 by brian
clean slate
1112
                                                         key_length);
1113
}
1114
1115
1116
/**
1117
  Test is 'table key' is protected by an exclusive name lock.
1118
520.1.22 by Brian Aker
Second pass of thd cleanup
1119
  @param[in] session        The current thread handler.
1 by brian
clean slate
1120
  @param[in] key
1121
  @param[in] key_length
1122
1123
  @note Needs to be protected by LOCK_open mutex
1124
1125
  @retval TRUE Table is protected
1126
  @retval FALSE Table is not protected
1127
 */
1128
1129
bool
520.1.22 by Brian Aker
Second pass of thd cleanup
1130
is_table_name_exclusively_locked_by_this_thread(Session *session, unsigned char *key,
1 by brian
clean slate
1131
                                                int key_length)
1132
{
1133
  HASH_SEARCH_STATE state;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
1134
  Table *table;
1 by brian
clean slate
1135
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
1136
  for (table= (Table*) hash_first(&open_cache, key,
1 by brian
clean slate
1137
                                  key_length, &state);
1138
       table ;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
1139
       table= (Table*) hash_next(&open_cache, key,
1 by brian
clean slate
1140
                                 key_length, &state))
1141
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
1142
    if (table->in_use == session &&
1 by brian
clean slate
1143
        table->open_placeholder == 1 &&
1144
        table->s->version == 0)
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1145
      return true;
1 by brian
clean slate
1146
  }
1147
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1148
  return false;
1 by brian
clean slate
1149
}
1150
1151
/**
1152
  Unlock all tables in list with a name lock.
1153
1154
  @param
520.1.22 by Brian Aker
Second pass of thd cleanup
1155
    session			Thread handle
1 by brian
clean slate
1156
  @param
1157
    table_list		Names of tables to unlock
1158
  @param
1159
    last_table		Don't unlock any tables after this one.
1160
			        (default 0, which will unlock all tables)
1161
1162
  @note
1163
    One must have a lock on LOCK_open when calling this.
1164
1165
  @note
1166
    This function will broadcast refresh signals to inform other threads
1167
    that the name locks are removed.
1168
1169
  @retval
1170
    0	ok
1171
  @retval
1172
    1	Fatal error (end of memory ?)
1173
*/
1174
520.1.22 by Brian Aker
Second pass of thd cleanup
1175
void unlock_table_names(Session *session, TableList *table_list,
327.2.4 by Brian Aker
Refactoring table.h
1176
			TableList *last_table)
1 by brian
clean slate
1177
{
327.2.4 by Brian Aker
Refactoring table.h
1178
  for (TableList *table= table_list;
1 by brian
clean slate
1179
       table != last_table;
1180
       table= table->next_local)
520.1.22 by Brian Aker
Second pass of thd cleanup
1181
    unlock_table_name(session,table);
1 by brian
clean slate
1182
  broadcast_refresh();
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1183
  return;
1 by brian
clean slate
1184
}
1185
1186
1187
static void print_lock_error(int error, const char *table)
1188
{
1189
  int textno;
1190
1191
  switch (error) {
1192
  case HA_ERR_LOCK_WAIT_TIMEOUT:
1193
    textno=ER_LOCK_WAIT_TIMEOUT;
1194
    break;
1195
  case HA_ERR_READ_ONLY_TRANSACTION:
1196
    textno=ER_READ_ONLY_TRANSACTION;
1197
    break;
1198
  case HA_ERR_LOCK_DEADLOCK:
1199
    textno=ER_LOCK_DEADLOCK;
1200
    break;
1201
  case HA_ERR_WRONG_COMMAND:
1202
    textno=ER_ILLEGAL_HA;
1203
    break;
1204
  default:
1205
    textno=ER_CANT_LOCK;
1206
    break;
1207
  }
1208
1209
  if ( textno == ER_ILLEGAL_HA )
1210
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), table);
1211
  else
1212
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error);
1213
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1214
  return;
1 by brian
clean slate
1215
}
1216
1217
1218
/****************************************************************************
1219
  Handling of global read locks
1220
1221
  Taking the global read lock is TWO steps (2nd step is optional; without
1222
  it, COMMIT of existing transactions will be allowed):
1223
  lock_global_read_lock() THEN make_global_read_lock_block_commit().
1224
1225
  The global locks are handled through the global variables:
1226
  global_read_lock
1227
    count of threads which have the global read lock (i.e. have completed at
1228
    least the first step above)
1229
  global_read_lock_blocks_commit
1230
    count of threads which have the global read lock and block
1231
    commits (i.e. are in or have completed the second step above)
1232
  waiting_for_read_lock
1233
    count of threads which want to take a global read lock but cannot
1234
  protect_against_global_read_lock
1235
    count of threads which have set protection against global read lock.
1236
1237
  access to them is protected with a mutex LOCK_global_read_lock
1238
1239
  (XXX: one should never take LOCK_open if LOCK_global_read_lock is
1240
  taken, otherwise a deadlock may occur. Other mutexes could be a
1241
  problem too - grep the code for global_read_lock if you want to use
1242
  any other mutex here) Also one must not hold LOCK_open when calling
1243
  wait_if_global_read_lock(). When the thread with the global read lock
1244
  tries to close its tables, it needs to take LOCK_open in
1245
  close_thread_table().
1246
1247
  How blocking of threads by global read lock is achieved: that's
1248
  advisory. Any piece of code which should be blocked by global read lock must
1249
  be designed like this:
1250
  - call to wait_if_global_read_lock(). When this returns 0, no global read
1251
  lock is owned; if argument abort_on_refresh was 0, none can be obtained.
1252
  - job
1253
  - if abort_on_refresh was 0, call to start_waiting_global_read_lock() to
1254
  allow other threads to get the global read lock. I.e. removal of the
1255
  protection.
1256
  (Note: it's a bit like an implementation of rwlock).
1257
1258
  [ I am sorry to mention some SQL syntaxes below I know I shouldn't but found
1259
  no better descriptive way ]
1260
1261
  Why does FLUSH TABLES WITH READ LOCK need to block COMMIT: because it's used
1262
  to read a non-moving SHOW MASTER STATUS, and a COMMIT writes to the binary
1263
  log.
1264
1265
  Why getting the global read lock is two steps and not one. Because FLUSH
1266
  TABLES WITH READ LOCK needs to insert one other step between the two:
1267
  flushing tables. So the order is
1268
  1) lock_global_read_lock() (prevents any new table write locks, i.e. stalls
1269
  all new updates)
1270
  2) close_cached_tables() (the FLUSH TABLES), which will wait for tables
1271
  currently opened and being updated to close (so it's possible that there is
1272
  a moment where all new updates of server are stalled *and* FLUSH TABLES WITH
1273
  READ LOCK is, too).
1274
  3) make_global_read_lock_block_commit().
1275
  If we have merged 1) and 3) into 1), we would have had this deadlock:
1276
  imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
1277
  table t.
520.1.22 by Brian Aker
Second pass of thd cleanup
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.
1 by brian
clean slate
1284
1285
  Note that we need to support that one thread does
1286
  FLUSH TABLES WITH READ LOCK; and then COMMIT;
1287
  (that's what innobackup does, for some good reason).
1288
  So in this exceptional case the COMMIT should not be blocked by the FLUSH
1289
  TABLES WITH READ LOCK.
1290
1291
****************************************************************************/
1292
482 by Brian Aker
Remove uint.
1293
volatile uint32_t global_read_lock=0;
1294
volatile uint32_t global_read_lock_blocks_commit=0;
1295
static volatile uint32_t protect_against_global_read_lock=0;
1296
static volatile uint32_t waiting_for_read_lock=0;
1 by brian
clean slate
1297
1298
#define GOT_GLOBAL_READ_LOCK               1
1299
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
1300
520.1.22 by Brian Aker
Second pass of thd cleanup
1301
bool lock_global_read_lock(Session *session)
1 by brian
clean slate
1302
{
520.1.22 by Brian Aker
Second pass of thd cleanup
1303
  if (!session->global_read_lock)
1 by brian
clean slate
1304
  {
1305
    const char *old_message;
1306
    (void) pthread_mutex_lock(&LOCK_global_read_lock);
520.1.22 by Brian Aker
Second pass of thd cleanup
1307
    old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1 by brian
clean slate
1308
                                "Waiting to get readlock");
1309
1310
    waiting_for_read_lock++;
520.1.22 by Brian Aker
Second pass of thd cleanup
1311
    while (protect_against_global_read_lock && !session->killed)
1 by brian
clean slate
1312
      pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1313
    waiting_for_read_lock--;
520.1.22 by Brian Aker
Second pass of thd cleanup
1314
    if (session->killed)
1 by brian
clean slate
1315
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
1316
      session->exit_cond(old_message);
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1317
      return(1);
1 by brian
clean slate
1318
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
1319
    session->global_read_lock= GOT_GLOBAL_READ_LOCK;
1 by brian
clean slate
1320
    global_read_lock++;
520.1.22 by Brian Aker
Second pass of thd cleanup
1321
    session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1 by brian
clean slate
1322
  }
1323
  /*
1324
    We DON'T set global_read_lock_blocks_commit now, it will be set after
1325
    tables are flushed (as the present function serves for FLUSH TABLES WITH
1326
    READ LOCK only). Doing things in this order is necessary to avoid
1327
    deadlocks (we must allow COMMIT until all tables are closed; we should not
1328
    forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
1329
    UPDATE and one does FLUSH TABLES WITH READ LOCK).
1330
  */
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1331
  return(0);
1 by brian
clean slate
1332
}
1333
1334
520.1.22 by Brian Aker
Second pass of thd cleanup
1335
void unlock_global_read_lock(Session *session)
1 by brian
clean slate
1336
{
482 by Brian Aker
Remove uint.
1337
  uint32_t tmp;
1 by brian
clean slate
1338
1339
  pthread_mutex_lock(&LOCK_global_read_lock);
1340
  tmp= --global_read_lock;
520.1.22 by Brian Aker
Second pass of thd cleanup
1341
  if (session->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1 by brian
clean slate
1342
    --global_read_lock_blocks_commit;
1343
  pthread_mutex_unlock(&LOCK_global_read_lock);
1344
  /* Send the signal outside the mutex to avoid a context switch */
1345
  if (!tmp)
1346
  {
1347
    pthread_cond_broadcast(&COND_global_read_lock);
1348
  }
520.1.22 by Brian Aker
Second pass of thd cleanup
1349
  session->global_read_lock= 0;
1 by brian
clean slate
1350
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1351
  return;
1 by brian
clean slate
1352
}
1353
1354
#define must_wait (global_read_lock &&                             \
1355
                   (is_not_commit ||                               \
1356
                    global_read_lock_blocks_commit))
1357
520.1.22 by Brian Aker
Second pass of thd cleanup
1358
bool wait_if_global_read_lock(Session *session, bool abort_on_refresh,
1 by brian
clean slate
1359
                              bool is_not_commit)
1360
{
1361
  const char *old_message= NULL;
1362
  bool result= 0, need_exit_cond;
1363
1364
  /*
1365
    Assert that we do not own LOCK_open. If we would own it, other
1366
    threads could not close their tables. This would make a pretty
1367
    deadlock.
1368
  */
1369
  safe_mutex_assert_not_owner(&LOCK_open);
1370
1371
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
1372
  if ((need_exit_cond= must_wait))
1373
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
1374
    if (session->global_read_lock)		// This thread had the read locks
1 by brian
clean slate
1375
    {
1376
      if (is_not_commit)
1377
        my_message(ER_CANT_UPDATE_WITH_READLOCK,
1378
                   ER(ER_CANT_UPDATE_WITH_READLOCK), MYF(0));
1379
      (void) pthread_mutex_unlock(&LOCK_global_read_lock);
1380
      /*
1381
        We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
1382
        This allowance is needed to not break existing versions of innobackup
1383
        which do a BEGIN; INSERT; FLUSH TABLES WITH READ LOCK; COMMIT.
1384
      */
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1385
      return(is_not_commit);
1 by brian
clean slate
1386
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
1387
    old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1 by brian
clean slate
1388
				"Waiting for release of readlock");
520.1.22 by Brian Aker
Second pass of thd cleanup
1389
    while (must_wait && ! session->killed &&
1390
	   (!abort_on_refresh || session->version == refresh_version))
1 by brian
clean slate
1391
    {
1392
      (void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1393
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
1394
    if (session->killed)
1 by brian
clean slate
1395
      result=1;
1396
  }
1397
  if (!abort_on_refresh && !result)
1398
    protect_against_global_read_lock++;
1399
  /*
1400
    The following is only true in case of a global read locks (which is rare)
1401
    and if old_message is set
1402
  */
1403
  if (unlikely(need_exit_cond))
520.1.22 by Brian Aker
Second pass of thd cleanup
1404
    session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1 by brian
clean slate
1405
  else
1406
    pthread_mutex_unlock(&LOCK_global_read_lock);
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1407
  return(result);
1 by brian
clean slate
1408
}
1409
1410
520.1.22 by Brian Aker
Second pass of thd cleanup
1411
void start_waiting_global_read_lock(Session *session)
1 by brian
clean slate
1412
{
1413
  bool tmp;
520.1.22 by Brian Aker
Second pass of thd cleanup
1414
  if (unlikely(session->global_read_lock))
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1415
    return;
1 by brian
clean slate
1416
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
1417
  tmp= (!--protect_against_global_read_lock &&
1418
        (waiting_for_read_lock || global_read_lock_blocks_commit));
1419
  (void) pthread_mutex_unlock(&LOCK_global_read_lock);
1420
  if (tmp)
1421
    pthread_cond_broadcast(&COND_global_read_lock);
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1422
  return;
1 by brian
clean slate
1423
}
1424
1425
520.1.22 by Brian Aker
Second pass of thd cleanup
1426
bool make_global_read_lock_block_commit(Session *session)
1 by brian
clean slate
1427
{
1428
  bool error;
1429
  const char *old_message;
1430
  /*
1431
    If we didn't succeed lock_global_read_lock(), or if we already suceeded
1432
    make_global_read_lock_block_commit(), do nothing.
1433
  */
520.1.22 by Brian Aker
Second pass of thd cleanup
1434
  if (session->global_read_lock != GOT_GLOBAL_READ_LOCK)
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1435
    return(0);
1 by brian
clean slate
1436
  pthread_mutex_lock(&LOCK_global_read_lock);
1437
  /* increment this BEFORE waiting on cond (otherwise race cond) */
1438
  global_read_lock_blocks_commit++;
520.1.22 by Brian Aker
Second pass of thd cleanup
1439
  old_message= session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1 by brian
clean slate
1440
                               "Waiting for all running commits to finish");
520.1.22 by Brian Aker
Second pass of thd cleanup
1441
  while (protect_against_global_read_lock && !session->killed)
1 by brian
clean slate
1442
    pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
520.1.22 by Brian Aker
Second pass of thd cleanup
1443
  if ((error= test(session->killed)))
1 by brian
clean slate
1444
    global_read_lock_blocks_commit--; // undo what we did
1445
  else
520.1.22 by Brian Aker
Second pass of thd cleanup
1446
    session->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1447
  session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1448
  return(error);
1 by brian
clean slate
1449
}
1450
1451
1452
/**
1453
  Broadcast COND_refresh and COND_global_read_lock.
1454
1455
    Due to a bug in a threading library it could happen that a signal
1456
    did not reach its target. A condition for this was that the same
1457
    condition variable was used with different mutexes in
1458
    pthread_cond_wait(). Some time ago we changed LOCK_open to
1459
    LOCK_global_read_lock in global read lock handling. So COND_refresh
1460
    was used with LOCK_open and LOCK_global_read_lock.
1461
1462
    We did now also change from COND_refresh to COND_global_read_lock
1463
    in global read lock handling. But now it is necessary to signal
1464
    both conditions at the same time.
1465
1466
  @note
1467
    When signalling COND_global_read_lock within the global read lock
1468
    handling, it is not necessary to also signal COND_refresh.
1469
*/
1470
1471
void broadcast_refresh(void)
1472
{
398.1.10 by Monty Taylor
Actually removed VOID() this time.
1473
  pthread_cond_broadcast(&COND_refresh);
1474
  pthread_cond_broadcast(&COND_global_read_lock);
1 by brian
clean slate
1475
}
1476
1477
1478
/*
1479
  Try to get transactional table locks for the tables in the list.
1480
1481
  SYNOPSIS
1482
    try_transactional_lock()
520.1.22 by Brian Aker
Second pass of thd cleanup
1483
      session                       Thread handle
1 by brian
clean slate
1484
      table_list                List of tables to lock
1485
1486
  DESCRIPTION
1487
    This is called if transactional table locks are requested for all
1488
    tables in table_list and no non-transactional locks pre-exist.
1489
1490
  RETURN
1491
    0                   OK. All tables are transactional locked.
1492
    1                   Error: must fall back to non-transactional locks.
1493
    -1                  Error: no recovery possible.
1494
*/
1495
520.1.22 by Brian Aker
Second pass of thd cleanup
1496
int try_transactional_lock(Session *session, TableList *table_list)
1 by brian
clean slate
1497
{
482 by Brian Aker
Remove uint.
1498
  uint32_t          dummy_counter;
1 by brian
clean slate
1499
  int           error;
1500
  int           result= 0;
1501
1502
  /* Need to open the tables to be able to access engine methods. */
520.1.22 by Brian Aker
Second pass of thd cleanup
1503
  if (open_tables(session, &table_list, &dummy_counter, 0))
1 by brian
clean slate
1504
  {
1505
    /* purecov: begin tested */
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1506
    return(-1);
1 by brian
clean slate
1507
    /* purecov: end */
1508
  }
1509
1510
  /* Required by InnoDB. */
520.1.22 by Brian Aker
Second pass of thd cleanup
1511
  session->in_lock_tables= true;
1 by brian
clean slate
1512
520.1.22 by Brian Aker
Second pass of thd cleanup
1513
  if ((error= set_handler_table_locks(session, table_list, true)))
1 by brian
clean slate
1514
  {
1515
    /*
1516
      Not all transactional locks could be taken. If the error was
1517
      something else but "unsupported by storage engine", abort the
1518
      execution of this statement.
1519
    */
1520
    if (error != HA_ERR_WRONG_COMMAND)
1521
    {
1522
      result= -1;
1523
      goto err;
1524
    }
1525
    /*
1526
      Fall back to non-transactional locks because transactional locks
1527
      are unsupported by a storage engine. No need to unlock the
1528
      successfully taken transactional locks. They go away at end of
1529
      transaction anyway.
1530
    */
1531
    result= 1;
1532
  }
1533
1534
 err:
1535
  /* We need to explicitly commit if autocommit mode is active. */
520.1.22 by Brian Aker
Second pass of thd cleanup
1536
  (void) ha_autocommit_or_rollback(session, 0);
1 by brian
clean slate
1537
  /* Close the tables. The locks (if taken) persist in the storage engines. */
520.1.22 by Brian Aker
Second pass of thd cleanup
1538
  close_tables_for_reopen(session, &table_list);
1539
  session->in_lock_tables= false;
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1540
  return(result);
1 by brian
clean slate
1541
}
1542
1543
1544
/*
1545
  Check if lock method conversion was done and was allowed.
1546
1547
  SYNOPSIS
1548
    check_transactional_lock()
520.1.22 by Brian Aker
Second pass of thd cleanup
1549
      session                       Thread handle
1 by brian
clean slate
1550
      table_list                List of tables to lock
1551
1552
  DESCRIPTION
1553
1554
    Lock method conversion can be done during parsing if one of the
1555
    locks is non-transactional. It can also happen if non-transactional
1556
    table locks exist when the statement is executed or if a storage
1557
    engine does not support transactional table locks.
1558
1559
    Check if transactional table locks have been converted to
1560
    non-transactional and if this was allowed. In a running transaction
1561
    or in strict mode lock method conversion is not allowed - report an
1562
    error. Otherwise it is allowed - issue a warning.
1563
1564
  RETURN
1565
    0                   OK. Proceed with non-transactional locks.
1566
    -1                  Error: Lock conversion is prohibited.
1567
*/
1568
779.3.53 by Monty Taylor
Revert the fail.
1569
int check_transactional_lock(Session *session, TableList *table_list)
1 by brian
clean slate
1570
{
327.2.4 by Brian Aker
Refactoring table.h
1571
  TableList    *tlist;
1 by brian
clean slate
1572
  int           result= 0;
779.3.53 by Monty Taylor
Revert the fail.
1573
  char          warn_buff[DRIZZLE_ERRMSG_SIZE];
1 by brian
clean slate
1574
1575
  for (tlist= table_list; tlist; tlist= tlist->next_global)
1576
  {
1577
1578
    /*
1579
      Unfortunately we cannot use tlist->placeholder() here. This method
1580
      returns TRUE if the table is not open, which is always the case
327.2.4 by Brian Aker
Refactoring table.h
1581
      here. Whenever the definition of TableList::placeholder() is
1 by brian
clean slate
1582
      changed, probably this condition needs to be changed too.
1583
    */
1584
    if (tlist->derived || tlist->schema_table || !tlist->lock_transactional)
1585
    {
1586
      continue;
1587
    }
1588
1589
    /* We must not convert the lock method in strict mode. */
779.3.53 by Monty Taylor
Revert the fail.
1590
    {
1591
      my_error(ER_NO_AUTO_CONVERT_LOCK_STRICT, MYF(0),
1592
               tlist->alias ? tlist->alias : tlist->table_name);
1593
      result= -1;
1594
      continue;
1595
    }
1596
1597
    /* We must not convert the lock method within an active transaction. */
1598
    if (session->active_transaction())
1599
    {
1600
      my_error(ER_NO_AUTO_CONVERT_LOCK_TRANSACTION, MYF(0),
1601
               tlist->alias ? tlist->alias : tlist->table_name);
1602
      result= -1;
1603
      continue;
1604
    }
1605
1606
    /* Warn about the conversion. */
1607
    snprintf(warn_buff, sizeof(warn_buff), ER(ER_WARN_AUTO_CONVERT_LOCK),
77.1.18 by Monty Taylor
Removed my_vsnprintf and my_snprintf.
1608
             tlist->alias ? tlist->alias : tlist->table_name);
779.3.53 by Monty Taylor
Revert the fail.
1609
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1610
                 ER_WARN_AUTO_CONVERT_LOCK, warn_buff);
1 by brian
clean slate
1611
  }
1612
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1613
  return(result);
1 by brian
clean slate
1614
}
1615
1616
1617
/*
1618
  Set table locks in the table handler.
1619
1620
  SYNOPSIS
1621
    set_handler_table_locks()
520.1.22 by Brian Aker
Second pass of thd cleanup
1622
      session                       Thread handle
1 by brian
clean slate
1623
      table_list                List of tables to lock
1624
      transactional             If to lock transactional or non-transactional
1625
1626
  RETURN
1627
    0                   OK.
1628
    != 0                Error code from handler::lock_table().
1629
*/
1630
520.1.22 by Brian Aker
Second pass of thd cleanup
1631
int set_handler_table_locks(Session *session, TableList *table_list,
1 by brian
clean slate
1632
                            bool transactional)
1633
{
327.2.4 by Brian Aker
Refactoring table.h
1634
  TableList    *tlist;
1 by brian
clean slate
1635
  int           error= 0;
1636
1637
  for (tlist= table_list; tlist; tlist= tlist->next_global)
1638
  {
1639
    int lock_type;
1640
    int lock_timeout= -1; /* Use default for non-transactional locks. */
1641
1642
    if (tlist->placeholder())
1643
      continue;
1644
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1645
    assert((tlist->lock_type == TL_READ) ||
1 by brian
clean slate
1646
                (tlist->lock_type == TL_READ_NO_INSERT) ||
1647
                (tlist->lock_type == TL_WRITE_DEFAULT) ||
1648
                (tlist->lock_type == TL_WRITE) ||
1649
                (tlist->lock_type == TL_WRITE_LOW_PRIORITY));
1650
1651
    /*
1652
      Every tlist object has a proper lock_type set. Even if it came in
1653
      the list as a base table from a view only.
1654
    */
1655
    lock_type= ((tlist->lock_type <= TL_READ_NO_INSERT) ?
1656
                HA_LOCK_IN_SHARE_MODE : HA_LOCK_IN_EXCLUSIVE_MODE);
1657
1658
    if (transactional)
1659
    {
1660
      /*
1661
        The lock timeout is not set if this table belongs to a view. We
1662
        need to take it from the top-level view. After this loop
1663
        iteration, lock_timeout is not needed any more. Not even if the
1664
        locks are converted to non-transactional locks later.
1665
        Non-transactional locks do not support a lock_timeout.
1666
      */
1667
      lock_timeout= tlist->top_table()->lock_timeout;
1668
1669
      /*
1670
        For warning/error reporting we need to set the intended lock
327.2.4 by Brian Aker
Refactoring table.h
1671
        method in the TableList object. It will be used later by
1 by brian
clean slate
1672
        check_transactional_lock(). The lock method is not set if this
1673
        table belongs to a view. We can safely set it to transactional
1674
        locking here. Even for non-view tables. This function is not
1675
        called if non-transactional locking was requested for any
1676
        object.
1677
      */
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1678
      tlist->lock_transactional= true;
1 by brian
clean slate
1679
    }
1680
1681
    /*
1682
      Because we need to set the lock method (see above) for all
1683
      involved tables, we cannot break the loop on an error.
1684
      But we do not try more locks after the first error.
1685
      However, for non-transactional locking handler::lock_table() is
1686
      a hint only. So we continue to call it for other tables.
1687
    */
1688
    if (!error || !transactional)
1689
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
1690
      error= tlist->table->file->lock_table(session, lock_type, lock_timeout);
1 by brian
clean slate
1691
      if (error && transactional && (error != HA_ERR_WRONG_COMMAND))
1692
        tlist->table->file->print_error(error, MYF(0));
1693
    }
1694
  }
1695
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1696
  return(error);
1 by brian
clean slate
1697
}
1698
1699
1700
/**
1701
  @} (end of group Locking)
1702
*/