Ejemplo n.º 1
0
void
row_purge(
    /*======*/
    purge_node_t*	node,	/*!< in: row purge node */
    que_thr_t*	thr)	/*!< in: query thread */
{
    ibool		updated_extern;

    ut_ad(node);
    ut_ad(thr);

    node->undo_rec = trx_purge_fetch_next_rec(&node->roll_ptr,
                     &node->reservation,
                     node->heap);
    if (!node->undo_rec) {
        /* Purge completed for this query thread */

        thr->run_node = que_node_get_parent(node);

        return;
    }

    if (node->undo_rec != &trx_purge_dummy_rec
            && row_purge_parse_undo_rec(node, &updated_extern, thr)) {
        node->found_clust = FALSE;

        node->index = dict_table_get_next_index(
                          dict_table_get_first_index(node->table));

        if (node->rec_type == TRX_UNDO_DEL_MARK_REC) {
            row_purge_del_mark(node);

        } else if (updated_extern
                   || node->rec_type == TRX_UNDO_UPD_EXIST_REC) {

            row_purge_upd_exist_or_extern(thr, node);
        }

        if (node->found_clust) {
            btr_pcur_close(&(node->pcur));
        }

        row_mysql_unfreeze_data_dictionary(thr_get_trx(thr));
    }

    /* Do some cleanup */
    trx_purge_rec_release(node->reservation);
    mem_heap_empty(node->heap);

    thr->run_node = node;
}
Ejemplo n.º 2
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);
}
Ejemplo n.º 3
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);
}
Ejemplo n.º 4
0
/***************************************************************
Fetches an undo log record and does the purge for the recorded operation.
If none left, or the current purge completed, returns the control to the
parent node, which is always a query thread node. */
static
ulint
row_purge(
/*======*/
				/* out: DB_SUCCESS if operation successfully
				completed, else error code */
	purge_node_t*	node,	/* in: row purge node */
	que_thr_t*	thr)	/* in: query thread */
{
	dulint	roll_ptr;
	ibool	purge_needed;
	ibool	updated_extern;
	trx_t*	trx;

	ut_ad(node && thr);

	trx = thr_get_trx(thr);

	node->undo_rec = trx_purge_fetch_next_rec(&roll_ptr,
						  &(node->reservation),
						  node->heap);
	if (!node->undo_rec) {
		/* Purge completed for this query thread */

		thr->run_node = que_node_get_parent(node);

		return(DB_SUCCESS);
	}

	node->roll_ptr = roll_ptr;

	if (node->undo_rec == &trx_purge_dummy_rec) {
		purge_needed = FALSE;
	} else {
		purge_needed = row_purge_parse_undo_rec(node, &updated_extern,
							thr);
		/* If purge_needed == TRUE, we must also remember to unfreeze
		data dictionary! */
	}

	if (purge_needed) {
		node->found_clust = FALSE;

		node->index = dict_table_get_next_index(
			dict_table_get_first_index(node->table));

		if (node->rec_type == TRX_UNDO_DEL_MARK_REC) {
			row_purge_del_mark(node);

		} else if (updated_extern
			   || node->rec_type == TRX_UNDO_UPD_EXIST_REC) {

			row_purge_upd_exist_or_extern(node);
		}

		if (node->found_clust) {
			btr_pcur_close(&(node->pcur));
		}

		row_mysql_unfreeze_data_dictionary(trx);
	}

	/* Do some cleanup */
	trx_purge_rec_release(node->reservation);
	mem_heap_empty(node->heap);

	thr->run_node = node;

	return(DB_SUCCESS);
}