/*******************************************************************//** Fills i_s_trx_row_t object. If memory can not be allocated then FALSE is returned. @return FALSE if allocation fails */ static ibool fill_trx_row( /*=========*/ i_s_trx_row_t* row, /*!< out: result object that's filled */ const trx_t* trx, /*!< in: transaction to get data from */ const i_s_locks_row_t* requested_lock_row,/*!< in: pointer to the corresponding row in innodb_locks if trx is waiting or NULL if trx is not waiting */ trx_i_s_cache_t* cache) /*!< in/out: cache into which to copy volatile strings */ { row->trx_id = trx_get_id(trx); row->trx_started = (ib_time_t) trx->start_time; row->trx_state = trx_get_que_state_str(trx); if (trx->wait_lock != NULL) { ut_a(requested_lock_row != NULL); row->requested_lock_row = requested_lock_row; row->trx_wait_started = (ib_time_t) trx->wait_started; } else { ut_a(requested_lock_row == NULL); row->requested_lock_row = NULL; row->trx_wait_started = 0; } row->trx_weight = (ullint) ut_conv_dulint_to_longlong(TRX_WEIGHT(trx)); if (trx->mysql_thd != NULL) { row->trx_mysql_thread_id = thd_get_thread_id(trx->mysql_thd); } else { /* For internal transactions e.g., purge and transactions being recovered at startup there is no associated MySQL thread data structure. */ row->trx_mysql_thread_id = 0; } if (trx->mysql_query_str != NULL && *trx->mysql_query_str != NULL) { if (strlen(*trx->mysql_query_str) > TRX_I_S_TRX_QUERY_MAX_LEN) { char query[TRX_I_S_TRX_QUERY_MAX_LEN + 1]; memcpy(query, *trx->mysql_query_str, TRX_I_S_TRX_QUERY_MAX_LEN); query[TRX_I_S_TRX_QUERY_MAX_LEN] = '\0'; row->trx_query = ha_storage_put_memlim( cache->storage, query, TRX_I_S_TRX_QUERY_MAX_LEN + 1, MAX_ALLOWED_FOR_STORAGE(cache)); } else { row->trx_query = ha_storage_put_str_memlim( cache->storage, *trx->mysql_query_str, MAX_ALLOWED_FOR_STORAGE(cache)); } if (row->trx_query == NULL) { return(FALSE); } } else { row->trx_query = NULL; } return(TRUE); }
/*******************************************************************//** Fills the "lock_data" member of i_s_locks_row_t object. If memory can not be allocated then FALSE is returned. @return FALSE if allocation fails */ static ibool fill_lock_data( /*===========*/ const char** lock_data,/*!< out: "lock_data" to fill */ const lock_t* lock, /*!< in: lock used to find the data */ ulint heap_no,/*!< in: rec num used to find the data */ trx_i_s_cache_t* cache) /*!< in/out: cache where to store volatile data */ { mtr_t mtr; const buf_block_t* block; const page_t* page; const rec_t* rec; ut_a(lock_get_type(lock) == LOCK_REC); mtr_start(&mtr); block = buf_page_try_get(lock_rec_get_space_id(lock), lock_rec_get_page_no(lock), &mtr); if (block == NULL) { *lock_data = NULL; mtr_commit(&mtr); return(TRUE); } page = (const page_t*) buf_block_get_frame(block); rec = page_find_rec_with_heap_no(page, heap_no); if (page_rec_is_infimum(rec)) { *lock_data = ha_storage_put_str_memlim( cache->storage, "infimum pseudo-record", MAX_ALLOWED_FOR_STORAGE(cache)); } else if (page_rec_is_supremum(rec)) { *lock_data = ha_storage_put_str_memlim( cache->storage, "supremum pseudo-record", MAX_ALLOWED_FOR_STORAGE(cache)); } else { const dict_index_t* index; ulint n_fields; mem_heap_t* heap; ulint offsets_onstack[REC_OFFS_NORMAL_SIZE]; ulint* offsets; char buf[TRX_I_S_LOCK_DATA_MAX_LEN]; ulint buf_used; ulint i; rec_offs_init(offsets_onstack); offsets = offsets_onstack; index = lock_rec_get_index(lock); n_fields = dict_index_get_n_unique(index); ut_a(n_fields > 0); heap = NULL; offsets = rec_get_offsets(rec, index, offsets, n_fields, &heap); /* format and store the data */ buf_used = 0; for (i = 0; i < n_fields; i++) { buf_used += put_nth_field( buf + buf_used, sizeof(buf) - buf_used, i, index, rec, offsets) - 1; } *lock_data = (const char*) ha_storage_put_memlim( cache->storage, buf, buf_used + 1, MAX_ALLOWED_FOR_STORAGE(cache)); if (UNIV_UNLIKELY(heap != NULL)) { /* this means that rec_get_offsets() has created a new heap and has stored offsets in it; check that this is really the case and free the heap */ ut_a(offsets != offsets_onstack); mem_heap_free(heap); } } mtr_commit(&mtr); if (*lock_data == NULL) { return(FALSE); } return(TRUE); }
/*******************************************************************//** Fills i_s_trx_row_t object. If memory can not be allocated then FALSE is returned. @return FALSE if allocation fails */ static ibool fill_trx_row( /*=========*/ i_s_trx_row_t* row, /*!< out: result object that's filled */ const trx_t* trx, /*!< in: transaction to get data from */ const i_s_locks_row_t* requested_lock_row,/*!< in: pointer to the corresponding row in innodb_locks if trx is waiting or NULL if trx is not waiting */ trx_i_s_cache_t* cache) /*!< in/out: cache into which to copy volatile strings */ { const char* stmt; size_t stmt_len; const char* s; ut_ad(mutex_own(&kernel_mutex)); row->trx_id = trx->id; row->trx_started = (ib_time_t) trx->start_time; row->trx_state = trx_get_que_state_str(trx); row->requested_lock_row = requested_lock_row; ut_ad(requested_lock_row == NULL || i_s_locks_row_validate(requested_lock_row)); if (trx->wait_lock != NULL) { ut_a(requested_lock_row != NULL); row->trx_wait_started = (ib_time_t) trx->wait_started; } else { ut_a(requested_lock_row == NULL); row->trx_wait_started = 0; } row->trx_weight = (ullint) TRX_WEIGHT(trx); if (trx->mysql_thd == NULL) { /* For internal transactions e.g., purge and transactions being recovered at startup there is no associated MySQL thread data structure. */ row->trx_mysql_thread_id = 0; row->trx_query = NULL; goto thd_done; } row->trx_mysql_thread_id = thd_get_thread_id(trx->mysql_thd); stmt = innobase_get_stmt(trx->mysql_thd, &stmt_len); if (stmt != NULL) { char query[TRX_I_S_TRX_QUERY_MAX_LEN + 1]; if (stmt_len > TRX_I_S_TRX_QUERY_MAX_LEN) { stmt_len = TRX_I_S_TRX_QUERY_MAX_LEN; } memcpy(query, stmt, stmt_len); query[stmt_len] = '\0'; row->trx_query = ha_storage_put_memlim( cache->storage, query, stmt_len + 1, MAX_ALLOWED_FOR_STORAGE(cache)); row->trx_query_cs = innobase_get_charset(trx->mysql_thd); if (row->trx_query == NULL) { return(FALSE); } } else { row->trx_query = NULL; } thd_done: s = trx->op_info; if (s != NULL && s[0] != '\0') { TRX_I_S_STRING_COPY(s, row->trx_operation_state, TRX_I_S_TRX_OP_STATE_MAX_LEN, cache); if (row->trx_operation_state == NULL) { return(FALSE); } } else { row->trx_operation_state = NULL; } row->trx_tables_in_use = trx->n_mysql_tables_in_use; row->trx_tables_locked = trx->mysql_n_tables_locked; row->trx_lock_structs = UT_LIST_GET_LEN(trx->trx_locks); row->trx_lock_memory_bytes = mem_heap_get_size(trx->lock_heap); row->trx_rows_locked = lock_number_of_rows_locked(trx); row->trx_rows_modified = trx->undo_no; row->trx_concurrency_tickets = trx->n_tickets_to_enter_innodb; switch (trx->isolation_level) { case TRX_ISO_READ_UNCOMMITTED: row->trx_isolation_level = "READ UNCOMMITTED"; break; case TRX_ISO_READ_COMMITTED: row->trx_isolation_level = "READ COMMITTED"; break; case TRX_ISO_REPEATABLE_READ: row->trx_isolation_level = "REPEATABLE READ"; break; case TRX_ISO_SERIALIZABLE: row->trx_isolation_level = "SERIALIZABLE"; break; /* Should not happen as TRX_ISO_READ_COMMITTED is default */ default: row->trx_isolation_level = "UNKNOWN"; } row->trx_unique_checks = (ibool) trx->check_unique_secondary; row->trx_foreign_key_checks = (ibool) trx->check_foreigns; s = trx->detailed_error; if (s != NULL && s[0] != '\0') { TRX_I_S_STRING_COPY(s, row->trx_foreign_key_error, TRX_I_S_TRX_FK_ERROR_MAX_LEN, cache); if (row->trx_foreign_key_error == NULL) { return(FALSE); } } else { row->trx_foreign_key_error = NULL; } row->trx_has_search_latch = (ibool) trx->has_search_latch; row->trx_search_latch_timeout = trx->search_latch_timeout; return(TRUE); }