lock.cc 34.5 KB
Newer Older
unknown's avatar
unknown committed
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
unknown's avatar
unknown committed
2

unknown's avatar
unknown committed
3 4 5 6
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
unknown's avatar
unknown committed
7

unknown's avatar
unknown committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
unknown's avatar
unknown committed
12

unknown's avatar
unknown committed
13 14 15 16 17 18 19 20 21 22 23
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


/* locking functions for mysql */
/*
  Because of the new concurrent inserts, we must first get external locks
  before getting internal locks.  If we do it in the other order, the status
  information is not up to date when called from the lock handler.

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
  GENERAL DESCRIPTION OF LOCKING

  When not using LOCK TABLES:

  - For each SQL statement mysql_lock_tables() is called for all involved
    tables.
    - mysql_lock_tables() will call
      table_handler->external_lock(thd,locktype) for each table.
      This is followed by a call to thr_multi_lock() for all tables.

  - When statement is done, we call mysql_unlock_tables().
    This will call thr_multi_unlock() followed by
    table_handler->external_lock(thd, F_UNLCK) for each table.

  - Note that mysql_unlock_tables() may be called several times as
    MySQL in some cases can free some tables earlier than others.

  - The above is true both for normal and temporary tables.

  - Temporary non transactional tables are never passed to thr_multi_lock()
    and we never call external_lock(thd, F_UNLOCK) on these.

  When using LOCK TABLES:

  - LOCK TABLE will call mysql_lock_tables() for all tables.
    mysql_lock_tables() will call
    table_handler->external_lock(thd,locktype) for each table.
    This is followed by a call to thr_multi_lock() for all tables.

  - For each statement, we will call table_handler->start_stmt(THD)
    to inform the table handler that we are using the table.

    The tables used can only be tables used in LOCK TABLES or a
    temporary table.

  - When statement is done, we will call ha_commit_stmt(thd);

  - When calling UNLOCK TABLES we call mysql_unlock_tables() for all
    tables used in LOCK TABLES

unknown's avatar
unknown committed
64 65 66 67 68 69 70
TODO:
  Change to use my_malloc() ONLY when using LOCK TABLES command or when
  we are forced to use mysql_lock_merge.
*/

#include "mysql_priv.h"
#include <hash.h>
unknown's avatar
unknown committed
71
#include "ha_myisammrg.h"
unknown's avatar
unknown committed
72 73 74
#ifndef MASTER
#include "../srclib/myisammrg/myrg_def.h"
#else
75
#include "../storage/myisammrg/myrg_def.h"
unknown's avatar
unknown committed
76
#endif
unknown's avatar
unknown committed
77 78 79

static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
				 bool unlock, TABLE **write_locked);
80
static int lock_external(THD *thd, TABLE **table,uint count);
unknown's avatar
unknown committed
81
static int unlock_external(THD *thd, TABLE **table,uint count);
82
static void print_lock_error(int error, const char *);
unknown's avatar
unknown committed
83 84


85 86 87 88 89 90 91 92 93 94 95
/*
  Lock tables.

  SYNOPSIS
    mysql_lock_tables()
    thd                         The current thread.
    tables                      An array of pointers to the tables to lock.
    count                       The number of tables to lock.
    flags                       Options:
      MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK      Ignore a global read lock
      MYSQL_LOCK_IGNORE_FLUSH                 Ignore a flush tables.
96 97 98 99 100 101 102
      MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN        Instead of reopening altered
                                              or dropped tables by itself,
                                              mysql_lock_tables() should
                                              notify upper level and rely
                                              on caller doing this.
    need_reopen                 Out parameter, TRUE if some tables were altered
                                or deleted and should be reopened by caller.
103 104 105

  RETURN
    A lock structure pointer on success.
106
    NULL on error or if some tables should be reopen.
107 108
*/

109
/* Map the return value of thr_lock to an error from errmsg.txt */
unknown's avatar
unknown committed
110 111 112
static int thr_lock_errno_to_mysql[]=
{ 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };

113 114
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
                              uint flags, bool *need_reopen)
unknown's avatar
unknown committed
115 116 117
{
  MYSQL_LOCK *sql_lock;
  TABLE *write_lock_used;
118
  int rc;
unknown's avatar
unknown committed
119 120
  DBUG_ENTER("mysql_lock_tables");

121 122
  *need_reopen= FALSE;

unknown's avatar
unknown committed
123 124 125 126 127
  for (;;)
  {
    if (!(sql_lock = get_lock_data(thd,tables,count, 0,&write_lock_used)))
      break;

128 129
    if (global_read_lock && write_lock_used &&
        ! (flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK))
unknown's avatar
unknown committed
130 131 132 133 134
    {
      /*
	Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
	Wait until the lock is gone
      */
135
      if (wait_if_global_read_lock(thd, 1, 1))
unknown's avatar
unknown committed
136 137 138 139 140
      {
	my_free((gptr) sql_lock,MYF(0));
	sql_lock=0;
	break;
      }	
141
      if (thd->version != refresh_version)
unknown's avatar
unknown committed
142 143 144 145 146 147 148
      {
	my_free((gptr) sql_lock,MYF(0));
	goto retry;
      }
    }

    thd->proc_info="System lock";
unknown's avatar
unknown committed
149
    DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info));
150
    if (lock_external(thd, tables, count))
unknown's avatar
unknown committed
151 152 153 154 155
    {
      my_free((gptr) sql_lock,MYF(0));
      sql_lock=0;
      break;
    }
156
    thd->proc_info="Table lock";
unknown's avatar
unknown committed
157
    DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info));
unknown's avatar
unknown committed
158
    thd->locked=1;
159 160 161 162 163 164 165 166 167 168 169
    rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks,
                                                     sql_lock->lock_count,
                                                     thd->lock_id)];
    if (rc > 1)                                 /* a timeout or a deadlock */
    {
      my_error(rc, MYF(0));
      my_free((gptr) sql_lock,MYF(0));
      sql_lock= 0;
      break;
    }
    else if (rc == 1)                           /* aborted */
unknown's avatar
unknown committed
170 171
    {
      thd->some_tables_deleted=1;		// Try again
172
      sql_lock->lock_count= 0;                  // Locks are already freed
unknown's avatar
unknown committed
173
    }
174
    else if (!thd->some_tables_deleted || (flags & MYSQL_LOCK_IGNORE_FLUSH))
unknown's avatar
unknown committed
175 176 177 178
    {
      thd->locked=0;
      break;
    }
179 180 181 182 183 184 185
    else if (!thd->open_tables)
    {
      // Only using temporary tables, no need to unlock
      thd->some_tables_deleted=0;
      thd->locked=0;
      break;
    }
186
    thd->proc_info=0;
unknown's avatar
unknown committed
187 188 189 190 191 192

    /* some table was altered or deleted. reopen tables marked deleted */
    mysql_unlock_tables(thd,sql_lock);
    thd->locked=0;
retry:
    sql_lock=0;
193 194 195 196 197
    if (flags & MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN)
    {
      *need_reopen= TRUE;
      break;
    }
unknown's avatar
unknown committed
198 199 200
    if (wait_for_tables(thd))
      break;					// Couldn't open tables
  }
201
  thd->proc_info=0;
unknown's avatar
unknown committed
202 203
  if (thd->killed)
  {
unknown's avatar
SCRUM  
unknown committed
204
    thd->send_kill_message();
unknown's avatar
unknown committed
205 206 207 208 209 210
    if (sql_lock)
    {
      mysql_unlock_tables(thd,sql_lock);
      sql_lock=0;
    }
  }
unknown's avatar
unknown committed
211

212
  thd->lock_time();
unknown's avatar
unknown committed
213 214 215 216
  DBUG_RETURN (sql_lock);
}


217
static int lock_external(THD *thd, TABLE **tables, uint count)
unknown's avatar
unknown committed
218 219 220 221 222
{
  reg1 uint i;
  int lock_type,error;
  DBUG_ENTER("lock_external");

unknown's avatar
unknown committed
223
  DBUG_PRINT("info", ("count %d", count));
unknown's avatar
unknown committed
224 225
  for (i=1 ; i <= count ; i++, tables++)
  {
unknown's avatar
unknown committed
226
    DBUG_ASSERT((*tables)->reginfo.lock_type >= TL_READ);
unknown's avatar
unknown committed
227 228 229 230 231 232 233
    lock_type=F_WRLCK;				/* Lock exclusive */
    if ((*tables)->db_stat & HA_READ_ONLY ||
	((*tables)->reginfo.lock_type >= TL_READ &&
	 (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
      lock_type=F_RDLCK;
    if ((error=(*tables)->file->external_lock(thd,lock_type)))
    {
234
      print_lock_error(error, (*tables)->file->table_type());
235
      for (; i-- ; tables--)
unknown's avatar
unknown committed
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
      {
	(*tables)->file->external_lock(thd, F_UNLCK);
	(*tables)->current_lock=F_UNLCK;
      }
      DBUG_RETURN(error);
    }
    else
    {
      (*tables)->db_stat &= ~ HA_BLOCK_LOCK;
      (*tables)->current_lock= lock_type;
    }
  }
  DBUG_RETURN(0);
}


void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
{
  DBUG_ENTER("mysql_unlock_tables");
unknown's avatar
unknown committed
255 256
  if (sql_lock->lock_count)
    thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
257
  if (sql_lock->table_count)
unknown's avatar
unknown committed
258
    VOID(unlock_external(thd,sql_lock->table,sql_lock->table_count));
unknown's avatar
unknown committed
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
  my_free((gptr) sql_lock,MYF(0));
  DBUG_VOID_RETURN;
}

/*
  Unlock some of the tables locked by mysql_lock_tables
  This will work even if get_lock_data fails (next unlock will free all)
  */

void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count)
{
  MYSQL_LOCK *sql_lock;
  TABLE *write_lock_used;
  if ((sql_lock = get_lock_data(thd, table, count, 1, &write_lock_used)))
    mysql_unlock_tables(thd, sql_lock);
}


/*
** unlock all tables locked for read.
*/

void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
{
  uint i,found;
  DBUG_ENTER("mysql_unlock_read_tables");

  /* Move all write locks first */
  THR_LOCK_DATA **lock=sql_lock->locks;
  for (i=found=0 ; i < sql_lock->lock_count ; i++)
  {
    if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_READ)
    {
292
      swap_variables(THR_LOCK_DATA *, *lock, sql_lock->locks[i]);
unknown's avatar
unknown committed
293 294 295 296 297 298 299 300
      lock++;
      found++;
    }
  }
  /* unlock the read locked tables */
  if (i != found)
  {
    thr_multi_unlock(lock,i-found);
unknown's avatar
unknown committed
301
    sql_lock->lock_count= found;
unknown's avatar
unknown committed
302 303
  }

304
  /* Then do the same for the external locks */
unknown's avatar
unknown committed
305 306 307 308 309 310
  /* Move all write locked tables first */
  TABLE **table=sql_lock->table;
  for (i=found=0 ; i < sql_lock->table_count ; i++)
  {
    if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
    {
311
      swap_variables(TABLE *, *table, sql_lock->table[i]);
unknown's avatar
unknown committed
312 313 314 315 316 317 318 319
      table++;
      found++;
    }
  }
  /* Unlock all read locked tables */
  if (i != found)
  {
    VOID(unlock_external(thd,table,i-found));
unknown's avatar
unknown committed
320
    sql_lock->table_count=found;
unknown's avatar
unknown committed
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
  }
  DBUG_VOID_RETURN;
}



void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table)
{
  mysql_unlock_some_tables(thd, &table,1);
  if (locked)
  {
    reg1 uint i;
    for (i=0; i < locked->table_count; i++)
    {
      if (locked->table[i] == table)
      {
	locked->table_count--;
	bmove((char*) (locked->table+i),
	      (char*) (locked->table+i+1),
	      (locked->table_count-i)* sizeof(TABLE*));
	break;
      }
    }
    THR_LOCK_DATA **prev=locked->locks;
    for (i=0 ; i < locked->lock_count ; i++)
    {
      if (locked->locks[i]->type != TL_UNLOCK)
	*prev++ = locked->locks[i];
    }
unknown's avatar
unknown committed
350
    locked->lock_count=(uint) (prev - locked->locks);
unknown's avatar
unknown committed
351 352 353 354 355 356 357 358 359
  }
}

/* abort all other threads waiting to get lock in table */

void mysql_lock_abort(THD *thd, TABLE *table)
{
  MYSQL_LOCK *locked;
  TABLE *write_lock_used;
unknown's avatar
unknown committed
360 361
  DBUG_ENTER("mysql_lock_abort");

unknown's avatar
unknown committed
362 363 364 365 366 367
  if ((locked = get_lock_data(thd,&table,1,1,&write_lock_used)))
  {
    for (uint i=0; i < locked->lock_count; i++)
      thr_abort_locks(locked->locks[i]->lock);
    my_free((gptr) locked,MYF(0));
  }
unknown's avatar
unknown committed
368
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
369 370 371
}


unknown's avatar
unknown committed
372 373 374 375 376 377 378 379 380 381 382 383
/*
  Abort one thread / table combination

  SYNOPSIS
    mysql_lock_abort_for_thread()
    thd		Thread handler
    table	Table that should be removed from lock queue

  RETURN
    0  Table was not locked by another thread
    1  Table was locked by at least one other thread
*/
384

unknown's avatar
unknown committed
385
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
386 387 388
{
  MYSQL_LOCK *locked;
  TABLE *write_lock_used;
unknown's avatar
unknown committed
389
  bool result= FALSE;
390 391 392 393 394
  DBUG_ENTER("mysql_lock_abort_for_thread");

  if ((locked = get_lock_data(thd,&table,1,1,&write_lock_used)))
  {
    for (uint i=0; i < locked->lock_count; i++)
unknown's avatar
unknown committed
395
    {
unknown's avatar
unknown committed
396 397 398
      if (thr_abort_locks_for_thread(locked->locks[i]->lock,
                                     table->in_use->real_id))
        result= TRUE;
unknown's avatar
unknown committed
399
    }
400 401
    my_free((gptr) locked,MYF(0));
  }
unknown's avatar
unknown committed
402
  DBUG_RETURN(result);
403 404 405
}


unknown's avatar
unknown committed
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
{
  MYSQL_LOCK *sql_lock;
  DBUG_ENTER("mysql_lock_merge");
  if (!(sql_lock= (MYSQL_LOCK*)
	my_malloc(sizeof(*sql_lock)+
		  sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+
		  sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME))))
    DBUG_RETURN(0);				// Fatal error
  sql_lock->lock_count=a->lock_count+b->lock_count;
  sql_lock->table_count=a->table_count+b->table_count;
  sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
  sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count);
  memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
  memcpy(sql_lock->locks+a->lock_count,b->locks,
	 b->lock_count*sizeof(*b->locks));
  memcpy(sql_lock->table,a->table,a->table_count*sizeof(*a->table));
  memcpy(sql_lock->table+a->table_count,b->table,
	 b->table_count*sizeof(*b->table));
  my_free((gptr) a,MYF(0));
  my_free((gptr) b,MYF(0));
  DBUG_RETURN(sql_lock);
}


431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
/*
  Find duplicate lock in tables.

  SYNOPSIS
    mysql_lock_have_duplicate()
    thd                         The current thread.
    needle                      The table to check for duplicate lock.
    haystack                    The list of tables to search for the dup lock.

  NOTE
    This is mainly meant for MERGE tables in INSERT ... SELECT
    situations. The 'real', underlying tables can be found only after
    the table is opened. The easier way is to check this after the
    tables are locked.

  RETURN
    1           A table from 'tables' matches a lock on 'table'.
    0           No duplicate lock is present.
    -1          Error.
*/

TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
                                      TABLE_LIST *haystack)
{
  uint                  count;
  uint                  dup_pos;
  TABLE                 *write_lock_used; /* dummy */
  TABLE                 **tables1;
  TABLE                 **tables2;
  TABLE                 **table_ptr;
  TABLE_LIST            *tlist_ptr;
  MYSQL_LOCK            *sql_lock1;
  MYSQL_LOCK            *sql_lock2;
  THR_LOCK_DATA         **lock_data1;
  THR_LOCK_DATA         **end_data1;
  THR_LOCK_DATA         **lock_data2;
  THR_LOCK_DATA         **end_data2;
  THR_LOCK              *lock1;
  DBUG_ENTER("mysql_lock_have_duplicate");

  /* Table may not be defined for derived or view tables. */
  if (! needle->table)
    DBUG_RETURN(NULL);

  /* Get lock(s) for needle. */
  tables1= &needle->table;
  if (! (sql_lock1= get_lock_data(thd, tables1, 1, 1, &write_lock_used)))
    goto err0;

  /* Count real tables in list. */
  count=0;
  for (tlist_ptr = haystack; tlist_ptr; tlist_ptr= tlist_ptr->next_global)
    if (! tlist_ptr->placeholder() && ! tlist_ptr->schema_table)
      count++;
  /* Allocate a table array. */
  if (! (tables2= (TABLE**) sql_alloc(sizeof(TABLE*) * count)))
    goto err1;
  table_ptr= tables2;
  /* Assign table pointers. */
  for (tlist_ptr = haystack; tlist_ptr; tlist_ptr= tlist_ptr->next_global)
    if (! tlist_ptr->placeholder() && ! tlist_ptr->schema_table)
      *(table_ptr++)= tlist_ptr->table;
  /* Get lock(s) for haystack. */
  if (! (sql_lock2= get_lock_data(thd, tables2, count, 1, &write_lock_used)))
    goto err1;

  /* Initialize duplicate position to an impossible value. */
  dup_pos= UINT_MAX;
  /*
    Find a duplicate lock.
    In case of merge tables, sql_lock1 can have more than 1 lock.
  */
  for (lock_data1= sql_lock1->locks,
         end_data1= lock_data1 + sql_lock1->lock_count;
       lock_data1 < end_data1;
       lock_data1++)
  {
    lock1= (*lock_data1)->lock;
    for (lock_data2= sql_lock2->locks,
           end_data2= lock_data2 + sql_lock2->lock_count;
         lock_data2 < end_data2;
         lock_data2++)
    {
      if ((*lock_data2)->lock == lock1)
      {
        DBUG_PRINT("ingo", ("duplicate lock found"));
        /* Change duplicate position to the real value. */
        dup_pos= lock_data2 - sql_lock2->locks;
        goto end;
      }
    }
  }

 end:
  tlist_ptr= NULL; /* In case that no duplicate was found. */
  if (dup_pos != UINT_MAX)
  {
    /* Duplicate found. Search the matching TABLE_LIST object. */
    count= 0;
    for (tlist_ptr = haystack; tlist_ptr; tlist_ptr= tlist_ptr->next_global)
    {
      if (! tlist_ptr->placeholder() && ! tlist_ptr->schema_table)
      {
        count+= tlist_ptr->table->file->lock_count();
        if (count > dup_pos)
          break;
      }
    }
  }
  my_free((gptr) sql_lock2, MYF(0));
  my_free((gptr) sql_lock1, MYF(0));
  DBUG_RETURN(tlist_ptr);

 err1:
  my_free((gptr) sql_lock1, MYF(0));
 err0:
  /* This non-null but special value indicates error, if caller cares. */
  DBUG_RETURN(needle);
}


unknown's avatar
unknown committed
552 553 554 555 556 557 558 559
	/* unlock a set of external */

static int unlock_external(THD *thd, TABLE **table,uint count)
{
  int error,error_code;
  DBUG_ENTER("unlock_external");

  error_code=0;
560
  do
unknown's avatar
unknown committed
561 562 563 564 565
  {
    if ((*table)->current_lock != F_UNLCK)
    {
      (*table)->current_lock = F_UNLCK;
      if ((error=(*table)->file->external_lock(thd, F_UNLCK)))
566
      {
unknown's avatar
unknown committed
567
	error_code=error;
568 569
	print_lock_error(error_code, (*table)->file->table_type());
      }
unknown's avatar
unknown committed
570
    }
571 572
    table++;
  } while (--count);
unknown's avatar
unknown committed
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
  DBUG_RETURN(error_code);
}


/*
** Get lock structures from table structs and initialize locks
*/


static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
				 bool get_old_locks, TABLE **write_lock_used)
{
  uint i,tables,lock_count;
  MYSQL_LOCK *sql_lock;
  THR_LOCK_DATA **locks;
  TABLE **to;
unknown's avatar
unknown committed
589
  DBUG_ENTER("get_lock_data");
590

unknown's avatar
unknown committed
591
  DBUG_PRINT("info", ("count %d", count));
unknown's avatar
unknown committed
592 593 594
  *write_lock_used=0;
  for (i=tables=lock_count=0 ; i < count ; i++)
  {
595
    if (table_ptr[i]->s->tmp_table != TMP_TABLE)
unknown's avatar
unknown committed
596 597 598 599
    {
      tables+=table_ptr[i]->file->lock_count();
      lock_count++;
    }
600 601 602 603 604 605 606 607 608
    /*
      To be able to open and lock for reading system tables like 'mysql.proc',
      when we already have some tables opened and locked, and avoid deadlocks
      we have to disallow write-locking of these tables with any other tables.
    */
    if (table_ptr[i]->s->system_table &&
        table_ptr[i]->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE &&
        count != 1)
    {
unknown's avatar
unknown committed
609 610
      my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0), table_ptr[i]->s->db.str,
               table_ptr[i]->s->table_name.str);
unknown's avatar
unknown committed
611
      DBUG_RETURN(0);
612
    }
unknown's avatar
unknown committed
613 614 615 616 617 618
  }

  if (!(sql_lock= (MYSQL_LOCK*)
	my_malloc(sizeof(*sql_lock)+
		  sizeof(THR_LOCK_DATA*)*tables+sizeof(table_ptr)*lock_count,
		  MYF(0))))
unknown's avatar
unknown committed
619
    DBUG_RETURN(0);
unknown's avatar
unknown committed
620 621 622 623
  locks=sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
  to=sql_lock->table=(TABLE**) (locks+tables);
  sql_lock->table_count=lock_count;
  sql_lock->lock_count=tables;
unknown's avatar
unknown committed
624 625
  DBUG_PRINT("info", ("sql_lock->table_count %d sql_lock->lock_count %d",
                      sql_lock->table_count, sql_lock->lock_count));
unknown's avatar
unknown committed
626 627 628 629

  for (i=0 ; i < count ; i++)
  {
    TABLE *table;
630
    if ((table=table_ptr[i])->s->tmp_table == TMP_TABLE)
unknown's avatar
unknown committed
631 632 633 634 635 636 637 638
      continue;
    *to++=table;
    enum thr_lock_type lock_type= table->reginfo.lock_type;
    if (lock_type >= TL_WRITE_ALLOW_WRITE)
    {
      *write_lock_used=table;
      if (table->db_stat & HA_READ_ONLY)
      {
639
	my_error(ER_OPEN_AS_READONLY, MYF(0), table->alias);
unknown's avatar
unknown committed
640
	my_free((gptr) sql_lock,MYF(0));
unknown's avatar
unknown committed
641
	DBUG_RETURN(0);
unknown's avatar
unknown committed
642 643
      }
    }
unknown's avatar
unknown committed
644
    THR_LOCK_DATA **org_locks = locks;
unknown's avatar
unknown committed
645 646
    locks=table->file->store_lock(thd, locks, get_old_locks ? TL_IGNORE :
				  lock_type);
unknown's avatar
unknown committed
647 648 649
    if (locks)
      for ( ; org_locks != locks ; org_locks++)
	(*org_locks)->debug_print_param= (void *) table;
unknown's avatar
unknown committed
650
  }
unknown's avatar
unknown committed
651
  DBUG_RETURN(sql_lock);
unknown's avatar
unknown committed
652
}
653

654

655
/*****************************************************************************
656 657
  Lock table based on the name.
  This is used when we need total access to a closed, not open table
658 659
*****************************************************************************/

660 661
/*
  Lock and wait for the named lock.
662 663 664 665 666 667 668 669 670 671 672 673 674

  SYNOPSIS
    lock_and_wait_for_table_name()
    thd			Thread handler
    table_list		Lock first table in this list


  NOTES
    Works together with global read lock.

  RETURN
    0	ok
    1	error
675 676 677 678 679 680 681 682
*/

int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list)
{
  int lock_retcode;
  int error= -1;
  DBUG_ENTER("lock_and_wait_for_table_name");

683
  if (wait_if_global_read_lock(thd, 0, 1))
684 685 686 687 688 689 690 691 692 693 694 695 696
    DBUG_RETURN(1);
  VOID(pthread_mutex_lock(&LOCK_open));
  if ((lock_retcode = lock_table_name(thd, table_list)) < 0)
    goto end;
  if (lock_retcode && wait_for_locked_table_names(thd, table_list))
  {
    unlock_table_name(thd, table_list);
    goto end;
  }
  error=0;

end:
  pthread_mutex_unlock(&LOCK_open);
unknown's avatar
unknown committed
697
  start_waiting_global_read_lock(thd);
698 699 700 701
  DBUG_RETURN(error);
}


702 703
/*
  Put a not open table with an old refresh version in the table cache.
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725

  SYNPOSIS
    lock_table_name()
    thd			Thread handler
    table_list		Lock first table in this list

  WARNING
    If you are going to update the table, you should use
    lock_and_wait_for_table_name instead of this function as this works
    together with 'FLUSH TABLES WITH READ LOCK'

  NOTES
    This will force any other threads that uses the table to release it
    as soon as possible.

  REQUIREMENTS
    One must have a lock on LOCK_open !

  RETURN:
    < 0 error
    == 0 table locked
    > 0  table locked, but someone is using it
726 727 728 729 730 731
*/

int lock_table_name(THD *thd, TABLE_LIST *table_list)
{
  TABLE *table;
  char  key[MAX_DBKEY_LENGTH];
unknown's avatar
unknown committed
732
  char *db= table_list->db;
733
  uint  key_length;
unknown's avatar
unknown committed
734
  DBUG_ENTER("lock_table_name");
735
  DBUG_PRINT("enter",("db: %s  name: %s", db, table_list->table_name));
736

unknown's avatar
unknown committed
737
  key_length= create_table_def_key(thd, key, table_list, 0);
738

739 740 741 742
  /* Only insert the table if we haven't insert it already */
  for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
       table ;
       table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
unknown's avatar
unknown committed
743
  {
744
    if (table->in_use == thd)
unknown's avatar
unknown committed
745 746 747 748
    {
      DBUG_PRINT("info", ("Table is in use"));
      table->s->version= 0;                  // Ensure no one can use this
      table->locked_by_name= 1;
unknown's avatar
unknown committed
749
      DBUG_RETURN(0);
unknown's avatar
unknown committed
750 751
    }
  }
unknown's avatar
unknown committed
752 753 754 755 756
  /*
    Create a table entry with the right key and with an old refresh version
    Note that we must use my_malloc() here as this is freed by the table
    cache
  */
unknown's avatar
unknown committed
757 758
  if (!(table= (TABLE*) my_malloc(sizeof(*table)+ sizeof(TABLE_SHARE)+
                                  key_length, MYF(MY_WME | MY_ZEROFILL))))
unknown's avatar
unknown committed
759
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
760 761 762 763 764 765
  table->s= (TABLE_SHARE*) (table+1);
  memcpy((table->s->table_cache_key.str= (char*) (table->s+1)), key,
         key_length);
  table->s->table_cache_key.length= key_length;
  table->s->tmp_table= INTERNAL_TMP_TABLE;  // for intern_close_table
  table->in_use= thd;
unknown's avatar
unknown committed
766
  table->locked_by_name=1;
767 768
  table_list->table=table;

unknown's avatar
SCRUM  
unknown committed
769
  if (my_hash_insert(&open_cache, (byte*) table))
770 771
  {
    my_free((gptr) table,MYF(0));
unknown's avatar
unknown committed
772
    DBUG_RETURN(-1);
773
  }
unknown's avatar
unknown committed
774
  
unknown's avatar
unknown committed
775
  /* Return 1 if table is in use */
unknown's avatar
unknown committed
776 777
  DBUG_RETURN(test(remove_table_from_cache(thd, db, table_list->table_name,
                                           RTFC_NO_FLAG)));
778 779
}

780

781 782 783
void unlock_table_name(THD *thd, TABLE_LIST *table_list)
{
  if (table_list->table)
unknown's avatar
unknown committed
784
  {
unknown's avatar
unknown committed
785
    hash_delete(&open_cache, (byte*) table_list->table);
unknown's avatar
unknown committed
786 787
    (void) pthread_cond_broadcast(&COND_refresh);
  }
788 789
}

790

791 792
static bool locked_named_table(THD *thd, TABLE_LIST *table_list)
{
unknown's avatar
VIEW  
unknown committed
793
  for (; table_list ; table_list=table_list->next_local)
794
  {
unknown's avatar
unknown committed
795 796 797 798 799 800 801 802 803 804 805
    TABLE *table= table_list->table;
    if (table)
    {
      TABLE *save_next= table->next;
      bool result;
      table->next= 0;
      result= table_is_used(table_list->table, 0);
      table->next= save_next;
      if (result)
        return 1;
    }
806 807 808 809 810 811 812 813
  }
  return 0;					// All tables are locked
}


bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list)
{
  bool result=0;
unknown's avatar
unknown committed
814
  DBUG_ENTER("wait_for_locked_table_names");
unknown's avatar
unknown committed
815

816
  safe_mutex_assert_owner(&LOCK_open);
817 818 819 820 821 822 823 824

  while (locked_named_table(thd,table_list))
  {
    if (thd->killed)
    {
      result=1;
      break;
    }
unknown's avatar
unknown committed
825
    wait_for_condition(thd, &LOCK_open, &COND_refresh);
unknown's avatar
unknown committed
826
    pthread_mutex_lock(&LOCK_open);
827
  }
unknown's avatar
unknown committed
828
  DBUG_RETURN(result);
829
}
830

831 832 833 834 835 836 837 838 839 840

/*
  Lock all tables in list with a name lock

  SYNOPSIS
    lock_table_names()
    thd			Thread handle
    table_list		Names of tables to lock

  NOTES
841 842 843 844
    If you are just locking one table, you should use
    lock_and_wait_for_table_name().

  REQUIREMENTS
845 846 847 848 849 850 851 852 853 854 855 856
    One must have a lock on LOCK_open when calling this

  RETURN
    0	ok
    1	Fatal error (end of memory ?)
*/

bool lock_table_names(THD *thd, TABLE_LIST *table_list)
{
  bool got_all_locks=1;
  TABLE_LIST *lock_table;

unknown's avatar
VIEW  
unknown committed
857
  for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
  {
    int got_lock;
    if ((got_lock=lock_table_name(thd,lock_table)) < 0)
      goto end;					// Fatal error
    if (got_lock)
      got_all_locks=0;				// Someone is using table
  }

  /* If some table was in use, wait until we got the lock */
  if (!got_all_locks && wait_for_locked_table_names(thd, table_list))
    goto end;
  return 0;

end:
  unlock_table_names(thd, table_list, lock_table);
  return 1;
}


/*
  Unlock all tables in list with a name lock

  SYNOPSIS
    unlock_table_names()
    thd			Thread handle
    table_list		Names of tables to unlock
    last_table		Don't unlock any tables after this one.
			(default 0, which will unlock all tables)

  NOTES
    One must have a lock on LOCK_open when calling this
    This function will send a COND_refresh signal to inform other threads
    that the name locks are removed

  RETURN
    0	ok
    1	Fatal error (end of memory ?)
*/

void unlock_table_names(THD *thd, TABLE_LIST *table_list,
			TABLE_LIST *last_table)
{
unknown's avatar
VIEW  
unknown committed
900 901 902
  for (TABLE_LIST *table= table_list;
       table != last_table;
       table= table->next_local)
903 904 905 906 907
    unlock_table_name(thd,table);
  pthread_cond_broadcast(&COND_refresh);
}


908
static void print_lock_error(int error, const char *table)
909 910 911 912 913 914 915 916 917 918 919
{
  int textno;
  DBUG_ENTER("print_lock_error");

  switch (error) {
  case HA_ERR_LOCK_WAIT_TIMEOUT:
    textno=ER_LOCK_WAIT_TIMEOUT;
    break;
  case HA_ERR_READ_ONLY_TRANSACTION:
    textno=ER_READ_ONLY_TRANSACTION;
    break;
920 921 922
  case HA_ERR_LOCK_DEADLOCK:
    textno=ER_LOCK_DEADLOCK;
    break;
923 924 925
  case HA_ERR_WRONG_COMMAND:
    textno=ER_ILLEGAL_HA;
    break;
926 927 928 929
  default:
    textno=ER_CANT_LOCK;
    break;
  }
930 931 932 933 934 935

  if ( textno == ER_ILLEGAL_HA )
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), table);
  else
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error);

936 937 938
  DBUG_VOID_RETURN;
}

939 940 941 942

/****************************************************************************
  Handling of global read locks

943 944 945 946
  Taking the global read lock is TWO steps (2nd step is optional; without
  it, COMMIT of existing transactions will be allowed):
  lock_global_read_lock() THEN make_global_read_lock_block_commit().

947 948
  The global locks are handled through the global variables:
  global_read_lock
949 950
    count of threads which have the global read lock (i.e. have completed at
    least the first step above)
951
  global_read_lock_blocks_commit
952
    count of threads which have the global read lock and block
953
    commits (i.e. are in or have completed the second step above)
954 955
  waiting_for_read_lock
    count of threads which want to take a global read lock but cannot
956
  protect_against_global_read_lock
957 958
    count of threads which have set protection against global read lock.

unknown's avatar
unknown committed
959 960
  access to them is protected with a mutex LOCK_global_read_lock

961 962 963 964 965 966 967
  (XXX: one should never take LOCK_open if LOCK_global_read_lock is
  taken, otherwise a deadlock may occur. Other mutexes could be a
  problem too - grep the code for global_read_lock if you want to use
  any other mutex here) Also one must not hold LOCK_open when calling
  wait_if_global_read_lock(). When the thread with the global read lock
  tries to close its tables, it needs to take LOCK_open in
  close_thread_table().
unknown's avatar
unknown committed
968

969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
  How blocking of threads by global read lock is achieved: that's
  advisory. Any piece of code which should be blocked by global read lock must
  be designed like this:
  - call to wait_if_global_read_lock(). When this returns 0, no global read
  lock is owned; if argument abort_on_refresh was 0, none can be obtained.
  - job
  - if abort_on_refresh was 0, call to start_waiting_global_read_lock() to
  allow other threads to get the global read lock. I.e. removal of the
  protection.
  (Note: it's a bit like an implementation of rwlock).

  [ I am sorry to mention some SQL syntaxes below I know I shouldn't but found
  no better descriptive way ]

  Why does FLUSH TABLES WITH READ LOCK need to block COMMIT: because it's used
  to read a non-moving SHOW MASTER STATUS, and a COMMIT writes to the binary
  log.

  Why getting the global read lock is two steps and not one. Because FLUSH
  TABLES WITH READ LOCK needs to insert one other step between the two:
  flushing tables. So the order is
  1) lock_global_read_lock() (prevents any new table write locks, i.e. stalls
  all new updates)
  2) close_cached_tables() (the FLUSH TABLES), which will wait for tables
  currently opened and being updated to close (so it's possible that there is
  a moment where all new updates of server are stalled *and* FLUSH TABLES WITH
  READ LOCK is, too).
  3) make_global_read_lock_block_commit().
  If we have merged 1) and 3) into 1), we would have had this deadlock:
  imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
  table t.
  thd1: SELECT * FROM t FOR UPDATE;
  thd2: UPDATE t SET a=1; # blocked by row-level locks of thd1
  thd3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
  table instance of thd2
  thd1: COMMIT; # blocked by thd3.
  thd1 blocks thd2 which blocks thd3 which blocks thd1: deadlock.
unknown's avatar
unknown committed
1006

1007 1008 1009 1010 1011 1012
  Note that we need to support that one thread does
  FLUSH TABLES WITH READ LOCK; and then COMMIT;
  (that's what innobackup does, for some good reason).
  So in this exceptional case the COMMIT should not be blocked by the FLUSH
  TABLES WITH READ LOCK.

1013 1014 1015
****************************************************************************/

volatile uint global_read_lock=0;
1016
volatile uint global_read_lock_blocks_commit=0;
1017 1018 1019
static volatile uint protect_against_global_read_lock=0;
static volatile uint waiting_for_read_lock=0;

1020 1021 1022
#define GOT_GLOBAL_READ_LOCK               1
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2

1023 1024 1025 1026 1027 1028
bool lock_global_read_lock(THD *thd)
{
  DBUG_ENTER("lock_global_read_lock");

  if (!thd->global_read_lock)
  {
1029 1030
    (void) pthread_mutex_lock(&LOCK_global_read_lock);
    const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_global_read_lock,
1031
					    "Waiting to get readlock");
unknown's avatar
unknown committed
1032 1033 1034 1035
    DBUG_PRINT("info",
	       ("waiting_for: %d  protect_against: %d",
		waiting_for_read_lock, protect_against_global_read_lock));

1036 1037
    waiting_for_read_lock++;
    while (protect_against_global_read_lock && !thd->killed)
1038
      pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock);
1039 1040 1041
    waiting_for_read_lock--;
    if (thd->killed)
    {
unknown's avatar
unknown committed
1042
      thd->exit_cond(old_message);
1043 1044
      DBUG_RETURN(1);
    }
1045
    thd->global_read_lock= GOT_GLOBAL_READ_LOCK;
1046
    global_read_lock++;
unknown's avatar
unknown committed
1047
    thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1048
  }
1049 1050 1051 1052 1053 1054 1055 1056
  /*
    We DON'T set global_read_lock_blocks_commit now, it will be set after
    tables are flushed (as the present function serves for FLUSH TABLES WITH
    READ LOCK only). Doing things in this order is necessary to avoid
    deadlocks (we must allow COMMIT until all tables are closed; we should not
    forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
    UPDATE and one does FLUSH TABLES WITH READ LOCK).
  */
1057 1058 1059 1060 1061 1062
  DBUG_RETURN(0);
}

void unlock_global_read_lock(THD *thd)
{
  uint tmp;
1063
  pthread_mutex_lock(&LOCK_global_read_lock);
1064
  tmp= --global_read_lock;
1065 1066
  if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
    --global_read_lock_blocks_commit;
1067
  pthread_mutex_unlock(&LOCK_global_read_lock);
1068 1069 1070
  /* Send the signal outside the mutex to avoid a context switch */
  if (!tmp)
    pthread_cond_broadcast(&COND_refresh);
1071
  thd->global_read_lock= 0;
1072 1073
}

1074 1075 1076
#define must_wait (global_read_lock &&                             \
                   (is_not_commit ||                               \
                    global_read_lock_blocks_commit))
1077

1078 1079
bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
                              bool is_not_commit)
1080 1081
{
  const char *old_message;
unknown's avatar
unknown committed
1082
  bool result= 0, need_exit_cond;
1083 1084
  DBUG_ENTER("wait_if_global_read_lock");

unknown's avatar
unknown committed
1085
  LINT_INIT(old_message);
1086 1087 1088 1089 1090 1091 1092
  /*
    Assert that we do not own LOCK_open. If we would own it, other
    threads could not close their tables. This would make a pretty
    deadlock.
  */
  safe_mutex_assert_not_owner(&LOCK_open);

1093
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
1094
  if ((need_exit_cond= must_wait))
1095 1096 1097
  {
    if (thd->global_read_lock)		// This thread had the read locks
    {
1098
      if (is_not_commit)
unknown's avatar
merge  
unknown committed
1099 1100
        my_message(ER_CANT_UPDATE_WITH_READLOCK,
                   ER(ER_CANT_UPDATE_WITH_READLOCK), MYF(0));
1101
      (void) pthread_mutex_unlock(&LOCK_global_read_lock);
1102 1103 1104 1105 1106 1107
      /*
        We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
        This allowance is needed to not break existing versions of innobackup
        which do a BEGIN; INSERT; FLUSH TABLES WITH READ LOCK; COMMIT.
      */
      DBUG_RETURN(is_not_commit);
unknown's avatar
unknown committed
1108
    }
1109
    old_message=thd->enter_cond(&COND_refresh, &LOCK_global_read_lock,
1110
				"Waiting for release of readlock");
1111
    while (must_wait && ! thd->killed &&
1112
	   (!abort_on_refresh || thd->version == refresh_version))
1113
      (void) pthread_cond_wait(&COND_refresh,&LOCK_global_read_lock);
1114 1115 1116 1117 1118
    if (thd->killed)
      result=1;
  }
  if (!abort_on_refresh && !result)
    protect_against_global_read_lock++;
1119 1120 1121 1122
  /*
    The following is only true in case of a global read locks (which is rare)
    and if old_message is set
  */
unknown's avatar
unknown committed
1123 1124
  if (unlikely(need_exit_cond))
    thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
unknown's avatar
unknown committed
1125
  else
1126
    pthread_mutex_unlock(&LOCK_global_read_lock);
1127 1128 1129 1130 1131 1132 1133
  DBUG_RETURN(result);
}


void start_waiting_global_read_lock(THD *thd)
{
  bool tmp;
unknown's avatar
unknown committed
1134
  DBUG_ENTER("start_waiting_global_read_lock");
1135 1136
  if (unlikely(thd->global_read_lock))
    DBUG_VOID_RETURN;
1137
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
1138 1139
  tmp= (!--protect_against_global_read_lock &&
        (waiting_for_read_lock || global_read_lock_blocks_commit));
1140
  (void) pthread_mutex_unlock(&LOCK_global_read_lock);
1141 1142
  if (tmp)
    pthread_cond_broadcast(&COND_refresh);
unknown's avatar
unknown committed
1143
  DBUG_VOID_RETURN;
1144
}
1145 1146


1147
bool make_global_read_lock_block_commit(THD *thd)
1148
{
1149 1150 1151
  bool error;
  const char *old_message;
  DBUG_ENTER("make_global_read_lock_block_commit");
1152 1153 1154 1155 1156
  /*
    If we didn't succeed lock_global_read_lock(), or if we already suceeded
    make_global_read_lock_block_commit(), do nothing.
  */
  if (thd->global_read_lock != GOT_GLOBAL_READ_LOCK)
1157
    DBUG_RETURN(0);
1158
  pthread_mutex_lock(&LOCK_global_read_lock);
1159 1160
  /* increment this BEFORE waiting on cond (otherwise race cond) */
  global_read_lock_blocks_commit++;
1161 1162 1163
  /* For testing we set up some blocking, to see if we can be killed */
  DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop",
                  protect_against_global_read_lock++;);
1164
  old_message= thd->enter_cond(&COND_refresh, &LOCK_global_read_lock,
1165 1166
                               "Waiting for all running commits to finish");
  while (protect_against_global_read_lock && !thd->killed)
1167
    pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock);
1168 1169
  DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop",
                  protect_against_global_read_lock--;);
unknown's avatar
unknown committed
1170
  if ((error= test(thd->killed)))
1171 1172 1173
    global_read_lock_blocks_commit--; // undo what we did
  else
    thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
unknown's avatar
unknown committed
1174
  thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1175
  DBUG_RETURN(error);
1176
}