~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
*/
1241.9.36 by Monty Taylor
ZOMG. I deleted drizzled/server_includes.h.
75
#include "config.h"
1241.9.1 by Monty Taylor
Removed global.h. Fixed all the headers.
76
#include <fcntl.h>
549 by Monty Taylor
Took gettext.h out of header files.
77
#include <drizzled/error.h>
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
78
#include <drizzled/my_hash.h>
1241.9.43 by Monty Taylor
Merged trunk. Also renamed thr_lock. Doh. I hate it when I do both.
79
#include <drizzled/thr_lock.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.
80
#include <drizzled/session.h>
81
#include <drizzled/sql_base.h>
670.2.4 by Monty Taylor
Removed more stuff from the headers.
82
#include <drizzled/lock.h>
1241.9.31 by Monty Taylor
Moved global pthread variables into their own header.
83
#include "drizzled/pthread_globals.h"
1241.9.64 by Monty Taylor
Moved remaining non-public portions of mysys and mystrings to drizzled/internal.
84
#include "drizzled/internal/my_sys.h"
1241.9.62 by Monty Taylor
Removed plugin/myisam/myisam.h from session.h
85
1 by brian
clean slate
86
87
/**
88
  @defgroup Locking Locking
89
  @{
90
*/
91
92
extern HASH open_cache;
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,
1046.1.7 by Brian Aker
Style cleanup.
96
                                   bool should_lock, 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,
1113.1.1 by Brian Aker
Dead code removal around LCOV finds.
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
  {
1046.1.7 by Brian Aker
Style cleanup.
179
    if (! (sql_lock= get_lock_data(session, tables, count, true,
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
1046.1.13 by Brian Aker
Remove malloc() of table.
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);
1054.1.8 by Brian Aker
Remove lock_tables list from session.
280
      sql_lock= NULL;
1 by brian
clean slate
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
1208.3.2 by brian
Update for Cursor renaming.
302
    if ((error=(*tables)->cursor->ha_external_lock(session,lock_type)))
1 by brian
clean slate
303
    {
1208.3.2 by brian
Update for Cursor renaming.
304
      print_lock_error(error, (*tables)->cursor->engine->getName().c_str());
1 by brian
clean slate
305
      while (--i)
306
      {
307
        tables--;
1208.3.2 by brian
Update for Cursor renaming.
308
	(*tables)->cursor->ha_external_lock(session, F_UNLCK);
1 by brian
clean slate
309
	(*tables)->current_lock=F_UNLCK;
310
      }
1046.1.7 by Brian Aker
Style cleanup.
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
  }
1046.1.7 by Brian Aker
Style cleanup.
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
1113.1.1 by Brian Aker
Dead code removal around LCOV finds.
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;
1046.1.7 by Brian Aker
Style cleanup.
343
  if ((sql_lock= get_lock_data(session, table, count, false,
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);
895 by Brian Aker
Completion (?) of uint conversion.
381
    if ((uint32_t) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
1 by brian
clean slate
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
1113.1.1 by Brian Aker
Dead code removal around LCOV finds.
429
void mysql_lock_remove(Session *session, Table *table)
1 by brian
clean slate
430
{
1113.1.1 by Brian Aker
Dead code removal around LCOV finds.
431
  mysql_unlock_some_tables(session, &table, /* table count */ 1);
1 by brian
clean slate
432
}
433
434
435
/** Abort all other threads waiting to get lock in table. */
436
1113.1.2 by Brian Aker
Refactor/kill some dead lock code.
437
void mysql_lock_abort(Session *session, Table *table)
1 by brian
clean slate
438
{
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
439
  DRIZZLE_LOCK *locked;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
440
  Table *write_lock_used;
1 by brian
clean slate
441
1046.1.7 by Brian Aker
Style cleanup.
442
  if ((locked= get_lock_data(session, &table, 1, false,
1 by brian
clean slate
443
                             &write_lock_used)))
444
  {
1113.1.2 by Brian Aker
Refactor/kill some dead lock code.
445
    for (uint32_t x= 0; x < locked->lock_count; x++)
446
      thr_abort_locks(locked->locks[x]->lock);
481 by Brian Aker
Remove all of uchar.
447
    free((unsigned char*) locked);
1 by brian
clean slate
448
  }
449
}
450
451
452
/**
453
  Abort one thread / table combination.
454
520.1.22 by Brian Aker
Second pass of thd cleanup
455
  @param session	   Thread handler
1 by brian
clean slate
456
  @param table	   Table that should be removed from lock queue
457
458
  @retval
459
    0  Table was not locked by another thread
460
  @retval
461
    1  Table was locked by at least one other thread
462
*/
463
520.1.22 by Brian Aker
Second pass of thd cleanup
464
bool mysql_lock_abort_for_thread(Session *session, Table *table)
1 by brian
clean slate
465
{
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
466
  DRIZZLE_LOCK *locked;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
467
  Table *write_lock_used;
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
468
  bool result= false;
1 by brian
clean slate
469
1046.1.7 by Brian Aker
Style cleanup.
470
  if ((locked= get_lock_data(session, &table, 1, false,
1 by brian
clean slate
471
                             &write_lock_used)))
472
  {
482 by Brian Aker
Remove uint.
473
    for (uint32_t i=0; i < locked->lock_count; i++)
1 by brian
clean slate
474
    {
475
      if (thr_abort_locks_for_thread(locked->locks[i]->lock,
476
                                     table->in_use->thread_id))
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
477
        result= true;
1 by brian
clean slate
478
    }
481 by Brian Aker
Remove all of uchar.
479
    free((unsigned char*) locked);
1 by brian
clean slate
480
  }
1046.1.7 by Brian Aker
Style cleanup.
481
  return result;
1 by brian
clean slate
482
}
483
484
485
/** Unlock a set of external. */
486
520.1.22 by Brian Aker
Second pass of thd cleanup
487
static int unlock_external(Session *session, Table **table,uint32_t count)
1 by brian
clean slate
488
{
489
  int error,error_code;
490
491
  error_code=0;
492
  do
493
  {
494
    if ((*table)->current_lock != F_UNLCK)
495
    {
496
      (*table)->current_lock = F_UNLCK;
1208.3.2 by brian
Update for Cursor renaming.
497
      if ((error=(*table)->cursor->ha_external_lock(session, F_UNLCK)))
1 by brian
clean slate
498
      {
499
	error_code=error;
1208.3.2 by brian
Update for Cursor renaming.
500
	print_lock_error(error_code, (*table)->cursor->engine->getName().c_str());
1 by brian
clean slate
501
      }
502
    }
503
    table++;
504
  } while (--count);
1046.1.7 by Brian Aker
Style cleanup.
505
  return error_code;
1 by brian
clean slate
506
}
507
508
509
/**
510
  Get lock structures from table structs and initialize locks.
511
520.1.22 by Brian Aker
Second pass of thd cleanup
512
  @param session		    Thread handler
1 by brian
clean slate
513
  @param table_ptr	    Pointer to tables that should be locks
1046.1.7 by Brian Aker
Style cleanup.
514
  @param should_lock		    One of:
515
           - false      : If we should send TL_IGNORE to store lock
516
           - true       : Store lock info in Table
1 by brian
clean slate
517
  @param write_lock_used   Store pointer to last table with WRITE_ALLOW_WRITE
518
*/
519
520.1.22 by Brian Aker
Second pass of thd cleanup
520
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table_ptr, uint32_t count,
1046.1.7 by Brian Aker
Style cleanup.
521
				 bool should_lock, Table **write_lock_used)
1 by brian
clean slate
522
{
482 by Brian Aker
Remove uint.
523
  uint32_t i,tables,lock_count;
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
524
  DRIZZLE_LOCK *sql_lock;
1 by brian
clean slate
525
  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
526
  Table **to, **table_buf;
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
527
1 by brian
clean slate
528
  *write_lock_used=0;
1046.1.7 by Brian Aker
Style cleanup.
529
  for (i= tables= lock_count= 0 ; i < count ; i++)
1 by brian
clean slate
530
  {
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
531
    Table *t= table_ptr[i];
1 by brian
clean slate
532
1235.1.2 by Brian Aker
Added engine flag so that an engine can skip store_lock.
533
    if (! (t->getEngine()->check_flag(HTON_BIT_SKIP_STORE_LOCK)))
1 by brian
clean slate
534
    {
1048 by Brian Aker
Removed useless handler call (was for MERGE).
535
      tables++;
1 by brian
clean slate
536
      lock_count++;
537
    }
538
  }
539
540
  /*
541
    Allocating twice the number of pointers for lock data for use in
542
    thr_mulit_lock(). This function reorders the lock data, but cannot
543
    update the table values. So the second part of the array is copied
544
    from the first part immediately before calling thr_multi_lock().
545
  */
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
546
  if (!(sql_lock= (DRIZZLE_LOCK*)
641.3.8 by Monty Taylor
Removed my_malloc from drizzled.
547
	malloc(sizeof(*sql_lock) +
548
               sizeof(THR_LOCK_DATA*) * tables * 2 +
549
               sizeof(table_ptr) * lock_count)))
1046.1.7 by Brian Aker
Style cleanup.
550
    return NULL;
1 by brian
clean slate
551
  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
552
  to= table_buf= sql_lock->table= (Table**) (locks + tables * 2);
1046.1.7 by Brian Aker
Style cleanup.
553
  sql_lock->table_count= lock_count;
1 by brian
clean slate
554
555
  for (i=0 ; i < count ; i++)
556
  {
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
557
    Table *table;
1 by brian
clean slate
558
    enum thr_lock_type lock_type;
559
1235.1.2 by Brian Aker
Added engine flag so that an engine can skip store_lock.
560
    if (table_ptr[i]->getEngine()->check_flag(HTON_BIT_SKIP_STORE_LOCK))
1 by brian
clean slate
561
      continue;
1235.1.2 by Brian Aker
Added engine flag so that an engine can skip store_lock.
562
1220.1.12 by Brian Aker
Small cleanup from something Jay noticed.
563
    table= table_ptr[i];
1 by brian
clean slate
564
    lock_type= table->reginfo.lock_type;
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
565
    assert (lock_type != TL_WRITE_DEFAULT);
1 by brian
clean slate
566
    if (lock_type >= TL_WRITE_ALLOW_WRITE)
567
    {
568
      *write_lock_used=table;
784.1.6 by Stewart Smith
merge
569
      if (table->db_stat & HA_READ_ONLY)
1 by brian
clean slate
570
      {
571
	my_error(ER_OPEN_AS_READONLY,MYF(0),table->alias);
572
        /* Clear the lock type of the lock data that are stored already. */
573
        sql_lock->lock_count= locks - sql_lock->locks;
574
        reset_lock_data_and_free(&sql_lock);
1046.1.7 by Brian Aker
Style cleanup.
575
	return NULL;
1 by brian
clean slate
576
      }
577
    }
578
    locks_start= locks;
1208.3.2 by brian
Update for Cursor renaming.
579
    locks= table->cursor->store_lock(session, locks,
1046.1.7 by Brian Aker
Style cleanup.
580
                                   should_lock == false ? TL_IGNORE : lock_type);
581
    if (should_lock)
1 by brian
clean slate
582
    {
895 by Brian Aker
Completion (?) of uint conversion.
583
      table->lock_position=   (uint32_t) (to - table_buf);
584
      table->lock_data_start= (uint32_t) (locks_start - locks_buf);
585
      table->lock_count=      (uint32_t) (locks - locks_start);
1046.1.7 by Brian Aker
Style cleanup.
586
      assert(table->lock_count == 1);
1 by brian
clean slate
587
    }
588
    *to++= table;
589
  }
590
  /*
591
    We do not use 'tables', because there are cases where store_lock()
592
    returns less locks than lock_count() claimed. This can happen when
593
    a FLUSH TABLES tries to abort locks from a MERGE table of another
594
    thread. When that thread has just opened the table, but not yet
595
    attached its children, it cannot return the locks. lock_count()
596
    always returns the number of locks that an attached table has.
597
    This is done to avoid the reverse situation: If lock_count() would
598
    return 0 for a non-attached MERGE table, and that table becomes
599
    attached between the calls to lock_count() and store_lock(), then
600
    we would have allocated too little memory for the lock data. Now
601
    we may allocate too much, but better safe than memory overrun.
602
    And in the FLUSH case, the memory is released quickly anyway.
603
  */
604
  sql_lock->lock_count= locks - locks_buf;
1046.1.7 by Brian Aker
Style cleanup.
605
606
  return sql_lock;
1 by brian
clean slate
607
}
608
609
610
/**
611
  Put a not open table with an old refresh version in the table cache.
612
520.1.22 by Brian Aker
Second pass of thd cleanup
613
  @param session			Thread handler
1 by brian
clean slate
614
  @param table_list		Lock first table in this list
615
  @param check_in_use           Do we need to check if table already in use by us
616
617
  @note
618
    One must have a lock on LOCK_open!
619
620
  @warning
621
    If you are going to update the table, you should use
1113.1.2 by Brian Aker
Refactor/kill some dead lock code.
622
    lock_and_wait_for_table_name(removed) instead of this function as this works
1 by brian
clean slate
623
    together with 'FLUSH TABLES WITH READ LOCK'
624
625
  @note
626
    This will force any other threads that uses the table to release it
627
    as soon as possible.
628
629
  @return
630
    < 0 error
631
  @return
632
    == 0 table locked
633
  @return
634
    > 0  table locked, but someone is using it
635
*/
636
520.1.22 by Brian Aker
Second pass of thd cleanup
637
int lock_table_name(Session *session, TableList *table_list, bool check_in_use)
1 by brian
clean slate
638
{
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
639
  Table *table;
1 by brian
clean slate
640
  char  key[MAX_DBKEY_LENGTH];
641
  char *db= table_list->db;
482 by Brian Aker
Remove uint.
642
  uint32_t  key_length;
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
643
  bool  found_locked_table= false;
1 by brian
clean slate
644
  HASH_SEARCH_STATE state;
645
1054.1.7 by Brian Aker
Refactor TableList methods.
646
  key_length= table_list->create_table_def_key(key);
1 by brian
clean slate
647
648
  if (check_in_use)
649
  {
650
    /* Only insert the table if we haven't insert it already */
481 by Brian Aker
Remove all of uchar.
651
    for (table=(Table*) hash_first(&open_cache, (unsigned char*)key,
1 by brian
clean slate
652
                                   key_length, &state);
653
         table ;
481 by Brian Aker
Remove all of uchar.
654
         table = (Table*) hash_next(&open_cache,(unsigned char*) key,
1 by brian
clean slate
655
                                    key_length, &state))
656
    {
657
      if (table->reginfo.lock_type < TL_WRITE)
658
      {
520.1.22 by Brian Aker
Second pass of thd cleanup
659
        if (table->in_use == session)
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
660
          found_locked_table= true;
1 by brian
clean slate
661
        continue;
662
      }
663
520.1.22 by Brian Aker
Second pass of thd cleanup
664
      if (table->in_use == session)
1 by brian
clean slate
665
      {
666
        table->s->version= 0;                  // Ensure no one can use this
667
        table->locked_by_name= 1;
1046.1.7 by Brian Aker
Style cleanup.
668
        return 0;
1 by brian
clean slate
669
      }
670
    }
671
  }
672
1054.1.9 by Brian Aker
This is a large number of refactors against the Session class for its
673
  if (!(table= session->table_cache_insert_placeholder(key, key_length)))
1046.1.7 by Brian Aker
Style cleanup.
674
    return -1;
1 by brian
clean slate
675
676
  table_list->table=table;
677
678
  /* Return 1 if table is in use */
520.1.22 by Brian Aker
Second pass of thd cleanup
679
  return(test(remove_table_from_cache(session, db, table_list->table_name,
1 by brian
clean slate
680
             check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG)));
681
}
682
683
1017 by Brian Aker
Drop dead session pass
684
void unlock_table_name(TableList *table_list)
1 by brian
clean slate
685
{
686
  if (table_list->table)
687
  {
481 by Brian Aker
Remove all of uchar.
688
    hash_delete(&open_cache, (unsigned char*) table_list->table);
1 by brian
clean slate
689
    broadcast_refresh();
690
  }
691
}
692
693
1019.1.1 by Brian Aker
Merge (also removes session from show variables).
694
static bool locked_named_table(TableList *table_list)
1 by brian
clean slate
695
{
696
  for (; table_list ; table_list=table_list->next_local)
697
  {
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
698
    Table *table= table_list->table;
1 by brian
clean slate
699
    if (table)
700
    {
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
701
      Table *save_next= table->next;
1 by brian
clean slate
702
      bool result;
703
      table->next= 0;
704
      result= table_is_used(table_list->table, 0);
705
      table->next= save_next;
706
      if (result)
707
        return 1;
708
    }
709
  }
710
  return 0;					// All tables are locked
711
}
712
713
520.1.22 by Brian Aker
Second pass of thd cleanup
714
bool wait_for_locked_table_names(Session *session, TableList *table_list)
1 by brian
clean slate
715
{
1046.1.7 by Brian Aker
Style cleanup.
716
  bool result= false;
1 by brian
clean slate
717
718
  safe_mutex_assert_owner(&LOCK_open);
719
1019.1.1 by Brian Aker
Merge (also removes session from show variables).
720
  while (locked_named_table(table_list))
1 by brian
clean slate
721
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
722
    if (session->killed)
1 by brian
clean slate
723
    {
724
      result=1;
725
      break;
726
    }
1054.1.10 by Brian Aker
Move open_table() to session.
727
    session->wait_for_condition(&LOCK_open, &COND_refresh);
1046.1.2 by Brian Aker
Comments on LOCK_open
728
    pthread_mutex_lock(&LOCK_open); /* Wait for a table to unlock and then lock it */
1 by brian
clean slate
729
  }
1046.1.7 by Brian Aker
Style cleanup.
730
  return result;
1 by brian
clean slate
731
}
732
733
734
/**
735
  Lock all tables in list with a name lock.
736
737
  REQUIREMENTS
738
  - One must have a lock on LOCK_open when calling this
739
740
  @param table_list		Names of tables to lock
741
742
  @retval
743
    0	ok
744
  @retval
745
    1	Fatal error (end of memory ?)
746
*/
747
520.1.22 by Brian Aker
Second pass of thd cleanup
748
bool lock_table_names(Session *session, TableList *table_list)
1 by brian
clean slate
749
{
750
  bool got_all_locks=1;
327.2.4 by Brian Aker
Refactoring table.h
751
  TableList *lock_table;
1 by brian
clean slate
752
753
  for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
754
  {
755
    int got_lock;
1019.1.1 by Brian Aker
Merge (also removes session from show variables).
756
    if ((got_lock= lock_table_name(session,lock_table, true)) < 0)
1 by brian
clean slate
757
      goto end;					// Fatal error
758
    if (got_lock)
759
      got_all_locks=0;				// Someone is using table
760
  }
761
762
  /* If some table was in use, wait until we got the lock */
520.1.22 by Brian Aker
Second pass of thd cleanup
763
  if (!got_all_locks && wait_for_locked_table_names(session, table_list))
1 by brian
clean slate
764
    goto end;
1034.1.7 by Brian Aker
Remove dead bits to the end of functions.
765
  return false;
1 by brian
clean slate
766
767
end:
1017 by Brian Aker
Drop dead session pass
768
  unlock_table_names(table_list, lock_table);
1034.1.7 by Brian Aker
Remove dead bits to the end of functions.
769
770
  return true;
1 by brian
clean slate
771
}
772
773
774
/**
775
  Unlock all tables in list with a name lock.
776
520.1.22 by Brian Aker
Second pass of thd cleanup
777
  @param session        Thread handle.
1 by brian
clean slate
778
  @param table_list Names of tables to lock.
779
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
780
  @note
781
    This function needs to be protected by LOCK_open. If we're
1 by brian
clean slate
782
    under LOCK TABLES, this function does not work as advertised. Namely,
783
    it does not exclude other threads from using this table and does not
784
    put an exclusive name lock on this table into the table cache.
785
786
  @see lock_table_names
787
  @see unlock_table_names
788
789
  @retval TRUE An error occured.
790
  @retval FALSE Name lock successfully acquired.
791
*/
792
520.1.22 by Brian Aker
Second pass of thd cleanup
793
bool lock_table_names_exclusively(Session *session, TableList *table_list)
1 by brian
clean slate
794
{
520.1.22 by Brian Aker
Second pass of thd cleanup
795
  if (lock_table_names(session, table_list))
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
796
    return true;
1 by brian
clean slate
797
798
  /*
799
    Upgrade the table name locks from semi-exclusive to exclusive locks.
800
  */
327.2.4 by Brian Aker
Refactoring table.h
801
  for (TableList *table= table_list; table; table= table->next_global)
1 by brian
clean slate
802
  {
803
    if (table->table)
804
      table->table->open_placeholder= 1;
805
  }
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
806
  return false;
1 by brian
clean slate
807
}
808
809
810
/**
811
  Unlock all tables in list with a name lock.
812
813
  @param
814
    table_list		Names of tables to unlock
815
  @param
816
    last_table		Don't unlock any tables after this one.
817
			        (default 0, which will unlock all tables)
818
819
  @note
820
    One must have a lock on LOCK_open when calling this.
821
822
  @note
823
    This function will broadcast refresh signals to inform other threads
824
    that the name locks are removed.
825
826
  @retval
827
    0	ok
828
  @retval
829
    1	Fatal error (end of memory ?)
830
*/
831
1017 by Brian Aker
Drop dead session pass
832
void unlock_table_names(TableList *table_list, TableList *last_table)
1 by brian
clean slate
833
{
327.2.4 by Brian Aker
Refactoring table.h
834
  for (TableList *table= table_list;
1 by brian
clean slate
835
       table != last_table;
836
       table= table->next_local)
1017 by Brian Aker
Drop dead session pass
837
    unlock_table_name(table);
1 by brian
clean slate
838
  broadcast_refresh();
839
}
840
841
842
static void print_lock_error(int error, const char *table)
843
{
844
  int textno;
845
846
  switch (error) {
847
  case HA_ERR_LOCK_WAIT_TIMEOUT:
848
    textno=ER_LOCK_WAIT_TIMEOUT;
849
    break;
850
  case HA_ERR_READ_ONLY_TRANSACTION:
851
    textno=ER_READ_ONLY_TRANSACTION;
852
    break;
853
  case HA_ERR_LOCK_DEADLOCK:
854
    textno=ER_LOCK_DEADLOCK;
855
    break;
856
  case HA_ERR_WRONG_COMMAND:
857
    textno=ER_ILLEGAL_HA;
858
    break;
859
  default:
860
    textno=ER_CANT_LOCK;
861
    break;
862
  }
863
864
  if ( textno == ER_ILLEGAL_HA )
865
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), table);
866
  else
867
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error);
868
}
869
870
871
/****************************************************************************
872
  Handling of global read locks
873
874
  Taking the global read lock is TWO steps (2nd step is optional; without
875
  it, COMMIT of existing transactions will be allowed):
876
  lock_global_read_lock() THEN make_global_read_lock_block_commit().
877
878
  The global locks are handled through the global variables:
879
  global_read_lock
880
    count of threads which have the global read lock (i.e. have completed at
881
    least the first step above)
882
  global_read_lock_blocks_commit
883
    count of threads which have the global read lock and block
884
    commits (i.e. are in or have completed the second step above)
885
  waiting_for_read_lock
886
    count of threads which want to take a global read lock but cannot
887
  protect_against_global_read_lock
888
    count of threads which have set protection against global read lock.
889
890
  access to them is protected with a mutex LOCK_global_read_lock
891
892
  (XXX: one should never take LOCK_open if LOCK_global_read_lock is
893
  taken, otherwise a deadlock may occur. Other mutexes could be a
894
  problem too - grep the code for global_read_lock if you want to use
895
  any other mutex here) Also one must not hold LOCK_open when calling
896
  wait_if_global_read_lock(). When the thread with the global read lock
897
  tries to close its tables, it needs to take LOCK_open in
898
  close_thread_table().
899
900
  How blocking of threads by global read lock is achieved: that's
901
  advisory. Any piece of code which should be blocked by global read lock must
902
  be designed like this:
903
  - call to wait_if_global_read_lock(). When this returns 0, no global read
904
  lock is owned; if argument abort_on_refresh was 0, none can be obtained.
905
  - job
906
  - if abort_on_refresh was 0, call to start_waiting_global_read_lock() to
907
  allow other threads to get the global read lock. I.e. removal of the
908
  protection.
909
  (Note: it's a bit like an implementation of rwlock).
910
911
  [ I am sorry to mention some SQL syntaxes below I know I shouldn't but found
912
  no better descriptive way ]
913
914
  Why does FLUSH TABLES WITH READ LOCK need to block COMMIT: because it's used
915
  to read a non-moving SHOW MASTER STATUS, and a COMMIT writes to the binary
916
  log.
917
918
  Why getting the global read lock is two steps and not one. Because FLUSH
919
  TABLES WITH READ LOCK needs to insert one other step between the two:
920
  flushing tables. So the order is
921
  1) lock_global_read_lock() (prevents any new table write locks, i.e. stalls
922
  all new updates)
923
  2) close_cached_tables() (the FLUSH TABLES), which will wait for tables
924
  currently opened and being updated to close (so it's possible that there is
925
  a moment where all new updates of server are stalled *and* FLUSH TABLES WITH
926
  READ LOCK is, too).
927
  3) make_global_read_lock_block_commit().
928
  If we have merged 1) and 3) into 1), we would have had this deadlock:
929
  imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
930
  table t.
520.1.22 by Brian Aker
Second pass of thd cleanup
931
  session1: SELECT * FROM t FOR UPDATE;
932
  session2: UPDATE t SET a=1; # blocked by row-level locks of session1
933
  session3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
934
  table instance of session2
935
  session1: COMMIT; # blocked by session3.
936
  session1 blocks session2 which blocks session3 which blocks session1: deadlock.
1 by brian
clean slate
937
938
  Note that we need to support that one thread does
939
  FLUSH TABLES WITH READ LOCK; and then COMMIT;
940
  (that's what innobackup does, for some good reason).
941
  So in this exceptional case the COMMIT should not be blocked by the FLUSH
942
  TABLES WITH READ LOCK.
943
944
****************************************************************************/
945
482 by Brian Aker
Remove uint.
946
volatile uint32_t global_read_lock=0;
947
volatile uint32_t global_read_lock_blocks_commit=0;
948
static volatile uint32_t protect_against_global_read_lock=0;
949
static volatile uint32_t waiting_for_read_lock=0;
1 by brian
clean slate
950
951
#define GOT_GLOBAL_READ_LOCK               1
952
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
953
520.1.22 by Brian Aker
Second pass of thd cleanup
954
bool lock_global_read_lock(Session *session)
1 by brian
clean slate
955
{
520.1.22 by Brian Aker
Second pass of thd cleanup
956
  if (!session->global_read_lock)
1 by brian
clean slate
957
  {
958
    const char *old_message;
959
    (void) pthread_mutex_lock(&LOCK_global_read_lock);
520.1.22 by Brian Aker
Second pass of thd cleanup
960
    old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1 by brian
clean slate
961
                                "Waiting to get readlock");
962
963
    waiting_for_read_lock++;
520.1.22 by Brian Aker
Second pass of thd cleanup
964
    while (protect_against_global_read_lock && !session->killed)
1 by brian
clean slate
965
      pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
966
    waiting_for_read_lock--;
520.1.22 by Brian Aker
Second pass of thd cleanup
967
    if (session->killed)
1 by brian
clean slate
968
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
969
      session->exit_cond(old_message);
1046.1.7 by Brian Aker
Style cleanup.
970
      return true;
1 by brian
clean slate
971
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
972
    session->global_read_lock= GOT_GLOBAL_READ_LOCK;
1 by brian
clean slate
973
    global_read_lock++;
520.1.22 by Brian Aker
Second pass of thd cleanup
974
    session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1 by brian
clean slate
975
  }
976
  /*
977
    We DON'T set global_read_lock_blocks_commit now, it will be set after
978
    tables are flushed (as the present function serves for FLUSH TABLES WITH
979
    READ LOCK only). Doing things in this order is necessary to avoid
980
    deadlocks (we must allow COMMIT until all tables are closed; we should not
981
    forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
982
    UPDATE and one does FLUSH TABLES WITH READ LOCK).
983
  */
1046.1.7 by Brian Aker
Style cleanup.
984
  return false;
1 by brian
clean slate
985
}
986
987
520.1.22 by Brian Aker
Second pass of thd cleanup
988
void unlock_global_read_lock(Session *session)
1 by brian
clean slate
989
{
482 by Brian Aker
Remove uint.
990
  uint32_t tmp;
1 by brian
clean slate
991
992
  pthread_mutex_lock(&LOCK_global_read_lock);
993
  tmp= --global_read_lock;
520.1.22 by Brian Aker
Second pass of thd cleanup
994
  if (session->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1 by brian
clean slate
995
    --global_read_lock_blocks_commit;
996
  pthread_mutex_unlock(&LOCK_global_read_lock);
997
  /* Send the signal outside the mutex to avoid a context switch */
998
  if (!tmp)
999
  {
1000
    pthread_cond_broadcast(&COND_global_read_lock);
1001
  }
520.1.22 by Brian Aker
Second pass of thd cleanup
1002
  session->global_read_lock= 0;
1 by brian
clean slate
1003
}
1004
1005
#define must_wait (global_read_lock &&                             \
1006
                   (is_not_commit ||                               \
1007
                    global_read_lock_blocks_commit))
1008
520.1.22 by Brian Aker
Second pass of thd cleanup
1009
bool wait_if_global_read_lock(Session *session, bool abort_on_refresh,
1 by brian
clean slate
1010
                              bool is_not_commit)
1011
{
1012
  const char *old_message= NULL;
1013
  bool result= 0, need_exit_cond;
1014
1015
  /*
1016
    Assert that we do not own LOCK_open. If we would own it, other
1017
    threads could not close their tables. This would make a pretty
1018
    deadlock.
1019
  */
1020
  safe_mutex_assert_not_owner(&LOCK_open);
1021
1022
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
1023
  if ((need_exit_cond= must_wait))
1024
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
1025
    if (session->global_read_lock)		// This thread had the read locks
1 by brian
clean slate
1026
    {
1027
      if (is_not_commit)
1028
        my_message(ER_CANT_UPDATE_WITH_READLOCK,
1029
                   ER(ER_CANT_UPDATE_WITH_READLOCK), MYF(0));
1030
      (void) pthread_mutex_unlock(&LOCK_global_read_lock);
1031
      /*
1032
        We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
1033
        This allowance is needed to not break existing versions of innobackup
1034
        which do a BEGIN; INSERT; FLUSH TABLES WITH READ LOCK; COMMIT.
1035
      */
1046.1.7 by Brian Aker
Style cleanup.
1036
      return is_not_commit;
1 by brian
clean slate
1037
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
1038
    old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1 by brian
clean slate
1039
				"Waiting for release of readlock");
520.1.22 by Brian Aker
Second pass of thd cleanup
1040
    while (must_wait && ! session->killed &&
1041
	   (!abort_on_refresh || session->version == refresh_version))
1 by brian
clean slate
1042
    {
1043
      (void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1044
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
1045
    if (session->killed)
1 by brian
clean slate
1046
      result=1;
1047
  }
1048
  if (!abort_on_refresh && !result)
1049
    protect_against_global_read_lock++;
1050
  /*
1051
    The following is only true in case of a global read locks (which is rare)
1052
    and if old_message is set
1053
  */
1054
  if (unlikely(need_exit_cond))
520.1.22 by Brian Aker
Second pass of thd cleanup
1055
    session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1 by brian
clean slate
1056
  else
1057
    pthread_mutex_unlock(&LOCK_global_read_lock);
1046.1.7 by Brian Aker
Style cleanup.
1058
  return result;
1 by brian
clean slate
1059
}
1060
1061
520.1.22 by Brian Aker
Second pass of thd cleanup
1062
void start_waiting_global_read_lock(Session *session)
1 by brian
clean slate
1063
{
1064
  bool tmp;
520.1.22 by Brian Aker
Second pass of thd cleanup
1065
  if (unlikely(session->global_read_lock))
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1066
    return;
1 by brian
clean slate
1067
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
1068
  tmp= (!--protect_against_global_read_lock &&
1069
        (waiting_for_read_lock || global_read_lock_blocks_commit));
1070
  (void) pthread_mutex_unlock(&LOCK_global_read_lock);
1071
  if (tmp)
1072
    pthread_cond_broadcast(&COND_global_read_lock);
51.1.27 by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE
1073
  return;
1 by brian
clean slate
1074
}
1075
1076
520.1.22 by Brian Aker
Second pass of thd cleanup
1077
bool make_global_read_lock_block_commit(Session *session)
1 by brian
clean slate
1078
{
1079
  bool error;
1080
  const char *old_message;
1081
  /*
1082
    If we didn't succeed lock_global_read_lock(), or if we already suceeded
1083
    make_global_read_lock_block_commit(), do nothing.
1084
  */
520.1.22 by Brian Aker
Second pass of thd cleanup
1085
  if (session->global_read_lock != GOT_GLOBAL_READ_LOCK)
1046.1.7 by Brian Aker
Style cleanup.
1086
    return false;
1 by brian
clean slate
1087
  pthread_mutex_lock(&LOCK_global_read_lock);
1088
  /* increment this BEFORE waiting on cond (otherwise race cond) */
1089
  global_read_lock_blocks_commit++;
520.1.22 by Brian Aker
Second pass of thd cleanup
1090
  old_message= session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1 by brian
clean slate
1091
                               "Waiting for all running commits to finish");
520.1.22 by Brian Aker
Second pass of thd cleanup
1092
  while (protect_against_global_read_lock && !session->killed)
1 by brian
clean slate
1093
    pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
520.1.22 by Brian Aker
Second pass of thd cleanup
1094
  if ((error= test(session->killed)))
1 by brian
clean slate
1095
    global_read_lock_blocks_commit--; // undo what we did
1096
  else
520.1.22 by Brian Aker
Second pass of thd cleanup
1097
    session->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1098
  session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1046.1.7 by Brian Aker
Style cleanup.
1099
  return error;
1 by brian
clean slate
1100
}
1101
1102
1103
/**
1104
  Broadcast COND_refresh and COND_global_read_lock.
1105
1106
    Due to a bug in a threading library it could happen that a signal
1107
    did not reach its target. A condition for this was that the same
1108
    condition variable was used with different mutexes in
1109
    pthread_cond_wait(). Some time ago we changed LOCK_open to
1110
    LOCK_global_read_lock in global read lock handling. So COND_refresh
1111
    was used with LOCK_open and LOCK_global_read_lock.
1112
1113
    We did now also change from COND_refresh to COND_global_read_lock
1114
    in global read lock handling. But now it is necessary to signal
1115
    both conditions at the same time.
1116
1117
  @note
1118
    When signalling COND_global_read_lock within the global read lock
1119
    handling, it is not necessary to also signal COND_refresh.
1120
*/
1121
1122
void broadcast_refresh(void)
1123
{
398.1.10 by Monty Taylor
Actually removed VOID() this time.
1124
  pthread_cond_broadcast(&COND_refresh);
1125
  pthread_cond_broadcast(&COND_global_read_lock);
1 by brian
clean slate
1126
}
1127
1128
1129
/**
1130
  @} (end of group Locking)
1131
*/