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.
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
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
991
991
static volatile uint32_t protect_against_global_read_lock=0;
992
992
static volatile uint32_t waiting_for_read_lock=0;
994
#define GOT_GLOBAL_READ_LOCK 1
995
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
997
bool lock_global_read_lock(Session *session)
994
bool Session::lockGlobalReadLock()
999
if (!session->global_read_lock)
996
if (isGlobalReadLock() == Session::NONE)
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");
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)
1014
session->exit_cond(old_message);
1011
exit_cond(old_message);
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
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
1033
void unlock_global_read_lock(Session *session)
1031
void Session::unlockGlobalReadLock(void)
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;
1043
1041
/* Send the signal outside the mutex to avoid a context switch */
1046
1044
COND_global_read_lock.notify_all();
1048
session->global_read_lock= 0;
1046
setGlobalReadLock(Session::NONE);
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)))
1074
if (session->global_read_lock) // This thread had the read locks
1072
if (session->isGlobalReadLock()) // This thread had the read locks
1076
1074
if (is_not_commit)
1077
1075
my_message(ER_CANT_UPDATE_WITH_READLOCK,
1096
1094
if (session->killed)
1099
if (!abort_on_refresh && !result)
1097
if (not abort_on_refresh && not result)
1100
1098
protect_against_global_read_lock++;
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
1108
1107
LOCK_global_read_lock.unlock();
1113
void start_waiting_global_read_lock(Session *session)
1113
void Session::startWaitingGlobalReadLock()
1116
if (unlikely(session->global_read_lock))
1116
if (unlikely(isGlobalReadLock()))
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
1125
COND_global_read_lock.notify_all();
1128
bool make_global_read_lock_block_commit(Session *session)
1129
bool Session::makeGlobalReadLockBlockCommit()
1131
1132
const char *old_message;
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.
1136
if (session->global_read_lock != GOT_GLOBAL_READ_LOCK)
1137
if (isGlobalReadLock() != Session::GOT_GLOBAL_READ_LOCK)
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)
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();
1149
if ((error= test(session->killed)))
1150
if ((error= test(killed)))
1150
1152
global_read_lock_blocks_commit--; // undo what we did
1152
session->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1153
session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1156
setGlobalReadLock(Session::MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT);
1159
exit_cond(old_message); // this unlocks LOCK_global_read_lock