35 #include "sync0sync.ic"
43 #ifdef UNIV_SYNC_DEBUG
173 static ib_int64_t mutex_spin_round_count = 0;
176 static ib_int64_t mutex_spin_wait_count = 0;
179 static ib_int64_t mutex_os_wait_count = 0;
196 #ifdef UNIV_SYNC_DEBUG
203 UNIV_INTERN
mutex_t sync_thread_mutex;
205 # ifdef UNIV_PFS_MUTEX
206 UNIV_INTERN mysql_pfs_key_t sync_thread_mutex_key;
216 #ifdef UNIV_PFS_MUTEX
217 UNIV_INTERN mysql_pfs_key_t mutex_list_mutex_key;
220 #ifdef UNIV_SYNC_DEBUG
222 UNIV_INTERN ibool sync_order_checks_on = FALSE;
233 #define SYNC_THREAD_N_LEVELS 10000
253 const char* cmutex_name,
254 # ifdef UNIV_SYNC_DEBUG
258 const char* cfile_name,
261 #if defined(HAVE_ATOMIC_BUILTINS)
262 mutex_reset_lock_word(mutex);
268 mutex_set_waiters(mutex, 0);
270 mutex->magic_n = MUTEX_MAGIC_N;
272 #ifdef UNIV_SYNC_DEBUG
274 mutex->file_name =
"not yet reserved";
275 mutex->level = level;
278 mutex->
cline = cline;
281 mutex->cmutex_name= cmutex_name;
282 mutex->count_using= 0;
283 mutex->mutex_type= 0;
284 mutex->lspent_time= 0;
285 mutex->lmax_spent_time= 0;
286 mutex->count_spin_loop= 0;
287 mutex->count_spin_rounds= 0;
288 mutex->count_os_yield= 0;
297 #ifdef UNIV_SYNC_DEBUG
298 || (mutex == &sync_thread_mutex)
326 ut_ad(mutex_validate(mutex));
328 ut_a(mutex_get_waiters(mutex) == 0);
330 #ifdef UNIV_MEM_DEBUG
331 if (mutex == &mem_hash_mutex) {
340 #ifdef UNIV_SYNC_DEBUG
341 && mutex != &sync_thread_mutex
360 #ifdef UNIV_MEM_DEBUG
363 #if !defined(HAVE_ATOMIC_BUILTINS)
390 ut_ad(mutex_validate(mutex));
392 if (!mutex_test_and_set(mutex)) {
395 #ifdef UNIV_SYNC_DEBUG
396 mutex_set_debug_info(mutex, file_name, line);
416 ut_a(mutex->magic_n == MUTEX_MAGIC_N);
431 ut_ad(mutex_validate(mutex));
466 const char* file_name,
473 ib_int64_t lstart_time = 0, lfinish_time;
477 uint timer_started = 0;
485 mutex_spin_wait_count++;
498 ut_d(mutex->count_spin_loop++);
501 if (srv_spin_wait_delay) {
510 mutex->count_os_yield++;
511 #ifndef UNIV_HOTBACKUP
512 if (timed_mutexes && timer_started == 0) {
514 lstart_time= (ib_int64_t)sec * 1000000 + ms;
522 #ifdef UNIV_SRV_PRINT_LATCH_WAITS
524 "Thread %lu spin wait mutex at %p"
525 " cfile %s cline %lu rnds %lu\n",
530 mutex_spin_round_count += i;
532 ut_d(mutex->count_spin_rounds += i);
534 if (mutex_test_and_set(mutex) == 0) {
538 #ifdef UNIV_SYNC_DEBUG
539 mutex_set_debug_info(mutex, file_name, line);
559 SYNC_MUTEX, file_name, line, &index);
567 mutex_set_waiters(mutex, 1);
570 for (i = 0; i < 4; i++) {
571 if (mutex_test_and_set(mutex) == 0) {
577 #ifdef UNIV_SYNC_DEBUG
578 mutex_set_debug_info(mutex, file_name, line);
581 #ifdef UNIV_SRV_PRINT_LATCH_WAITS
582 fprintf(stderr,
"Thread %lu spin wait succeeds at 2:"
600 #ifdef UNIV_SRV_PRINT_LATCH_WAITS
602 "Thread %lu OS wait mutex at %p cfile %s cline %lu rnds %lu\n",
607 mutex_os_wait_count++;
612 #ifndef UNIV_HOTBACKUP
613 if (timed_mutexes == 1 && timer_started == 0) {
615 lstart_time= (ib_int64_t)sec * 1000000 + ms;
626 if (timed_mutexes == 1 && timer_started==1) {
628 lfinish_time= (ib_int64_t)sec * 1000000 + ms;
630 ltime_diff= (ulint) (lfinish_time - lstart_time);
631 mutex->lspent_time += ltime_diff;
633 if (mutex->lmax_spent_time < ltime_diff) {
634 mutex->lmax_spent_time= ltime_diff;
649 mutex_set_waiters(mutex, 0);
657 #ifdef UNIV_SYNC_DEBUG
662 mutex_set_debug_info(
665 const char* file_name,
671 sync_thread_add_level(mutex, mutex->level);
673 mutex->file_name = file_name;
681 mutex_get_debug_info(
684 const char** file_name,
691 *file_name = mutex->file_name;
693 *thread_id = mutex->thread_id;
700 mutex_list_print_info(
705 const char* file_name;
712 "----------\n", file);
714 mutex_enter(&mutex_list_mutex);
718 while (mutex != NULL) {
722 mutex_get_debug_info(mutex, &file_name, &line,
725 "Locked mutex: addr %p thread %ld"
726 " file %s line %ld\n",
734 fprintf(file,
"Total number of mutexes %ld\n", count);
736 mutex_exit(&mutex_list_mutex);
744 mutex_n_reserved(
void)
750 mutex_enter(&mutex_list_mutex);
754 while (mutex != NULL) {
763 mutex_exit(&mutex_list_mutex);
780 return(mutex_n_reserved() + rw_lock_n_locked() == 0);
788 sync_thread_level_arrays_get_nth(
792 ut_ad(n < OS_THREAD_MAX_N);
794 return(sync_thread_level_arrays + n);
802 sync_thread_level_arrays_find_slot(
void)
812 for (i = 0; i < OS_THREAD_MAX_N; i++) {
814 slot = sync_thread_level_arrays_get_nth(i);
830 sync_thread_level_arrays_find_free(
void)
837 for (i = 0; i < OS_THREAD_MAX_N; i++) {
839 slot = sync_thread_level_arrays_get_nth(i);
841 if (slot->
levels == NULL) {
855 sync_thread_levels_get_nth(
861 ut_ad(n < SYNC_THREAD_N_LEVELS);
872 sync_thread_levels_g(
884 for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
886 slot = sync_thread_levels_get_nth(arr, i);
888 if (slot->
latch != NULL) {
889 if (slot->
level <= limit) {
900 "InnoDB: sync levels should be"
901 " > %lu but a level is %lu\n",
902 (ulong) limit, (ulong) slot->
level);
904 if (mutex->magic_n == MUTEX_MAGIC_N) {
906 "Mutex created at %s %lu\n",
908 (ulong) mutex->
cline);
911 const char* file_name;
915 mutex_get_debug_info(
920 "InnoDB: Locked mutex:"
921 " addr %p thread %ld"
922 " file %s line %ld\n",
929 fputs(
"Not locked\n", stderr);
948 sync_thread_levels_contain(
957 for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
959 slot = sync_thread_levels_get_nth(arr, i);
961 if (slot->
latch != NULL) {
962 if (slot->
level == level) {
978 sync_thread_levels_contains(
988 if (!sync_order_checks_on) {
993 mutex_enter(&sync_thread_mutex);
995 thread_slot = sync_thread_level_arrays_find_slot();
997 if (thread_slot == NULL) {
999 mutex_exit(&sync_thread_mutex);
1004 arr = thread_slot->
levels;
1006 for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
1008 slot = sync_thread_levels_get_nth(arr, i);
1010 if (slot->
latch != NULL && slot->
level == level) {
1012 mutex_exit(&sync_thread_mutex);
1013 return(slot->
latch);
1017 mutex_exit(&sync_thread_mutex);
1027 sync_thread_levels_nonempty_gen(
1029 ibool dict_mutex_allowed)
1039 if (!sync_order_checks_on) {
1044 mutex_enter(&sync_thread_mutex);
1046 thread_slot = sync_thread_level_arrays_find_slot();
1048 if (thread_slot == NULL) {
1050 mutex_exit(&sync_thread_mutex);
1055 arr = thread_slot->
levels;
1057 for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
1059 slot = sync_thread_levels_get_nth(arr, i);
1061 if (slot->
latch != NULL
1062 && (!dict_mutex_allowed
1063 || (slot->
level != SYNC_DICT
1064 && slot->
level != SYNC_DICT_OPERATION))) {
1066 mutex_exit(&sync_thread_mutex);
1069 return(slot->
latch);
1073 mutex_exit(&sync_thread_mutex);
1083 sync_thread_levels_empty(
void)
1086 return(sync_thread_levels_empty_gen(FALSE));
1095 sync_thread_add_level(
1106 if (!sync_order_checks_on) {
1111 if ((latch == (
void*)&sync_thread_mutex)
1112 || (latch == (
void*)&mutex_list_mutex)
1113 || (latch == (
void*)&rw_lock_debug_mutex)
1114 || (latch == (
void*)&rw_lock_list_mutex)) {
1119 if (level == SYNC_LEVEL_VARYING) {
1124 mutex_enter(&sync_thread_mutex);
1126 thread_slot = sync_thread_level_arrays_find_slot();
1128 if (thread_slot == NULL) {
1132 thread_slot = sync_thread_level_arrays_find_free();
1135 thread_slot->
levels = array;
1137 for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
1139 slot = sync_thread_levels_get_nth(array, i);
1145 array = thread_slot->
levels;
1153 case SYNC_NO_ORDER_CHECK:
1154 case SYNC_EXTERN_STORAGE:
1155 case SYNC_TREE_NODE_FROM_HASH:
1158 case SYNC_TRX_SYS_HEADER:
1159 if (srv_is_being_started) {
1168 case SYNC_WORK_QUEUE:
1170 case SYNC_LOG_FLUSH_ORDER:
1171 case SYNC_THR_LOCAL:
1172 case SYNC_ANY_LATCH:
1173 case SYNC_FILE_FORMAT_TAG:
1174 case SYNC_DOUBLEWRITE:
1175 case SYNC_SEARCH_SYS:
1176 case SYNC_SEARCH_SYS_CONF:
1177 case SYNC_TRX_LOCK_HEAP:
1179 case SYNC_IBUF_BITMAP_MUTEX:
1182 case SYNC_PURGE_LATCH:
1183 case SYNC_PURGE_SYS:
1184 case SYNC_DICT_AUTOINC_MUTEX:
1185 case SYNC_DICT_OPERATION:
1186 case SYNC_DICT_HEADER:
1187 case SYNC_TRX_I_S_RWLOCK:
1188 case SYNC_TRX_I_S_LAST_READ:
1189 if (!sync_thread_levels_g(array, level, TRUE)) {
1191 "InnoDB: sync_thread_levels_g(array, %lu)"
1192 " does not hold!\n", level);
1196 case SYNC_BUF_FLUSH_LIST:
1200 if (!sync_thread_levels_g(array, level-1, TRUE)) {
1202 "InnoDB: sync_thread_levels_g(array, %lu)"
1203 " does not hold!\n", level-1);
1208 case SYNC_BUF_BLOCK:
1212 if (!sync_thread_levels_g(array, level, FALSE)) {
1213 ut_a(sync_thread_levels_g(array, level - 1, TRUE));
1214 ut_a(sync_thread_levels_contain(array, SYNC_BUF_POOL));
1218 if (sync_thread_levels_contain(array, SYNC_KERNEL)) {
1219 ut_a(sync_thread_levels_g(array, SYNC_REC_LOCK - 1,
1222 ut_a(sync_thread_levels_g(array, SYNC_REC_LOCK, TRUE));
1225 case SYNC_IBUF_BITMAP:
1229 if (sync_thread_levels_contain(array,
1230 SYNC_IBUF_BITMAP_MUTEX)) {
1231 ut_a(sync_thread_levels_g(array, SYNC_IBUF_BITMAP - 1,
1237 ut_a(srv_is_being_started
1238 || sync_thread_levels_g(array, SYNC_IBUF_BITMAP,
1243 ut_a(sync_thread_levels_contain(array, SYNC_FSP));
1246 ut_a(sync_thread_levels_contain(array, SYNC_FSP)
1247 || sync_thread_levels_g(array, SYNC_FSP, TRUE));
1249 case SYNC_TRX_UNDO_PAGE:
1250 ut_a(sync_thread_levels_contain(array, SYNC_TRX_UNDO)
1251 || sync_thread_levels_contain(array, SYNC_RSEG)
1252 || sync_thread_levels_contain(array, SYNC_PURGE_SYS)
1253 || sync_thread_levels_g(array, SYNC_TRX_UNDO_PAGE, TRUE));
1255 case SYNC_RSEG_HEADER:
1256 ut_a(sync_thread_levels_contain(array, SYNC_RSEG));
1258 case SYNC_RSEG_HEADER_NEW:
1259 ut_a(sync_thread_levels_contain(array, SYNC_KERNEL)
1260 && sync_thread_levels_contain(array, SYNC_FSP_PAGE));
1262 case SYNC_TREE_NODE:
1263 ut_a(sync_thread_levels_contain(array, SYNC_INDEX_TREE)
1264 || sync_thread_levels_contain(array, SYNC_DICT_OPERATION)
1265 || sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE));
1267 case SYNC_TREE_NODE_NEW:
1268 ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE)
1269 || sync_thread_levels_contain(array, SYNC_IBUF_MUTEX));
1271 case SYNC_INDEX_TREE:
1272 if (sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)
1273 && sync_thread_levels_contain(array, SYNC_FSP)) {
1274 ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1,
1277 ut_a(sync_thread_levels_g(array, SYNC_TREE_NODE - 1,
1281 case SYNC_IBUF_MUTEX:
1282 ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, TRUE));
1284 case SYNC_IBUF_PESS_INSERT_MUTEX:
1285 ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE));
1286 ut_a(!sync_thread_levels_contain(array, SYNC_IBUF_MUTEX));
1288 case SYNC_IBUF_HEADER:
1289 ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE));
1290 ut_a(!sync_thread_levels_contain(array, SYNC_IBUF_MUTEX));
1291 ut_a(!sync_thread_levels_contain(array,
1292 SYNC_IBUF_PESS_INSERT_MUTEX));
1296 ut_a(buf_debug_prints
1297 || sync_thread_levels_g(array, SYNC_DICT, TRUE));
1299 ut_a(sync_thread_levels_g(array, SYNC_DICT, TRUE));
1306 for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
1308 slot = sync_thread_levels_get_nth(array, i);
1310 if (slot->
latch == NULL) {
1311 slot->
latch = latch;
1312 slot->
level = level;
1318 ut_a(i < SYNC_THREAD_N_LEVELS);
1320 mutex_exit(&sync_thread_mutex);
1330 sync_thread_reset_level(
1339 if (!sync_order_checks_on) {
1344 if ((latch == (
void*)&sync_thread_mutex)
1345 || (latch == (
void*)&mutex_list_mutex)
1346 || (latch == (
void*)&rw_lock_debug_mutex)
1347 || (latch == (
void*)&rw_lock_list_mutex)) {
1352 mutex_enter(&sync_thread_mutex);
1354 thread_slot = sync_thread_level_arrays_find_slot();
1356 if (thread_slot == NULL) {
1360 mutex_exit(&sync_thread_mutex);
1364 array = thread_slot->
levels;
1366 for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
1368 slot = sync_thread_levels_get_nth(array, i);
1370 if (slot->
latch == latch) {
1373 mutex_exit(&sync_thread_mutex);
1379 if (((
mutex_t*) latch)->magic_n != MUTEX_MAGIC_N) {
1384 if (rw_lock->level == SYNC_LEVEL_VARYING) {
1385 mutex_exit(&sync_thread_mutex);
1393 mutex_exit(&sync_thread_mutex);
1406 #ifdef UNIV_SYNC_DEBUG
1420 #ifdef UNIV_SYNC_DEBUG
1424 sync_thread_level_arrays =
ut_malloc(OS_THREAD_MAX_N
1426 for (i = 0; i < OS_THREAD_MAX_N; i++) {
1428 thread_slot = sync_thread_level_arrays_get_nth(i);
1429 thread_slot->
levels = NULL;
1436 SYNC_NO_ORDER_CHECK);
1437 #ifdef UNIV_SYNC_DEBUG
1438 mutex_create(sync_thread_mutex_key, &sync_thread_mutex,
1439 SYNC_NO_ORDER_CHECK);
1445 mutex_create(rw_lock_list_mutex_key, &rw_lock_list_mutex,
1446 SYNC_NO_ORDER_CHECK);
1448 #ifdef UNIV_SYNC_DEBUG
1449 mutex_create(rw_lock_debug_mutex_key, &rw_lock_debug_mutex,
1450 SYNC_NO_ORDER_CHECK);
1453 rw_lock_debug_waiters = FALSE;
1472 #ifdef UNIV_MEM_DEBUG
1473 if (mutex == &mem_hash_mutex) {
1483 #ifdef UNIV_SYNC_DEBUG
1484 mutex_free(&sync_thread_mutex);
1487 sync_order_checks_on = FALSE;
1501 #ifdef UNIV_SYNC_DEBUG
1502 fprintf(file,
"Mutex exits %llu, rws exits %llu, rwx exits %llu\n",
1507 "Mutex spin waits %"PRId64
", rounds %"PRId64
", "
1508 "OS waits %"PRId64
"\n"
1509 "RW-shared spins %"PRId64
", rounds %"PRId64
", OS waits %"PRId64
";"
1510 " RW-excl spins %"PRId64
", rounds %"PRId64
", OS waits %"PRId64
"\n",
1511 mutex_spin_wait_count,
1512 mutex_spin_round_count,
1513 mutex_os_wait_count,
1522 "Spin rounds per wait: %.2f mutex, %.2f RW-shared, "
1524 (
double) mutex_spin_round_count /
1525 (mutex_spin_wait_count ? mutex_spin_wait_count : 1),
1540 #ifdef UNIV_SYNC_DEBUG
1541 mutex_list_print_info(file);
1543 rw_lock_list_print_info(file);