Skip to content

Commit d1a17a5

Browse files
committed
[RP004] Optimize InnoDB rw_lock s-lock operation cost on high concurrency
- Removes rw_lock_t::reader_thread(*) from except for debug build. It makes s-lock cost "very" expensive at high concurrency, even without any concurrent x-locks. - In addition, removes also updating rw_lock_t::last_s_[file_name|line]. Though legacy code, it also make the s-lock cost expensive. Anyway, this is uncertain information, and not worth to reduce performance. The cost is cache coherency cost amoung cpu cores or chips. The cache coherency bandwidth is limited resource, and should be saved for actual performance. (*) The rw_lock_t::reader_thread was introduced at > commit a8dcfe2 > Author: Marcin Babij <marcin.babij@oracle.com> > Date: Tue Jan 26 13:13:57 2021 +0100 > > Bug #32252477 RW_LOCK COULD STORE AND PRINT INFO ON S-LATCHER, IF THERE IS A SINGLE ONE
1 parent c304e71 commit d1a17a5

File tree

6 files changed

+19
-19
lines changed

6 files changed

+19
-19
lines changed

MYSQL_VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ MYSQL_VERSION_MINOR=0
33
MYSQL_VERSION_PATCH=42
44
MYSQL_VERSION_EXTRA=
55
MYSQL_VERSION_STABILITY="LTS"
6-
MYSQL_RP_REVISION="-RP003"
6+
MYSQL_RP_REVISION="-RP004"

storage/innobase/include/sync0rw.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,9 +392,11 @@ struct rw_lock_t
392392
thread which already released or passed the lock. */
393393
std::atomic<std::thread::id> writer_thread;
394394

395+
#ifdef UNIV_DEBUG
395396
/** XOR of reader threads' IDs. If there is exactly one reader it should allow
396397
to retrieve the thread ID of that reader. */
397398
Atomic_xor_of_thread_id reader_thread;
399+
#endif /* UNIV_DEBUG */
398400

399401
/** Used by sync0arr.cc for thread queueing */
400402
os_event_t event;

storage/innobase/include/sync0rw.ic

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ bool rw_lock_s_lock_low(rw_lock_t *lock, ulint pass [[maybe_unused]],
251251

252252
ut_d(rw_lock_add_debug_info(lock, pass, RW_LOCK_S, location));
253253

254+
#ifdef UNIV_DEBUG
254255
/* These debugging values are not set safely: they may be incorrect
255256
or even refer to a line that is invalid for the file name. */
256257
lock->last_s_file_name = location.filename;
@@ -259,6 +260,7 @@ bool rw_lock_s_lock_low(rw_lock_t *lock, ulint pass [[maybe_unused]],
259260
std::numeric_limits<decltype(lock->last_s_line)>::max());
260261
lock->last_s_line = location.line;
261262
lock->reader_thread.xor_thing(std::this_thread::get_id());
263+
#endif /* UNIV_DEBUG */
262264

263265
return true; /* locking succeeded */
264266
}
@@ -353,7 +355,9 @@ static inline void rw_lock_s_unlock_func(IF_DEBUG(ulint pass, )
353355
ut_ad(lock->lock_word > -X_LOCK_DECR);
354356
ut_ad(lock->lock_word != 0);
355357
ut_ad(lock->lock_word < X_LOCK_DECR);
358+
#ifdef UNIV_DEBUG
356359
lock->reader_thread.xor_thing(std::this_thread::get_id());
360+
#endif /* UNIV_DEBUG */
357361

358362
ut_d(rw_lock_remove_debug_info(lock, pass, RW_LOCK_S));
359363

storage/innobase/sync/sync0arr.cc

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -419,10 +419,12 @@ void sync_array_cell_print(FILE *file, const sync_cell_t *cell) {
419419

420420
const auto readers_count = rw_lock_get_reader_count(rwlock);
421421
fprintf(file, "number of readers " ULINTPF, readers_count);
422+
#ifdef UNIV_DEBUG
422423
if (readers_count == 1) {
423424
fprintf(file, " (thread id %s)",
424425
to_string(rwlock->reader_thread.recover_if_single()).c_str());
425426
}
427+
#endif /* UNIV_DEBUG */
426428
fprintf(file,
427429
", waiters flag %d"
428430
", lock_word: %lx\n"
@@ -574,24 +576,6 @@ bool sync_array_detect_rwlock_deadlock(sync_cell_t *cell, sync_array_t *arr,
574576
}
575577
}
576578
}
577-
{
578-
if (rw_lock_get_reader_count(lock) == 1) {
579-
/* You might be worried about a race-condition: could it happen that the
580-
number of s-lockers has changed from 1 to say 3, and the XOR we recover in
581-
the line below corresponds to some unrelated fourth thread?
582-
For example 0x101 xor 0x110 xor 0x111 = 0x100.
583-
This isn't a problem in practice, because conflicts(RW_LOCKS,..) is true
584-
only if the waiter waits for RW_LOCK_X_WAIT, which means it already has
585-
announced its presence via lock_word, so no more s-locks should be granted
586-
to not starve it. Thus the number of readers can only decrease. We double
587-
check it is still 1 after recovering the xor, so it can't be 0 nor torn.*/
588-
const auto thread = lock->reader_thread.recover_if_single();
589-
if (rw_lock_get_reader_count(lock) == 1 && thread != none &&
590-
std::forward<F>(conflicts)(RW_LOCK_S, thread == waiter)) {
591-
suspects[suspects_cnt++] = thread;
592-
}
593-
}
594-
}
595579
for (size_t i = 0; i < suspects_cnt; ++i) {
596580
if (sync_array_deadlock_step(arr, suspects[i], depth)) {
597581
sync_array_cell_print(stderr, cell);

storage/innobase/sync/sync0rw.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,11 @@ void rw_lock_create_func(rw_lock_t *lock,
223223
std::numeric_limits<decltype(lock->clocation.line)>::max());
224224

225225
lock->count_os_wait = 0;
226+
#ifdef UNIV_DEBUG
226227
lock->last_s_file_name = "not yet reserved";
228+
#else
229+
lock->last_s_file_name = "not recorded";
230+
#endif /* UNIV_DEBUG */
227231
lock->last_x_file_name = "not yet reserved";
228232
lock->last_s_line = 0;
229233
lock->last_x_line = 0;

unittest/gunit/innodb/sync0rw-t.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,10 @@ TEST(sync0rw, rw_lock_reader_thread) {
137137
EXPECT_EQ(rw_lock_get_reader_count(rw_locks[0]), 1);
138138
EXPECT_EQ(rw_lock_get_reader_count(rw_locks[1]), 2);
139139
EXPECT_EQ(rw_lock_get_reader_count(rw_locks[2]), 0);
140+
#ifdef UNIV_DEBUG
140141
EXPECT_EQ(rw_locks[0]->reader_thread.recover_if_single(),
141142
thread_1_id.load());
143+
#endif /* UNIV_DEBUG */
142144

143145
FILE *tmp_file = tmpfile();
144146
EXPECT_NE(tmp_file, nullptr);
@@ -176,9 +178,13 @@ TEST(sync0rw, rw_lock_reader_thread) {
176178
EXPECT_THAT(cell_print, testing::HasSubstr("number of readers 0, waiters"));
177179
/* Note that std::to_string(thread_id_to_uint64(thread_id) could be
178180
something different than to_string(thread_id). */
181+
#ifdef UNIV_DEBUG
179182
EXPECT_THAT(cell_print, testing::HasSubstr(
180183
"number of readers 1 (thread id " +
181184
to_string(thread_1_id.load()) + "), waiters"));
185+
#else
186+
EXPECT_THAT(cell_print, testing::HasSubstr("number of readers 1, waiters"));
187+
#endif /* UNIV_DEBUG */
182188
EXPECT_THAT(cell_print, testing::HasSubstr("number of readers 2, waiters"));
183189
};
184190

0 commit comments

Comments
 (0)