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