int trx_weight_cmp( /*===========*/ /* out: <0, 0 or >0; similar to strcmp(3) */ trx_t* a, /* in: the first transaction to be compared */ trx_t* b) /* in: the second transaction to be compared */ { ibool a_notrans_edit; ibool b_notrans_edit; /* If mysql_thd is NULL for a transaction we assume that it has not edited non-transactional tables. */ a_notrans_edit = a->mysql_thd != NULL && thd_has_edited_nontrans_tables(a->mysql_thd); b_notrans_edit = b->mysql_thd != NULL && thd_has_edited_nontrans_tables(b->mysql_thd); if (a_notrans_edit && !b_notrans_edit) { return(1); } if (!a_notrans_edit && b_notrans_edit) { return(-1); } /* Either both had edited non-transactional tables or both had not, we fall back to comparing the number of altered/locked rows. */ #if 0 fprintf(stderr, "%s TRX_WEIGHT(a): %lld+%lu, TRX_WEIGHT(b): %lld+%lu\n", __func__, ut_conv_dulint_to_longlong(a->undo_no), UT_LIST_GET_LEN(a->trx_locks), ut_conv_dulint_to_longlong(b->undo_no), UT_LIST_GET_LEN(b->trx_locks)); #endif #define TRX_WEIGHT(t) \ ut_dulint_add((t)->undo_no, UT_LIST_GET_LEN((t)->trx_locks)) return(ut_dulint_cmp(TRX_WEIGHT(a), TRX_WEIGHT(b))); }
/***************************************************************//** Builds an index definition row to insert. @return DB_SUCCESS or error code */ static ulint dict_build_index_def_step( /*======================*/ que_thr_t* thr, /*!< in: query thread */ ind_node_t* node) /*!< in: index create node */ { dict_table_t* table; dict_index_t* index; dtuple_t* row; trx_t* trx; ut_ad(mutex_own(&(dict_sys->mutex))); trx = thr_get_trx(thr); index = node->index; table = dict_table_get_low(index->table_name); if (table == NULL) { return(DB_TABLE_NOT_FOUND); } trx->table_id = table->id; node->table = table; ut_ad((UT_LIST_GET_LEN(table->indexes) > 0) || dict_index_is_clust(index)); dict_hdr_get_new_id(NULL, &index->id, NULL); /* Inherit the space id from the table; we store all indexes of a table in the same tablespace */ index->space = table->space; node->page_no = FIL_NULL; row = dict_create_sys_indexes_tuple(index, node->heap); node->ind_row = row; ins_node_set_new_row(node->ind_def, row); /* Note that the index was created by this transaction. */ index->trx_id = (ib_uint64_t) ut_conv_dulint_to_longlong(trx->id); return(DB_SUCCESS); }
/**********************************************************************//** This function is used to find number of prepared transactions and their transaction objects for a recovery. @return number of prepared transactions stored in xid_list */ UNIV_INTERN int trx_recover_for_mysql( /*==================*/ XID* xid_list, /*!< in/out: prepared transactions */ ulint len) /*!< in: number of slots in xid_list */ { trx_t* trx; ulint count = 0; ut_ad(xid_list); ut_ad(len); /* We should set those transactions which are in the prepared state to the xid_list */ mutex_enter(&kernel_mutex); trx = UT_LIST_GET_FIRST(trx_sys->trx_list); while (trx) { if (trx->conc_state == TRX_PREPARED) { xid_list[count] = trx->xid; if (count == 0) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Starting recovery for" " XA transactions...\n"); } ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Transaction " TRX_ID_FMT " in" " prepared state after recovery\n", TRX_ID_PREP_PRINTF(trx->id)); ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Transaction contains changes" " to %lu rows\n", (ulong) ut_conv_dulint_to_longlong( trx->undo_no)); count++; if (count == len) { break; } } trx = UT_LIST_GET_NEXT(trx_list, trx); } mutex_exit(&kernel_mutex); if (count > 0){ ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: %lu transactions in prepared state" " after recovery\n", (ulong) count); } return ((int) count); }
/*******************************************************************//** 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); }