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