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