35 #include "sync0sync.ic"
43 #ifdef UNIV_SYNC_DEBUG
174 static ib_int64_t mutex_spin_round_count = 0;
177 static ib_int64_t mutex_spin_wait_count = 0;
180 static ib_int64_t mutex_os_wait_count = 0;
197 #ifdef UNIV_SYNC_DEBUG
205 UNIV_INTERN
mutex_t sync_thread_mutex;
207 # ifdef UNIV_PFS_MUTEX
208 UNIV_INTERN mysql_pfs_key_t sync_thread_mutex_key;
218 #ifdef UNIV_PFS_MUTEX
219 UNIV_INTERN mysql_pfs_key_t mutex_list_mutex_key;
222 #ifdef UNIV_SYNC_DEBUG
224 UNIV_INTERN ibool sync_order_checks_on = FALSE;
228 static const ulint SYNC_THREAD_N_LEVELS = 10000;
274 const char* cmutex_name,
275 # ifdef UNIV_SYNC_DEBUG
279 const char* cfile_name,
282 #if defined(HAVE_ATOMIC_BUILTINS)
283 mutex_reset_lock_word(mutex);
289 mutex_set_waiters(mutex, 0);
291 mutex->magic_n = MUTEX_MAGIC_N;
293 #ifdef UNIV_SYNC_DEBUG
295 mutex->file_name =
"not yet reserved";
296 mutex->level = level;
299 mutex->
cline = cline;
302 mutex->cmutex_name= cmutex_name;
303 mutex->count_using= 0;
304 mutex->mutex_type= 0;
305 mutex->lspent_time= 0;
306 mutex->lmax_spent_time= 0;
307 mutex->count_spin_loop= 0;
308 mutex->count_spin_rounds= 0;
309 mutex->count_os_yield= 0;
318 #ifdef UNIV_SYNC_DEBUG
319 || (mutex == &sync_thread_mutex)
347 ut_ad(mutex_validate(mutex));
349 ut_a(mutex_get_waiters(mutex) == 0);
351 #ifdef UNIV_MEM_DEBUG
352 if (mutex == &mem_hash_mutex) {
361 #ifdef UNIV_SYNC_DEBUG
362 && mutex != &sync_thread_mutex
381 #ifdef UNIV_MEM_DEBUG
384 #if !defined(HAVE_ATOMIC_BUILTINS)
411 ut_ad(mutex_validate(mutex));
413 if (!mutex_test_and_set(mutex)) {
416 #ifdef UNIV_SYNC_DEBUG
417 mutex_set_debug_info(mutex, file_name, line);
437 ut_a(mutex->magic_n == MUTEX_MAGIC_N);
452 ut_ad(mutex_validate(mutex));
487 const char* file_name,
494 ib_int64_t lstart_time = 0, lfinish_time;
498 uint timer_started = 0;
506 mutex_spin_wait_count++;
519 ut_d(mutex->count_spin_loop++);
522 if (srv_spin_wait_delay) {
531 mutex->count_os_yield++;
532 #ifndef UNIV_HOTBACKUP
533 if (timed_mutexes && timer_started == 0) {
535 lstart_time= (ib_int64_t)sec * 1000000 + ms;
543 #ifdef UNIV_SRV_PRINT_LATCH_WAITS
545 "Thread %lu spin wait mutex at %p"
546 " cfile %s cline %lu rnds %lu\n",
549 (ulong) mutex->
cline, (ulong) i);
552 mutex_spin_round_count += i;
554 ut_d(mutex->count_spin_rounds += i);
556 if (mutex_test_and_set(mutex) == 0) {
560 #ifdef UNIV_SYNC_DEBUG
561 mutex_set_debug_info(mutex, file_name, line);
581 SYNC_MUTEX, file_name, line, &index);
589 mutex_set_waiters(mutex, 1);
592 for (i = 0; i < 4; i++) {
593 if (mutex_test_and_set(mutex) == 0) {
599 #ifdef UNIV_SYNC_DEBUG
600 mutex_set_debug_info(mutex, file_name, line);
603 #ifdef UNIV_SRV_PRINT_LATCH_WAITS
604 fprintf(stderr,
"Thread %lu spin wait succeeds at 2:"
622 #ifdef UNIV_SRV_PRINT_LATCH_WAITS
624 "Thread %lu OS wait mutex at %p cfile %s cline %lu rnds %lu\n",
627 (ulong) mutex->
cline, (ulong) i);
630 mutex_os_wait_count++;
635 #ifndef UNIV_HOTBACKUP
636 if (timed_mutexes == 1 && timer_started == 0) {
638 lstart_time= (ib_int64_t)sec * 1000000 + ms;
649 if (timed_mutexes == 1 && timer_started==1) {
651 lfinish_time= (ib_int64_t)sec * 1000000 + ms;
653 ltime_diff= (ulint) (lfinish_time - lstart_time);
654 mutex->lspent_time += ltime_diff;
656 if (mutex->lmax_spent_time < ltime_diff) {
657 mutex->lmax_spent_time= ltime_diff;
672 mutex_set_waiters(mutex, 0);
680 #ifdef UNIV_SYNC_DEBUG
685 mutex_set_debug_info(
688 const char* file_name,
694 sync_thread_add_level(mutex, mutex->level);
696 mutex->file_name = file_name;
704 mutex_get_debug_info(
707 const char** file_name,
714 *file_name = mutex->file_name;
716 *thread_id = mutex->thread_id;
723 mutex_list_print_info(
728 const char* file_name;
735 "----------\n", file);
737 mutex_enter(&mutex_list_mutex);
741 while (mutex != NULL) {
745 mutex_get_debug_info(mutex, &file_name, &line,
748 "Locked mutex: addr %p thread %ld"
749 " file %s line %ld\n",
757 fprintf(file,
"Total number of mutexes %ld\n", count);
759 mutex_exit(&mutex_list_mutex);
767 mutex_n_reserved(
void)
773 mutex_enter(&mutex_list_mutex);
785 mutex_exit(&mutex_list_mutex);
804 return(mutex_n_reserved() + rw_lock_n_locked() == 0);
812 sync_thread_level_arrays_find_slot(
void)
821 for (i = 0; i < OS_THREAD_MAX_N; i++) {
824 slot = &sync_thread_level_arrays[i];
840 sync_thread_level_arrays_find_free(
void)
846 for (i = 0; i < OS_THREAD_MAX_N; i++) {
849 slot = &sync_thread_level_arrays[i];
851 if (slot->
levels == NULL) {
874 if (mutex->magic_n == MUTEX_MAGIC_N) {
876 "Mutex created at %s %lu\n",
878 (ulong) mutex->
cline);
882 const char* file_name;
885 mutex_get_debug_info(
886 mutex, &file_name, &line, &thread_id);
889 "InnoDB: Locked mutex:"
890 " addr %p thread %ld file %s line %ld\n",
892 file_name, (ulong) line);
894 fputs(
"Not locked\n", stderr);
909 sync_thread_levels_g(
918 for (i = 0; i < arr->
n_elems; i++) {
921 slot = &arr->
elems[i];
923 if (slot->
latch != NULL && slot->
level <= limit) {
926 "InnoDB: sync levels should be"
927 " > %lu but a level is %lu\n",
928 (ulong) limit, (ulong) slot->
level);
929 sync_print_warning(slot);
945 sync_thread_levels_contain(
953 for (i = 0; i < arr->
n_elems; i++) {
956 slot = &arr->
elems[i];
958 if (slot->
latch != NULL && slot->
level == level) {
972 sync_thread_levels_contains(
981 if (!sync_order_checks_on) {
986 mutex_enter(&sync_thread_mutex);
988 thread_slot = sync_thread_level_arrays_find_slot();
990 if (thread_slot == NULL) {
992 mutex_exit(&sync_thread_mutex);
997 arr = thread_slot->
levels;
999 for (i = 0; i < arr->
n_elems; i++) {
1002 slot = &arr->
elems[i];
1004 if (slot->
latch != NULL && slot->
level == level) {
1006 mutex_exit(&sync_thread_mutex);
1007 return(slot->
latch);
1011 mutex_exit(&sync_thread_mutex);
1021 sync_thread_levels_nonempty_gen(
1023 ibool dict_mutex_allowed)
1032 if (!sync_order_checks_on) {
1037 mutex_enter(&sync_thread_mutex);
1039 thread_slot = sync_thread_level_arrays_find_slot();
1041 if (thread_slot == NULL) {
1043 mutex_exit(&sync_thread_mutex);
1048 arr = thread_slot->
levels;
1050 for (i = 0; i < arr->
n_elems; ++i) {
1053 slot = &arr->
elems[i];
1055 if (slot->
latch != NULL
1056 && (!dict_mutex_allowed
1057 || (slot->
level != SYNC_DICT
1058 && slot->
level != SYNC_DICT_OPERATION))) {
1060 mutex_exit(&sync_thread_mutex);
1063 return(slot->
latch);
1067 mutex_exit(&sync_thread_mutex);
1077 sync_thread_levels_empty(
void)
1080 return(sync_thread_levels_empty_gen(FALSE));
1089 sync_thread_add_level(
1100 if (!sync_order_checks_on) {
1105 if ((latch == (
void*)&sync_thread_mutex)
1106 || (latch == (
void*)&mutex_list_mutex)
1107 || (latch == (
void*)&rw_lock_debug_mutex)
1108 || (latch == (
void*)&rw_lock_list_mutex)) {
1113 if (level == SYNC_LEVEL_VARYING) {
1118 mutex_enter(&sync_thread_mutex);
1120 thread_slot = sync_thread_level_arrays_find_slot();
1122 if (thread_slot == NULL) {
1126 + (
sizeof(*array->
elems) * SYNC_THREAD_N_LEVELS);
1129 array = calloc(sz,
sizeof(
char));
1130 ut_a(array != NULL);
1133 array->
max_elems = SYNC_THREAD_N_LEVELS;
1136 thread_slot = sync_thread_level_arrays_find_free();
1137 thread_slot->
levels = array;
1141 array = thread_slot->
levels;
1149 case SYNC_NO_ORDER_CHECK:
1150 case SYNC_EXTERN_STORAGE:
1151 case SYNC_TREE_NODE_FROM_HASH:
1154 case SYNC_TRX_SYS_HEADER:
1155 if (srv_is_being_started) {
1164 case SYNC_WORK_QUEUE:
1166 case SYNC_LOG_FLUSH_ORDER:
1167 case SYNC_THR_LOCAL:
1168 case SYNC_ANY_LATCH:
1169 case SYNC_FILE_FORMAT_TAG:
1170 case SYNC_DOUBLEWRITE:
1171 case SYNC_SEARCH_SYS:
1172 case SYNC_SEARCH_SYS_CONF:
1173 case SYNC_TRX_LOCK_HEAP:
1175 case SYNC_IBUF_BITMAP_MUTEX:
1178 case SYNC_PURGE_LATCH:
1179 case SYNC_PURGE_QUEUE:
1180 case SYNC_DICT_AUTOINC_MUTEX:
1181 case SYNC_DICT_OPERATION:
1182 case SYNC_DICT_HEADER:
1183 case SYNC_TRX_I_S_RWLOCK:
1184 case SYNC_TRX_I_S_LAST_READ:
1185 if (!sync_thread_levels_g(array, level, TRUE)) {
1187 "InnoDB: sync_thread_levels_g(array, %lu)"
1188 " does not hold!\n", level);
1192 case SYNC_BUF_FLUSH_LIST:
1196 if (!sync_thread_levels_g(array, level-1, TRUE)) {
1198 "InnoDB: sync_thread_levels_g(array, %lu)"
1199 " does not hold!\n", level-1);
1204 case SYNC_BUF_BLOCK:
1208 if (!sync_thread_levels_g(array, level, FALSE)) {
1209 ut_a(sync_thread_levels_g(array, level - 1, TRUE));
1210 ut_a(sync_thread_levels_contain(array, SYNC_BUF_POOL));
1214 if (sync_thread_levels_contain(array, SYNC_KERNEL)) {
1215 ut_a(sync_thread_levels_g(array, SYNC_REC_LOCK - 1,
1218 ut_a(sync_thread_levels_g(array, SYNC_REC_LOCK, TRUE));
1221 case SYNC_IBUF_BITMAP:
1225 if (sync_thread_levels_contain(array,
1226 SYNC_IBUF_BITMAP_MUTEX)) {
1227 ut_a(sync_thread_levels_g(array, SYNC_IBUF_BITMAP - 1,
1233 ut_a(srv_is_being_started
1234 || sync_thread_levels_g(array, SYNC_IBUF_BITMAP,
1239 ut_a(sync_thread_levels_contain(array, SYNC_FSP));
1242 ut_a(sync_thread_levels_contain(array, SYNC_FSP)
1243 || sync_thread_levels_g(array, SYNC_FSP, TRUE));
1245 case SYNC_TRX_UNDO_PAGE:
1253 ut_a(sync_thread_levels_contain(array, SYNC_TRX_UNDO)
1254 || sync_thread_levels_contain(array, SYNC_RSEG)
1255 || sync_thread_levels_g(array, level - 1, TRUE));
1257 case SYNC_RSEG_HEADER:
1258 ut_a(sync_thread_levels_contain(array, SYNC_RSEG));
1260 case SYNC_RSEG_HEADER_NEW:
1261 ut_a(sync_thread_levels_contain(array, SYNC_KERNEL)
1262 && sync_thread_levels_contain(array, SYNC_FSP_PAGE));
1264 case SYNC_TREE_NODE:
1265 ut_a(sync_thread_levels_contain(array, SYNC_INDEX_TREE)
1266 || sync_thread_levels_contain(array, SYNC_DICT_OPERATION)
1267 || sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE));
1269 case SYNC_TREE_NODE_NEW:
1270 ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE)
1271 || sync_thread_levels_contain(array, SYNC_IBUF_MUTEX));
1273 case SYNC_INDEX_TREE:
1274 if (sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)
1275 && sync_thread_levels_contain(array, SYNC_FSP)) {
1276 ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1,
1279 ut_a(sync_thread_levels_g(array, SYNC_TREE_NODE - 1,
1283 case SYNC_IBUF_MUTEX:
1284 ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, TRUE));
1286 case SYNC_IBUF_PESS_INSERT_MUTEX:
1287 ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE));
1288 ut_a(!sync_thread_levels_contain(array, SYNC_IBUF_MUTEX));
1290 case SYNC_IBUF_HEADER:
1291 ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE));
1292 ut_a(!sync_thread_levels_contain(array, SYNC_IBUF_MUTEX));
1293 ut_a(!sync_thread_levels_contain(array,
1294 SYNC_IBUF_PESS_INSERT_MUTEX));
1298 ut_a(buf_debug_prints
1299 || sync_thread_levels_g(array, SYNC_DICT, TRUE));
1301 ut_a(sync_thread_levels_g(array, SYNC_DICT, TRUE));
1308 if (array->
next_free == ULINT_UNDEFINED) {
1317 ut_a(i < array->n_elems);
1318 ut_a(i != ULINT_UNDEFINED);
1322 slot = &array->
elems[i];
1326 slot->
latch = latch;
1327 slot->
level = level;
1329 mutex_exit(&sync_thread_mutex);
1339 sync_thread_reset_level(
1347 if (!sync_order_checks_on) {
1352 if ((latch == (
void*)&sync_thread_mutex)
1353 || (latch == (
void*)&mutex_list_mutex)
1354 || (latch == (
void*)&rw_lock_debug_mutex)
1355 || (latch == (
void*)&rw_lock_list_mutex)) {
1360 mutex_enter(&sync_thread_mutex);
1362 thread_slot = sync_thread_level_arrays_find_slot();
1364 if (thread_slot == NULL) {
1368 mutex_exit(&sync_thread_mutex);
1372 array = thread_slot->
levels;
1374 for (i = 0; i < array->
n_elems; i++) {
1377 slot = &array->
elems[i];
1379 if (slot->
latch != latch) {
1397 if (array->
in_use == 0) {
1402 mutex_exit(&sync_thread_mutex);
1407 if (((
mutex_t*) latch)->magic_n != MUTEX_MAGIC_N) {
1412 if (rw_lock->level == SYNC_LEVEL_VARYING) {
1413 mutex_exit(&sync_thread_mutex);
1421 mutex_exit(&sync_thread_mutex);
1443 #ifdef UNIV_SYNC_DEBUG
1447 sync_thread_level_arrays = calloc(
1449 ut_a(sync_thread_level_arrays != NULL);
1456 SYNC_NO_ORDER_CHECK);
1457 #ifdef UNIV_SYNC_DEBUG
1458 mutex_create(sync_thread_mutex_key, &sync_thread_mutex,
1459 SYNC_NO_ORDER_CHECK);
1465 mutex_create(rw_lock_list_mutex_key, &rw_lock_list_mutex,
1466 SYNC_NO_ORDER_CHECK);
1468 #ifdef UNIV_SYNC_DEBUG
1469 mutex_create(rw_lock_debug_mutex_key, &rw_lock_debug_mutex,
1470 SYNC_NO_ORDER_CHECK);
1473 rw_lock_debug_waiters = FALSE;
1477 #ifdef UNIV_SYNC_DEBUG
1482 sync_thread_level_arrays_free(
void)
1488 for (i = 0; i < OS_THREAD_MAX_N; i++) {
1491 slot = &sync_thread_level_arrays[i];
1494 if (slot->
levels != NULL) {
1500 free(sync_thread_level_arrays);
1501 sync_thread_level_arrays = NULL;
1521 #ifdef UNIV_MEM_DEBUG
1522 if (mutex == &mem_hash_mutex) {
1534 #ifdef UNIV_SYNC_DEBUG
1535 mutex_free(&sync_thread_mutex);
1538 sync_order_checks_on = FALSE;
1540 sync_thread_level_arrays_free();
1554 #ifdef UNIV_SYNC_DEBUG
1555 fprintf(file,
"Mutex exits %llu, rws exits %llu, rwx exits %llu\n",
1560 "Mutex spin waits %"PRId64
", rounds %"PRId64
", "
1561 "OS waits %"PRId64
"\n"
1562 "RW-shared spins %"PRId64
", rounds %"PRId64
", OS waits %"PRId64
";"
1563 " RW-excl spins %"PRId64
", rounds %"PRId64
", OS waits %"PRId64
"\n",
1564 mutex_spin_wait_count,
1565 mutex_spin_round_count,
1566 mutex_os_wait_count,
1575 "Spin rounds per wait: %.2f mutex, %.2f RW-shared, "
1577 (
double) mutex_spin_round_count /
1578 (mutex_spin_wait_count ? mutex_spin_wait_count : 1),
1593 #ifdef UNIV_SYNC_DEBUG
1594 mutex_list_print_info(file);
1596 rw_lock_list_print_info(file);