~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/lock.cc

  • Committer: Brian Aker
  • Date: 2010-11-08 05:00:04 UTC
  • mto: (1921.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 1916.
  • Revision ID: brian@tangent.org-20101108050004-l50ikx9zdtcq1e5a
First pass through the global lock refactor merge.

Show diffs side-by-side

added added

removed removed

Lines of Context:
946
946
  - call to wait_if_global_read_lock(). When this returns 0, no global read
947
947
  lock is owned; if argument abort_on_refresh was 0, none can be obtained.
948
948
  - job
949
 
  - if abort_on_refresh was 0, call to start_waiting_global_read_lock() to
 
949
  - if abort_on_refresh was 0, call to session->startWaitingGlobalReadLock() to
950
950
  allow other threads to get the global read lock. I.e. removal of the
951
951
  protection.
952
952
  (Note: it's a bit like an implementation of rwlock).
967
967
  currently opened and being updated to close (so it's possible that there is
968
968
  a moment where all new updates of server are stalled *and* FLUSH TABLES WITH
969
969
  READ LOCK is, too).
970
 
  3) make_global_read_lock_block_commit().
 
970
  3) session::makeGlobalReadLockBlockCommit().
971
971
  If we have merged 1) and 3) into 1), we would have had this deadlock:
972
972
  imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
973
973
  table t.
991
991
static volatile uint32_t protect_against_global_read_lock=0;
992
992
static volatile uint32_t waiting_for_read_lock=0;
993
993
 
994
 
#define GOT_GLOBAL_READ_LOCK               1
995
 
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
996
 
 
997
 
bool lock_global_read_lock(Session *session)
 
994
bool Session::lockGlobalReadLock()
998
995
{
999
 
  if (!session->global_read_lock)
 
996
  if (isGlobalReadLock() == Session::NONE)
1000
997
  {
1001
998
    const char *old_message;
1002
999
    LOCK_global_read_lock.lock();
1003
 
    old_message=session->enter_cond(COND_global_read_lock, LOCK_global_read_lock,
1004
 
                                    "Waiting to get readlock");
 
1000
    old_message= enter_cond(COND_global_read_lock, LOCK_global_read_lock,
 
1001
                            "Waiting to get readlock");
1005
1002
 
1006
1003
    waiting_for_read_lock++;
1007
1004
    boost_unique_lock_t scopedLock(LOCK_global_read_lock, boost::adopt_lock_t());
1008
 
    while (protect_against_global_read_lock && !session->killed)
 
1005
    while (protect_against_global_read_lock && not killed)
1009
1006
      COND_global_read_lock.wait(scopedLock);
1010
1007
    waiting_for_read_lock--;
1011
1008
    scopedLock.release();
1012
 
    if (session->killed)
 
1009
    if (killed)
1013
1010
    {
1014
 
      session->exit_cond(old_message);
 
1011
      exit_cond(old_message);
1015
1012
      return true;
1016
1013
    }
1017
 
    session->global_read_lock= GOT_GLOBAL_READ_LOCK;
 
1014
    setGlobalReadLock(Session::GOT_GLOBAL_READ_LOCK);
1018
1015
    global_read_lock++;
1019
 
    session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
 
1016
    exit_cond(old_message); // this unlocks LOCK_global_read_lock
1020
1017
  }
 
1018
 
1021
1019
  /*
1022
1020
    We DON'T set global_read_lock_blocks_commit now, it will be set after
1023
1021
    tables are flushed (as the present function serves for FLUSH TABLES WITH
1030
1028
}
1031
1029
 
1032
1030
 
1033
 
void unlock_global_read_lock(Session *session)
 
1031
void Session::unlockGlobalReadLock(void)
1034
1032
{
1035
1033
  uint32_t tmp;
1036
1034
 
1037
1035
  {
1038
1036
    boost_unique_lock_t scopedLock(LOCK_global_read_lock);
1039
1037
    tmp= --global_read_lock;
1040
 
    if (session->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
 
1038
    if (isGlobalReadLock() == Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
1041
1039
      --global_read_lock_blocks_commit;
1042
1040
  }
1043
1041
  /* Send the signal outside the mutex to avoid a context switch */
1044
 
  if (!tmp)
 
1042
  if (not tmp)
1045
1043
  {
1046
1044
    COND_global_read_lock.notify_all();
1047
1045
  }
1048
 
  session->global_read_lock= 0;
 
1046
  setGlobalReadLock(Session::NONE);
1049
1047
}
1050
1048
 
1051
1049
static inline bool must_wait(bool is_not_commit)
1071
1069
  LOCK_global_read_lock.lock();
1072
1070
  if ((need_exit_cond= must_wait(is_not_commit)))
1073
1071
  {
1074
 
    if (session->global_read_lock)              // This thread had the read locks
 
1072
    if (session->isGlobalReadLock())            // This thread had the read locks
1075
1073
    {
1076
1074
      if (is_not_commit)
1077
1075
        my_message(ER_CANT_UPDATE_WITH_READLOCK,
1096
1094
    if (session->killed)
1097
1095
      result=1;
1098
1096
  }
1099
 
  if (!abort_on_refresh && !result)
 
1097
  if (not abort_on_refresh && not result)
1100
1098
    protect_against_global_read_lock++;
 
1099
 
1101
1100
  /*
1102
1101
    The following is only true in case of a global read locks (which is rare)
1103
1102
    and if old_message is set
1106
1105
    session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1107
1106
  else
1108
1107
    LOCK_global_read_lock.unlock();
 
1108
 
1109
1109
  return result;
1110
1110
}
1111
1111
 
1112
1112
 
1113
 
void start_waiting_global_read_lock(Session *session)
 
1113
void Session::startWaitingGlobalReadLock()
1114
1114
{
1115
1115
  bool tmp;
1116
 
  if (unlikely(session->global_read_lock))
 
1116
  if (unlikely(isGlobalReadLock()))
1117
1117
    return;
 
1118
 
1118
1119
  LOCK_global_read_lock.lock();
1119
1120
  tmp= (!--protect_against_global_read_lock &&
1120
1121
        (waiting_for_read_lock || global_read_lock_blocks_commit));
1121
1122
  LOCK_global_read_lock.unlock();
 
1123
 
1122
1124
  if (tmp)
1123
1125
    COND_global_read_lock.notify_all();
1124
 
  return;
1125
1126
}
1126
1127
 
1127
1128
 
1128
 
bool make_global_read_lock_block_commit(Session *session)
 
1129
bool Session::makeGlobalReadLockBlockCommit()
1129
1130
{
1130
1131
  bool error;
1131
1132
  const char *old_message;
1132
1133
  /*
1133
1134
    If we didn't succeed lock_global_read_lock(), or if we already suceeded
1134
 
    make_global_read_lock_block_commit(), do nothing.
 
1135
    Session::makeGlobalReadLockBlockCommit(), do nothing.
1135
1136
  */
1136
 
  if (session->global_read_lock != GOT_GLOBAL_READ_LOCK)
 
1137
  if (isGlobalReadLock() != Session::GOT_GLOBAL_READ_LOCK)
1137
1138
    return false;
1138
1139
  LOCK_global_read_lock.lock();
1139
1140
  /* increment this BEFORE waiting on cond (otherwise race cond) */
1140
1141
  global_read_lock_blocks_commit++;
1141
 
  old_message= session->enter_cond(COND_global_read_lock, LOCK_global_read_lock,
1142
 
                                   "Waiting for all running commits to finish");
1143
 
  while (protect_against_global_read_lock && !session->killed)
 
1142
  old_message= enter_cond(COND_global_read_lock, LOCK_global_read_lock,
 
1143
                          "Waiting for all running commits to finish");
 
1144
  while (protect_against_global_read_lock && not killed)
1144
1145
  {
1145
1146
    boost_unique_lock_t scopedLock(LOCK_global_read_lock, boost::adopt_lock_t());
1146
1147
    COND_global_read_lock.wait(scopedLock);
1147
1148
    scopedLock.release();
1148
1149
  }
1149
 
  if ((error= test(session->killed)))
 
1150
  if ((error= test(killed)))
 
1151
  {
1150
1152
    global_read_lock_blocks_commit--; // undo what we did
 
1153
  }
1151
1154
  else
1152
 
    session->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1153
 
  session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
 
1155
  {
 
1156
    setGlobalReadLock(Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT);
 
1157
  }
 
1158
 
 
1159
  exit_cond(old_message); // this unlocks LOCK_global_read_lock
 
1160
 
1154
1161
  return error;
1155
1162
}
1156
1163