Example #1
0
/***********************************************************//**
Fetches an undo log record and does the undo for the recorded operation.
If none left, or a partial rollback completed, returns control to the
parent node, which is always a query thread node.
@return	DB_SUCCESS if operation successfully completed, else error code */
static
ulint
row_undo(
/*=====*/
	undo_node_t*	node,	/*!< in: row undo node */
	que_thr_t*	thr)	/*!< in: query thread */
{
	ulint		err;
	trx_t*		trx;
	roll_ptr_t	roll_ptr;
	ibool		locked_data_dict;

	ut_ad(node && thr);

	trx = node->trx;

	if (node->state == UNDO_NODE_FETCH_NEXT) {

		node->undo_rec = trx_roll_pop_top_rec_of_trx(trx,
							     trx->roll_limit,
							     &roll_ptr,
							     node->heap);
		if (!node->undo_rec) {
			/* Rollback completed for this query thread */

			thr->run_node = que_node_get_parent(node);

			return(DB_SUCCESS);
		}

		node->roll_ptr = roll_ptr;
		node->undo_no = trx_undo_rec_get_undo_no(node->undo_rec);

		if (trx_undo_roll_ptr_is_insert(roll_ptr)) {

			node->state = UNDO_NODE_INSERT;
		} else {
			node->state = UNDO_NODE_MODIFY;
		}

	} else if (node->state == UNDO_NODE_PREV_VERS) {

		/* Undo should be done to the same clustered index record
		again in this same rollback, restoring the previous version */

		roll_ptr = node->new_roll_ptr;

		node->undo_rec = trx_undo_get_undo_rec_low(roll_ptr,
							   node->heap);
		node->roll_ptr = roll_ptr;
		node->undo_no = trx_undo_rec_get_undo_no(node->undo_rec);

		if (trx_undo_roll_ptr_is_insert(roll_ptr)) {

			node->state = UNDO_NODE_INSERT;
		} else {
			node->state = UNDO_NODE_MODIFY;
		}
	}

	/* Prevent DROP TABLE etc. while we are rolling back this row.
	If we are doing a TABLE CREATE or some other dictionary operation,
	then we already have dict_operation_lock locked in x-mode. Do not
	try to lock again, because that would cause a hang. */

	locked_data_dict = (trx->dict_operation_lock_mode == 0);

	if (locked_data_dict) {

		row_mysql_freeze_data_dictionary(trx);
	}

	if (node->state == UNDO_NODE_INSERT) {

		err = row_undo_ins(node);

		node->state = UNDO_NODE_FETCH_NEXT;
	} else {
		ut_ad(node->state == UNDO_NODE_MODIFY);
		err = row_undo_mod(node, thr);
	}

	if (locked_data_dict) {

		row_mysql_unfreeze_data_dictionary(trx);
	}

	/* Do some cleanup */
	btr_pcur_close(&(node->pcur));

	mem_heap_empty(node->heap);

	thr->run_node = node;

	return(err);
}
Example #2
0
/***********************************************************//**
Parses the row reference and other info in a modify undo log record.
@return TRUE if purge operation required: NOTE that then the CALLER
must unfreeze data dictionary! */
static
ibool
row_purge_parse_undo_rec(
    /*=====================*/
    purge_node_t*	node,	/*!< in: row undo node */
    ibool*		updated_extern,
    /*!< out: TRUE if an externally stored field
    was updated */
    que_thr_t*	thr)	/*!< in: query thread */
{
    dict_index_t*	clust_index;
    byte*		ptr;
    trx_t*		trx;
    undo_no_t	undo_no;
    table_id_t	table_id;
    trx_id_t	trx_id;
    roll_ptr_t	roll_ptr;
    ulint		info_bits;
    ulint		type;

    ut_ad(node && thr);

    trx = thr_get_trx(thr);

    ptr = trx_undo_rec_get_pars(
              node->undo_rec, &type, &node->cmpl_info,
              updated_extern, &undo_no, &table_id);
    node->rec_type = type;

    if (type == TRX_UNDO_UPD_DEL_REC && !(*updated_extern)) {

        return(FALSE);
    }

    ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr,
                                           &info_bits);
    node->table = NULL;

    if (type == TRX_UNDO_UPD_EXIST_REC
            && node->cmpl_info & UPD_NODE_NO_ORD_CHANGE
            && !(*updated_extern)) {

        /* Purge requires no changes to indexes: we may return */

        return(FALSE);
    }

    /* Prevent DROP TABLE etc. from running when we are doing the purge
    for this row */

    row_mysql_freeze_data_dictionary(trx);

    mutex_enter(&(dict_sys->mutex));

    node->table = dict_table_get_on_id_low(table_id);

    mutex_exit(&(dict_sys->mutex));

    if (node->table == NULL) {
        /* The table has been dropped: no need to do purge */
err_exit:
        row_mysql_unfreeze_data_dictionary(trx);
        return(FALSE);
    }

    if (node->table->ibd_file_missing) {
        /* We skip purge of missing .ibd files */

        node->table = NULL;

        goto err_exit;
    }

    clust_index = dict_table_get_first_index(node->table);

    if (clust_index == NULL) {
        /* The table was corrupt in the data dictionary */

        goto err_exit;
    }

    ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
                                   node->heap);

    ptr = trx_undo_update_rec_get_update(ptr, clust_index, type, trx_id,
                                         roll_ptr, info_bits, trx,
                                         node->heap, &(node->update));

    /* Read to the partial row the fields that occur in indexes */

    if (!(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
        ptr = trx_undo_rec_get_partial_row(
                  ptr, clust_index, &node->row,
                  type == TRX_UNDO_UPD_DEL_REC,
                  node->heap);
    }

    return(TRUE);
}