Drizzled Public API Documentation

global.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 Brian Aker
3  Copyright (C) 2000-2006 MySQL AB
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; version 2 of the License.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
17 
18 
79 #include <config.h>
80 
81 #include <fcntl.h>
82 
83 #include <drizzled/error.h>
84 #include <drizzled/thr_lock.h>
85 #include <drizzled/session.h>
86 #include <drizzled/session/times.h>
87 #include <drizzled/sql_base.h>
88 #include <drizzled/lock.h>
89 #include <drizzled/pthread_globals.h>
90 #include <drizzled/internal/my_sys.h>
91 #include <drizzled/pthread_globals.h>
92 #include <drizzled/plugin/storage_engine.h>
93 #include <drizzled/util/test.h>
94 #include <drizzled/open_tables_state.h>
95 #include <drizzled/table/cache.h>
96 
97 #include <set>
98 #include <vector>
99 #include <algorithm>
100 #include <functional>
101 
102 #include <boost/thread/shared_mutex.hpp>
103 #include <boost/thread/condition_variable.hpp>
104 
105 using namespace std;
106 
107 namespace drizzled
108 {
109 
110 static boost::mutex LOCK_global_read_lock;
111 static boost::condition_variable_any COND_global_read_lock;
112 
118 static void print_lock_error(int error, const char *);
119 
120 /*
121  Lock tables.
122 
123  SYNOPSIS
124  lockTables()
125  tables An array of pointers to the tables to lock.
126  count The number of tables to lock.
127  flags Options:
128  DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
129  DRIZZLE_LOCK_IGNORE_FLUSH Ignore a flush tables.
130  DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN Instead of reopening altered
131  or dropped tables by itself,
132  lockTables() should
133  notify upper level and rely
134  on caller doing this.
135 
136  RETURN
137  A lock structure pointer on success.
138  NULL on error or if some tables should be reopen.
139 */
140 
141 /* Map the return value of thr_lock to an error from errmsg.txt */
142 static drizzled::error_t thr_lock_errno_to_mysql[]=
143 { EE_OK, EE_ERROR_FIRST, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };
144 
145 
167 {
168  lock->reset();
169  delete lock;
170  lock= NULL;
171 }
172 
173 DrizzleLock *Session::lockTables(Table **tables, uint32_t count, uint32_t flags)
174 {
175  DrizzleLock *sql_lock;
176  Table *write_lock_used;
177  vector<plugin::StorageEngine *> involved_engines;
178 
179  do
180  {
181  if (! (sql_lock= get_lock_data(tables, count, true, &write_lock_used)))
182  break;
183 
184  if (global_read_lock && write_lock_used and (not (flags & DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK)))
185  {
186  /*
187  Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
188  Wait until the lock is gone
189  */
190  if (wait_if_global_read_lock(1, 1))
191  {
192  /* Clear the lock type of all lock data to avoid reusage. */
193  reset_lock_data_and_free(sql_lock);
194  break;
195  }
196 
197  if (open_tables.version != g_refresh_version)
198  {
199  /* Clear the lock type of all lock data to avoid reusage. */
200  reset_lock_data_and_free(sql_lock);
201  break;
202  }
203  }
204 
205  set_proc_info("Notify start statement");
206  /*
207  * Here, we advise all storage engines involved in the
208  * statement that we are starting a new statement
209  */
210  if (sql_lock->sizeTable())
211  {
212  size_t num_tables= sql_lock->sizeTable();
213  plugin::StorageEngine *engine;
214  std::set<size_t> involved_slots;
215 
216  for (size_t x= 1; x <= num_tables; x++, tables++)
217  {
218  engine= (*tables)->cursor->getEngine();
219 
220  if (involved_slots.count(engine->getId()) > 0)
221  continue; /* already added to involved engines */
222 
223  involved_engines.push_back(engine);
224  involved_slots.insert(engine->getId());
225  }
226 
227  for_each(involved_engines.begin(),
228  involved_engines.end(),
229  bind2nd(mem_fun(&plugin::StorageEngine::startStatement), this));
230  }
231 
232  set_proc_info("External lock");
233  /*
234  * Here, the call to lock_external() informs the
235  * all engines for all tables used in this statement
236  * of the type of lock that Drizzle intends to take on a
237  * specific table.
238  */
239  if (sql_lock->sizeTable() && lock_external(sql_lock->getTable(), sql_lock->sizeTable()))
240  {
241  /* Clear the lock type of all lock data to avoid reusage. */
242  reset_lock_data_and_free(sql_lock);
243  break;
244  }
245  set_proc_info("Table lock");
246  /* Copy the lock data array. thr_multi_lock() reorders its contens. */
247  memcpy(sql_lock->getLocks() + sql_lock->sizeLock(),
248  sql_lock->getLocks(),
249  sql_lock->sizeLock() * sizeof(*sql_lock->getLocks()));
250 
251  /* Lock on the copied half of the lock data array. */
252  drizzled::error_t rc;
253  rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(*this,
254  sql_lock->getLocks() +
255  sql_lock->sizeLock(),
256  sql_lock->sizeLock(),
257  this->lock_id)];
258  if (rc) /* a timeout or a deadlock */
259  {
260  if (sql_lock->sizeTable())
261  unlock_external(sql_lock->getTable(), sql_lock->sizeTable());
262  reset_lock_data_and_free(sql_lock);
263  my_error(rc, MYF(0));
264  }
265  } while(0);
266 
267  set_proc_info(0);
268  if (getKilled())
269  {
270  send_kill_message();
271  if (sql_lock)
272  {
273  unlockTables(sql_lock);
274  sql_lock= NULL;
275  }
276  }
277 
278  times.set_time_after_lock();
279 
280  return sql_lock;
281 }
282 
283 
284 int Session::lock_external(Table **tables, uint32_t count)
285 {
286  int lock_type,error;
287  for (uint32_t i= 1 ; i <= count ; i++, tables++)
288  {
289  assert((*tables)->reginfo.lock_type >= TL_READ);
290  lock_type=F_WRLCK; /* Lock exclusive */
291  if ((*tables)->db_stat & HA_READ_ONLY ||
292  ((*tables)->reginfo.lock_type >= TL_READ &&
293  (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
294  lock_type=F_RDLCK;
295 
296  if ((error=(*tables)->cursor->ha_external_lock(this,lock_type)))
297  {
298  print_lock_error(error, (*tables)->cursor->getEngine()->getName().c_str());
299  while (--i)
300  {
301  tables--;
302  (*tables)->cursor->ha_external_lock(this, F_UNLCK);
303  (*tables)->current_lock=F_UNLCK;
304  }
305  return error;
306  }
307  else
308  {
309  (*tables)->db_stat &= ~ HA_BLOCK_LOCK;
310  (*tables)->current_lock= lock_type;
311  }
312  }
313  return 0;
314 }
315 
316 
317 void Session::unlockTables(DrizzleLock *sql_lock)
318 {
319  if (sql_lock->sizeLock())
320  sql_lock->unlock(sql_lock->sizeLock());
321  if (sql_lock->sizeTable())
322  unlock_external(sql_lock->getTable(), sql_lock->sizeTable());
323  delete sql_lock;
324 }
325 
332 void Session::unlockSomeTables(Table **table, uint32_t count)
333 {
334  DrizzleLock *sql_lock;
335  Table *write_lock_used;
336  if ((sql_lock= get_lock_data(table, count, false,
337  &write_lock_used)))
338  unlockTables(sql_lock);
339 }
340 
341 
346 void Session::unlockReadTables(DrizzleLock *sql_lock)
347 {
348  uint32_t i,found;
349 
350  /* Move all write locks first */
351  THR_LOCK_DATA **lock_local= sql_lock->getLocks();
352  for (i=found=0 ; i < sql_lock->sizeLock(); i++)
353  {
354  if (sql_lock->getLocks()[i]->type >= TL_WRITE_ALLOW_READ)
355  {
356  std::swap(*lock_local, sql_lock->getLocks()[i]);
357  lock_local++;
358  found++;
359  }
360  }
361  /* unlock the read locked tables */
362  if (i != found)
363  {
364  thr_multi_unlock(lock_local, i - found);
365  sql_lock->setLock(found);
366  }
367 
368  /* Then do the same for the external locks */
369  /* Move all write locked tables first */
370  Table **table= sql_lock->getTable();
371  for (i=found=0 ; i < sql_lock->sizeTable() ; i++)
372  {
373  assert(sql_lock->getTable()[i]->lock_position == i);
374  if ((uint32_t) sql_lock->getTable()[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
375  {
376  std::swap(*table, sql_lock->getTable()[i]);
377  table++;
378  found++;
379  }
380  }
381  /* Unlock all read locked tables */
382  if (i != found)
383  {
384  unlock_external(table, i - found);
385  sql_lock->resizeTable(found);
386  }
387  /* Fix the lock positions in Table */
388  table= sql_lock->getTable();
389  found= 0;
390  for (i= 0; i < sql_lock->sizeTable(); i++)
391  {
392  Table *tbl= *table;
393  tbl->lock_position= table - sql_lock->getTable();
394  tbl->lock_data_start= found;
395  found+= tbl->lock_count;
396  table++;
397  }
398 }
399 
400 
421 void Session::removeLock(Table *table)
422 {
423  unlockSomeTables(&table, /* table count */ 1);
424 }
425 
426 
429 void Session::abortLock(Table *table)
430 {
431  DrizzleLock *locked;
432  Table *write_lock_used;
433 
434  if ((locked= get_lock_data(&table, 1, false,
435  &write_lock_used)))
436  {
437  for (uint32_t x= 0; x < locked->sizeLock(); x++)
438  locked->getLocks()[x]->lock->abort_locks();
439  delete locked;
440  }
441 }
442 
443 
456 bool Session::abortLockForThread(Table *table)
457 {
458  bool result= false;
459  Table* write_lock_used;
460  if (DrizzleLock* locked= get_lock_data(&table, 1, false, &write_lock_used))
461  {
462  for (uint32_t i= 0; i < locked->sizeLock(); i++)
463  {
464  if (locked->getLocks()[i]->lock->abort_locks_for_thread(table->in_use->thread_id))
465  result= true;
466  }
467  delete locked;
468  }
469  return result;
470 }
471 
474 int Session::unlock_external(Table **table, uint32_t count)
475 {
476  int error;
477 
478  int error_code=0;
479  do
480  {
481  if ((*table)->current_lock != F_UNLCK)
482  {
483  (*table)->current_lock = F_UNLCK;
484  if ((error=(*table)->cursor->ha_external_lock(this, F_UNLCK)))
485  {
486  error_code=error;
487  print_lock_error(error_code, (*table)->cursor->getEngine()->getName().c_str());
488  }
489  }
490  table++;
491  } while (--count);
492  return error_code;
493 }
494 
495 
507 DrizzleLock *Session::get_lock_data(Table **table_ptr, uint32_t count,
508  bool should_lock, Table **write_lock_used)
509 {
510  uint32_t lock_count;
511  THR_LOCK_DATA **locks, **locks_buf, **locks_start;
512  Table **to, **table_buf;
513 
514  *write_lock_used=0;
515  for (uint32_t i= lock_count= 0 ; i < count ; i++)
516  {
517  Table *t= table_ptr[i];
518 
519  if (! (t->getEngine()->check_flag(HTON_BIT_SKIP_STORE_LOCK)))
520  {
521  lock_count++;
522  }
523  }
524 
525  /*
526  Allocating twice the number of pointers for lock data for use in
527  thr_mulit_lock(). This function reorders the lock data, but cannot
528  update the table values. So the second part of the array is copied
529  from the first part immediately before calling thr_multi_lock().
530  */
531  DrizzleLock *sql_lock= new DrizzleLock(lock_count);
532 
533  if (not sql_lock)
534  return NULL;
535 
536  locks= locks_buf= sql_lock->getLocks();
537  to= table_buf= sql_lock->getTable();
538 
539  for (uint32_t i= 0; i < count ; i++)
540  {
541  Table *table;
542  thr_lock_type lock_type;
543 
544  if (table_ptr[i]->getEngine()->check_flag(HTON_BIT_SKIP_STORE_LOCK))
545  continue;
546 
547  table= table_ptr[i];
548  lock_type= table->reginfo.lock_type;
549  assert (lock_type != TL_WRITE_DEFAULT);
550  if (lock_type >= TL_WRITE_ALLOW_WRITE)
551  {
552  *write_lock_used=table;
553  if (table->db_stat & HA_READ_ONLY)
554  {
555  my_error(ER_OPEN_AS_READONLY, MYF(0), table->getAlias());
556  /* Clear the lock type of the lock data that are stored already. */
557  sql_lock->setLock(locks - sql_lock->getLocks());
558  reset_lock_data_and_free(sql_lock);
559  return NULL;
560  }
561  }
562  locks_start= locks;
563  locks= table->cursor->store_lock(this, locks, should_lock ? lock_type : TL_IGNORE);
564  if (should_lock)
565  {
566  table->lock_position= (uint32_t) (to - table_buf);
567  table->lock_data_start= (uint32_t) (locks_start - locks_buf);
568  table->lock_count= (uint32_t) (locks - locks_start);
569  assert(table->lock_count == 1);
570  }
571  *to++= table;
572  }
573  /*
574  We do not use 'tables', because there are cases where store_lock()
575  returns less locks than lock_count() claimed. This can happen when
576  a FLUSH TABLES tries to abort locks from a MERGE table of another
577  thread. When that thread has just opened the table, but not yet
578  attached its children, it cannot return the locks. lock_count()
579  always returns the number of locks that an attached table has.
580  This is done to avoid the reverse situation: If lock_count() would
581  return 0 for a non-attached MERGE table, and that table becomes
582  attached between the calls to lock_count() and store_lock(), then
583  we would have allocated too little memory for the lock data. Now
584  we may allocate too much, but better safe than memory overrun.
585  And in the FLUSH case, the memory is released quickly anyway.
586  */
587  sql_lock->setLock(locks - locks_buf);
588 
589  return sql_lock;
590 }
591 
592 
619 int Session::lock_table_name(TableList *table_list)
620 {
621  identifier::Table identifier(table_list->getSchemaName(), table_list->getTableName());
622  {
623  /* Only insert the table if we haven't insert it already */
624  table::CacheRange ppp= table::getCache().equal_range(identifier.getKey());
625  for (table::CacheMap::const_iterator iter= ppp.first; iter != ppp.second; ++iter)
626  {
627  Table *table= iter->second;
628  if (table->reginfo.lock_type < TL_WRITE)
629  continue;
630  if (table->in_use == this)
631  {
632  table->getMutableShare()->resetVersion(); // Ensure no one can use this
633  table->locked_by_name= true;
634  return 0;
635  }
636  }
637  }
638 
639  table::Placeholder *table= &table_cache_insert_placeholder(identifier);
640  table_list->table= reinterpret_cast<Table*>(table);
641 
642  /* Return 1 if table is in use */
643  return (test(table::Cache::removeTable(*this, identifier, RTFC_NO_FLAG)));
644 }
645 
646 
647 void TableList::unlock_table_name()
648 {
649  if (table)
650  {
651  table::remove_table(static_cast<table::Concurrent *>(table));
653  }
654 }
655 
656 
657 static bool locked_named_table(TableList *table_list)
658 {
659  for (; table_list; table_list=table_list->next_local)
660  {
661  Table *table= table_list->table;
662  if (table)
663  {
664  Table *save_next= table->getNext();
665  table->setNext(NULL);
666  bool result= table::Cache::areTablesUsed(table_list->table, 0);
667  table->setNext(save_next);
668  if (result)
669  return 1;
670  }
671  }
672  return 0; // All tables are locked
673 }
674 
675 
676 bool Session::wait_for_locked_table_names(TableList *table_list)
677 {
678  bool result= false;
679 
680 #if 0
681  assert(ownership of table::Cache::mutex());
682 #endif
683 
684  while (locked_named_table(table_list))
685  {
686  if (getKilled())
687  {
688  result= true;
689  break;
690  }
691  wait_for_condition(table::Cache::mutex(), COND_refresh);
692  table::Cache::mutex().lock(); /* Wait for a table to unlock and then lock it */
693  }
694  return result;
695 }
696 
697 
712 bool Session::lock_table_names(TableList *table_list)
713 {
714  bool got_all_locks= true;
715  for (TableList* lock_table= table_list; lock_table; lock_table= lock_table->next_local)
716  {
717  int got_lock= lock_table_name(lock_table);
718  if (got_lock < 0)
719  {
720  table_list->unlock_table_names(table_list);
721  return true; // Fatal error
722  }
723  if (got_lock)
724  got_all_locks= false; // Someone is using table
725  }
726 
727  /* If some table was in use, wait until we got the lock */
728  if (not got_all_locks && wait_for_locked_table_names(table_list))
729  {
730  table_list->unlock_table_names(table_list);
731  return true;
732  }
733  return false;
734 }
735 
736 
755 bool Session::lock_table_names_exclusively(TableList *table_list)
756 {
757  if (lock_table_names(table_list))
758  return true;
759 
760  /*
761  Upgrade the table name locks from semi-exclusive to exclusive locks.
762  */
763  for (TableList *table= table_list; table; table= table->next_global)
764  {
765  if (table->table)
766  table->table->open_placeholder= 1;
767  }
768  return false;
769 }
770 
771 
794 void TableList::unlock_table_names(TableList *last_table)
795 {
796  for (TableList *table_iter= this; table_iter != last_table; table_iter= table_iter->next_local)
797  {
798  table_iter->unlock_table_name();
799  }
801 }
802 
803 
804 static void print_lock_error(int error, const char *table)
805 {
806  drizzled::error_t textno;
807  switch (error)
808  {
809  case HA_ERR_LOCK_WAIT_TIMEOUT:
810  textno=ER_LOCK_WAIT_TIMEOUT;
811  break;
812  case HA_ERR_READ_ONLY_TRANSACTION:
813  textno=ER_READ_ONLY_TRANSACTION;
814  break;
815  case HA_ERR_LOCK_DEADLOCK:
816  textno=ER_LOCK_DEADLOCK;
817  break;
818  case HA_ERR_WRONG_COMMAND:
819  textno=ER_ILLEGAL_HA;
820  break;
821  default:
822  textno=ER_CANT_LOCK;
823  break;
824  }
825 
826  if ( textno == ER_ILLEGAL_HA )
827  my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), table);
828  else
829  my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error);
830 }
831 
832 
833 /****************************************************************************
834  Handling of global read locks
835 
836  Taking the global read lock is TWO steps (2nd step is optional; without
837  it, COMMIT of existing transactions will be allowed):
838  lock_global_read_lock() THEN make_global_read_lock_block_commit().
839 
840  The global locks are handled through the global variables:
841  global_read_lock
842  count of threads which have the global read lock (i.e. have completed at
843  least the first step above)
844  global_read_lock_blocks_commit
845  count of threads which have the global read lock and block
846  commits (i.e. are in or have completed the second step above)
847  waiting_for_read_lock
848  count of threads which want to take a global read lock but cannot
849  protect_against_global_read_lock
850  count of threads which have set protection against global read lock.
851 
852  access to them is protected with a mutex LOCK_global_read_lock
853 
854  (XXX: one should never take table::Cache::mutex() if LOCK_global_read_lock is
855  taken, otherwise a deadlock may occur. Other mutexes could be a
856  problem too - grep the code for global_read_lock if you want to use
857  any other mutex here) Also one must not hold table::Cache::mutex() when calling
858  wait_if_global_read_lock(). When the thread with the global read lock
859  tries to close its tables, it needs to take table::Cache::mutex() in
860  close_thread_table().
861 
862  How blocking of threads by global read lock is achieved: that's
863  advisory. Any piece of code which should be blocked by global read lock must
864  be designed like this:
865  - call to wait_if_global_read_lock(). When this returns 0, no global read
866  lock is owned; if argument abort_on_refresh was 0, none can be obtained.
867  - job
868  - if abort_on_refresh was 0, call to session->startWaitingGlobalReadLock() to
869  allow other threads to get the global read lock. I.e. removal of the
870  protection.
871  (Note: it's a bit like an implementation of rwlock).
872 
873  [ I am sorry to mention some SQL syntaxes below I know I shouldn't but found
874  no better descriptive way ]
875 
876  Why does FLUSH TABLES WITH READ LOCK need to block COMMIT: because it's used
877  to read a non-moving SHOW MASTER STATUS, and a COMMIT writes to the binary
878  log.
879 
880  Why getting the global read lock is two steps and not one. Because FLUSH
881  TABLES WITH READ LOCK needs to insert one other step between the two:
882  flushing tables. So the order is
883  1) lock_global_read_lock() (prevents any new table write locks, i.e. stalls
884  all new updates)
885  2) close_cached_tables() (the FLUSH TABLES), which will wait for tables
886  currently opened and being updated to close (so it's possible that there is
887  a moment where all new updates of server are stalled *and* FLUSH TABLES WITH
888  READ LOCK is, too).
889  3) session::makeGlobalReadLockBlockCommit().
890  If we have merged 1) and 3) into 1), we would have had this deadlock:
891  imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
892  table t.
893  session1: SELECT * FROM t FOR UPDATE;
894  session2: UPDATE t SET a=1; # blocked by row-level locks of session1
895  session3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
896  table instance of session2
897  session1: COMMIT; # blocked by session3.
898  session1 blocks session2 which blocks session3 which blocks session1: deadlock.
899 
900  Note that we need to support that one thread does
901  FLUSH TABLES WITH READ LOCK; and then COMMIT;
902  (that's what innobackup does, for some good reason).
903  So in this exceptional case the COMMIT should not be blocked by the FLUSH
904  TABLES WITH READ LOCK.
905 
906 ****************************************************************************/
907 
908 volatile uint32_t global_read_lock=0;
909 volatile uint32_t global_read_lock_blocks_commit=0;
910 static volatile uint32_t protect_against_global_read_lock=0;
911 static volatile uint32_t waiting_for_read_lock=0;
912 
913 bool Session::lockGlobalReadLock()
914 {
915  if (isGlobalReadLock() == Session::NONE)
916  {
917  const char *old_message;
918  LOCK_global_read_lock.lock();
919  old_message= enter_cond(COND_global_read_lock, LOCK_global_read_lock,
920  "Waiting to get readlock");
921 
922  waiting_for_read_lock++;
923  boost::mutex::scoped_lock scopedLock(LOCK_global_read_lock, boost::adopt_lock_t());
924  while (protect_against_global_read_lock && not getKilled())
925  COND_global_read_lock.wait(scopedLock);
926  waiting_for_read_lock--;
927  scopedLock.release();
928  if (getKilled())
929  {
930  exit_cond(old_message);
931  return true;
932  }
933  setGlobalReadLock(Session::GOT_GLOBAL_READ_LOCK);
934  global_read_lock++;
935  exit_cond(old_message); // this unlocks LOCK_global_read_lock
936  }
937 
938  /*
939  We DON'T set global_read_lock_blocks_commit now, it will be set after
940  tables are flushed (as the present function serves for FLUSH TABLES WITH
941  READ LOCK only). Doing things in this order is necessary to avoid
942  deadlocks (we must allow COMMIT until all tables are closed; we should not
943  forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
944  UPDATE and one does FLUSH TABLES WITH READ LOCK).
945  */
946  return false;
947 }
948 
949 
950 void Session::unlockGlobalReadLock(void)
951 {
952  uint32_t tmp;
953 
954  if (not isGlobalReadLock()) // If we have no personal stake in the global lock, just return
955  return;
956 
957  {
958  boost::mutex::scoped_lock scopedLock(LOCK_global_read_lock);
959  tmp= --global_read_lock;
960  if (isGlobalReadLock() == Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
961  --global_read_lock_blocks_commit;
962  }
963  /* Send the signal outside the mutex to avoid a context switch */
964  if (not tmp)
965  {
966  COND_global_read_lock.notify_all();
967  }
968  setGlobalReadLock(Session::NONE);
969 }
970 
971 static inline bool must_wait(bool is_not_commit)
972 {
973  return (global_read_lock &&
974  (is_not_commit ||
975  global_read_lock_blocks_commit));
976 }
977 
978 bool Session::wait_if_global_read_lock(bool abort_on_refresh, bool is_not_commit)
979 {
980  const char *old_message= NULL;
981  bool result= 0, need_exit_cond;
982 
983  /*
984  Assert that we do not own table::Cache::mutex(). If we would own it, other
985  threads could not close their tables. This would make a pretty
986  deadlock.
987  */
988  safe_mutex_assert_not_owner(table::Cache::mutex().native_handle());
989 
990  LOCK_global_read_lock.lock();
991  if ((need_exit_cond= must_wait(is_not_commit)))
992  {
993  if (isGlobalReadLock()) // This thread had the read locks
994  {
995  if (is_not_commit)
996  my_message(ER_CANT_UPDATE_WITH_READLOCK,
997  ER(ER_CANT_UPDATE_WITH_READLOCK), MYF(0));
998  LOCK_global_read_lock.unlock();
999  /*
1000  We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
1001  This allowance is needed to not break existing versions of innobackup
1002  which do a BEGIN; INSERT; FLUSH TABLES WITH READ LOCK; COMMIT.
1003  */
1004  return is_not_commit;
1005  }
1006  old_message= enter_cond(COND_global_read_lock, LOCK_global_read_lock,
1007  "Waiting for release of readlock");
1008 
1009  while (must_wait(is_not_commit) && not getKilled() &&
1010  (!abort_on_refresh || open_tables.version == g_refresh_version))
1011  {
1012  boost::mutex::scoped_lock scoped(LOCK_global_read_lock, boost::adopt_lock_t());
1013  COND_global_read_lock.wait(scoped);
1014  scoped.release();
1015  }
1016  if (getKilled())
1017  result=1;
1018  }
1019 
1020  if (not abort_on_refresh && not result)
1021  protect_against_global_read_lock++;
1022 
1023  /*
1024  The following is only true in case of a global read locks (which is rare)
1025  and if old_message is set
1026  */
1027  if (unlikely(need_exit_cond))
1028  {
1029  exit_cond(old_message); // this unlocks LOCK_global_read_lock
1030  }
1031  else
1032  {
1033  LOCK_global_read_lock.unlock();
1034  }
1035 
1036  return result;
1037 }
1038 
1039 
1040 void Session::startWaitingGlobalReadLock()
1041 {
1042  if (unlikely(isGlobalReadLock()))
1043  return;
1044 
1045  LOCK_global_read_lock.lock();
1046  bool tmp= (!--protect_against_global_read_lock && (waiting_for_read_lock || global_read_lock_blocks_commit));
1047  LOCK_global_read_lock.unlock();
1048 
1049  if (tmp)
1050  COND_global_read_lock.notify_all();
1051 }
1052 
1053 
1054 bool Session::makeGlobalReadLockBlockCommit()
1055 {
1056  bool error;
1057  const char *old_message;
1058  /*
1059  If we didn't succeed lock_global_read_lock(), or if we already suceeded
1060  Session::makeGlobalReadLockBlockCommit(), do nothing.
1061  */
1062  if (isGlobalReadLock() != Session::GOT_GLOBAL_READ_LOCK)
1063  return false;
1064  LOCK_global_read_lock.lock();
1065  /* increment this BEFORE waiting on cond (otherwise race cond) */
1066  global_read_lock_blocks_commit++;
1067  old_message= enter_cond(COND_global_read_lock, LOCK_global_read_lock,
1068  "Waiting for all running commits to finish");
1069  while (protect_against_global_read_lock && not getKilled())
1070  {
1071  boost::mutex::scoped_lock scopedLock(LOCK_global_read_lock, boost::adopt_lock_t());
1072  COND_global_read_lock.wait(scopedLock);
1073  scopedLock.release();
1074  }
1075  if ((error= test(getKilled())))
1076  {
1077  global_read_lock_blocks_commit--; // undo what we did
1078  }
1079  else
1080  {
1081  setGlobalReadLock(Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT);
1082  }
1083 
1084  exit_cond(old_message); // this unlocks LOCK_global_read_lock
1085 
1086  return error;
1087 }
1088 
1089 
1110 {
1111  COND_refresh.notify_all();
1112  COND_global_read_lock.notify_all();
1113 }
1114 
1115 } /* namespace drizzled */