Beispiel #1
0
trx_rseg_t*
trx_rseg_create(
/*============*/
				/* out: the created segment object, NULL if
				fail */
	ulint	space,		/* in: space id */
	ulint	max_size,	/* in: max size in pages */
	ulint*	id,		/* out: rseg id */
	mtr_t*	mtr)		/* in: mtr */
{
	ulint		page_no;
	trx_rseg_t*	rseg;

	mtr_x_lock(fil_space_get_latch(space), mtr);	
	mutex_enter(&kernel_mutex);

	page_no = trx_rseg_header_create(space, max_size, id, mtr);

	if (page_no == FIL_NULL) {

		mutex_exit(&kernel_mutex);
		return(NULL);
	}

	rseg = trx_rseg_mem_create(*id, space, page_no, mtr);

	mutex_exit(&kernel_mutex);

	return(rseg);
}
/****************************************************************//**
Creates a new rollback segment to the database.
@return	the created segment object, NULL if fail */
UNIV_INTERN
trx_rseg_t*
trx_rseg_create(
/*============*/
	ulint	space,		/*!< in: space id */
	ulint	max_size,	/*!< in: max size in pages */
	ulint*	id,		/*!< out: rseg id */
	mtr_t*	mtr)		/*!< in: mtr */
{
	ulint		flags;
	ulint		zip_size;
	ulint		page_no;
	trx_rseg_t*	rseg;

	mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
	zip_size = dict_table_flags_to_zip_size(flags);
	mutex_enter(&kernel_mutex);

	page_no = trx_rseg_header_create(space, zip_size, max_size, id, mtr);

	if (page_no == FIL_NULL) {

		mutex_exit(&kernel_mutex);
		return(NULL);
	}

	rseg = trx_rseg_mem_create(*id, space, zip_size, page_no, mtr);

	mutex_exit(&kernel_mutex);

	return(rseg);
}
Beispiel #3
0
/*********************************************************************
Creates a rollback segment.
@return pointer to new rollback segment if create successful */
UNIV_INTERN
trx_rseg_t*
trx_rseg_create(void)
/*=================*/
{
	mtr_t		mtr;
	ulint		slot_no;
	trx_rseg_t*	rseg = NULL;

	mtr_start(&mtr);

	/* To obey the latching order, acquire the file space
	x-latch before the kernel mutex. */
	mtr_x_lock(fil_space_get_latch(TRX_SYS_SPACE, NULL), &mtr);

	mutex_enter(&kernel_mutex);

	slot_no = trx_sysf_rseg_find_free(&mtr);

	if (slot_no != ULINT_UNDEFINED) {
		ulint		space;
		ulint		page_no;
		ulint		zip_size;
		trx_sysf_t*	sys_header;

		page_no = trx_rseg_header_create(
			TRX_SYS_SPACE, 0, ULINT_MAX, slot_no, &mtr);

		ut_a(page_no != FIL_NULL);

		ut_ad(!trx_rseg_get_on_id(slot_no));

		sys_header = trx_sysf_get(&mtr);

		space = trx_sysf_rseg_get_space(sys_header, slot_no, &mtr);

		zip_size = space ? fil_space_get_zip_size(space) : 0;

		rseg = trx_rseg_mem_create(
			slot_no, space, zip_size, page_no, &mtr);
	}

	mutex_exit(&kernel_mutex);
	mtr_commit(&mtr);

	return(rseg);
}
Beispiel #4
0
/***********************************************************//**
Purges an update of an existing record. Also purges an update of a delete
marked record if that record contained an externally stored field. */
static
void
row_purge_upd_exist_or_extern_func(
    /*===============================*/
#ifdef UNIV_DEBUG
    const que_thr_t*thr,	/*!< in: query thread */
#endif /* UNIV_DEBUG */
    purge_node_t*	node)	/*!< in: row purge node */
{
    mem_heap_t*	heap;
    dtuple_t*	entry;
    dict_index_t*	index;
    ibool		is_insert;
    ulint		rseg_id;
    ulint		page_no;
    ulint		offset;
    ulint		i;
    mtr_t		mtr;

    ut_ad(node);

    if (node->rec_type == TRX_UNDO_UPD_DEL_REC
            || (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {

        goto skip_secondaries;
    }

    heap = mem_heap_create(1024);

    while (node->index != NULL) {
        dict_table_skip_corrupt_index(node->index);

        if (!node->index) {
            break;
        }

        index = node->index;

        if (row_upd_changes_ord_field_binary(node->index, node->update,
                                             thr, NULL, NULL)) {
            /* Build the older version of the index entry */
            entry = row_build_index_entry(node->row, NULL,
                                          index, heap);
            ut_a(entry);
            row_purge_remove_sec_if_poss(node, index, entry);
        }

        node->index = dict_table_get_next_index(node->index);
    }

    mem_heap_free(heap);

skip_secondaries:
    /* Free possible externally stored fields */
    for (i = 0; i < upd_get_n_fields(node->update); i++) {

        const upd_field_t*	ufield
            = upd_get_nth_field(node->update, i);

        if (dfield_is_ext(&ufield->new_val)) {
            buf_block_t*	block;
            ulint		internal_offset;
            byte*		data_field;

            /* We use the fact that new_val points to
            node->undo_rec and get thus the offset of
            dfield data inside the undo record. Then we
            can calculate from node->roll_ptr the file
            address of the new_val data */

            internal_offset
                = ((const byte*)
                   dfield_get_data(&ufield->new_val))
                  - node->undo_rec;

            ut_a(internal_offset < UNIV_PAGE_SIZE);

            trx_undo_decode_roll_ptr(node->roll_ptr,
                                     &is_insert, &rseg_id,
                                     &page_no, &offset);
            mtr_start(&mtr);

            /* We have to acquire an X-latch to the clustered
            index tree */

            index = dict_table_get_first_index(node->table);

            mtr_x_lock(dict_index_get_lock(index), &mtr);

            /* NOTE: we must also acquire an X-latch to the
            root page of the tree. We will need it when we
            free pages from the tree. If the tree is of height 1,
            the tree X-latch does NOT protect the root page,
            because it is also a leaf page. Since we will have a
            latch on an undo log page, we would break the
            latching order if we would only later latch the
            root page of such a tree! */

            btr_root_get(index, &mtr);

            /* We assume in purge of externally stored fields
            that the space id of the undo log record is 0! */

            block = buf_page_get(0, 0, page_no, RW_X_LATCH, &mtr);
            buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);

            data_field = buf_block_get_frame(block)
                         + offset + internal_offset;

            ut_a(dfield_get_len(&ufield->new_val)
                 >= BTR_EXTERN_FIELD_REF_SIZE);
            btr_free_externally_stored_field(
                index,
                data_field + dfield_get_len(&ufield->new_val)
                - BTR_EXTERN_FIELD_REF_SIZE,
                NULL, NULL, NULL, 0, RB_NONE, &mtr);
            mtr_commit(&mtr);
        }
    }
}
Beispiel #5
0
/***************************************************************
Purges an update of an existing record. Also purges an update of a delete
marked record if that record contained an externally stored field. */
static
void
row_purge_upd_exist_or_extern(
/*==========================*/
	purge_node_t*	node,	/* in: row purge node */
	que_thr_t*	thr)	/* in: query thread */
{
	mem_heap_t*	heap;
	dtuple_t*	entry;
	dict_index_t*	index;
	upd_field_t*	ufield;
	ibool		is_insert;
	ulint		rseg_id;
	ulint		page_no;
	ulint		offset;
	ulint		internal_offset;
	byte*		data_field;
	ulint		data_field_len;
	ulint		i;
	mtr_t		mtr;
	
	ut_ad(node && thr);

	if (node->rec_type == TRX_UNDO_UPD_DEL_REC) {

		goto skip_secondaries;
	}

	heap = mem_heap_create(1024);

	while (node->index != NULL) {
		index = node->index;

		if (row_upd_changes_ord_field_binary(NULL, node->index,
							node->update)) {
			/* Build the older version of the index entry */
			entry = row_build_index_entry(node->row, index, heap);

			row_purge_remove_sec_if_poss(node, thr, index, entry);
		}

		node->index = dict_table_get_next_index(node->index);
	}

	mem_heap_free(heap);	

skip_secondaries:
	/* Free possible externally stored fields */
	for (i = 0; i < upd_get_n_fields(node->update); i++) {

		ufield = upd_get_nth_field(node->update, i);

		if (ufield->extern_storage) {
			/* We use the fact that new_val points to
			node->undo_rec and get thus the offset of
			dfield data inside the unod record. Then we
			can calculate from node->roll_ptr the file
			address of the new_val data */

			internal_offset = ((byte*)ufield->new_val.data)
						- node->undo_rec;
						
			ut_a(internal_offset < UNIV_PAGE_SIZE);

			trx_undo_decode_roll_ptr(node->roll_ptr,
						&is_insert, &rseg_id,
						&page_no, &offset);
			mtr_start(&mtr);

			/* We have to acquire an X-latch to the clustered
			index tree */

			index = dict_table_get_first_index(node->table);

			mtr_x_lock(dict_tree_get_lock(index->tree), &mtr);
			
			/* We assume in purge of externally stored fields
			that the space id of the undo log record is 0! */

			data_field = buf_page_get(0, page_no, RW_X_LATCH, &mtr)
				     + offset + internal_offset;

			buf_page_dbg_add_level(buf_frame_align(data_field),
						SYNC_TRX_UNDO_PAGE);
				     
			data_field_len = ufield->new_val.len;

			btr_free_externally_stored_field(index, data_field,
						data_field_len, FALSE, &mtr);
			mtr_commit(&mtr);
		}
	}
}
/***************************************************************
Purges an update of an existing record. Also purges an update of a delete
marked record if that record contained an externally stored field. */
static
void
row_purge_upd_exist_or_extern(
/*==========================*/
	purge_node_t*	node)	/* in: row purge node */
{
	mem_heap_t*	heap;
	dtuple_t*	entry;
	dict_index_t*	index;
	upd_field_t*	ufield;
	ibool		is_insert;
	ulint		rseg_id;
	ulint		page_no;
	ulint		offset;
	ulint		internal_offset;
	byte*		data_field;
	ulint		data_field_len;
	ulint		i;
	mtr_t		mtr;

	ut_ad(node);

	if (node->rec_type == TRX_UNDO_UPD_DEL_REC) {

		goto skip_secondaries;
	}

	heap = mem_heap_create(1024);

	while (node->index != NULL) {
		index = node->index;

		if (row_upd_changes_ord_field_binary(NULL, node->index,
						     node->update)) {
			/* Build the older version of the index entry */
			entry = row_build_index_entry(node->row, index, heap);

			row_purge_remove_sec_if_poss(node, index, entry);
		}

		node->index = dict_table_get_next_index(node->index);
	}

	mem_heap_free(heap);

skip_secondaries:
	/* Free possible externally stored fields */
	for (i = 0; i < upd_get_n_fields(node->update); i++) {

		ufield = upd_get_nth_field(node->update, i);

		if (ufield->extern_storage) {
			/* We use the fact that new_val points to
			node->undo_rec and get thus the offset of
			dfield data inside the unod record. Then we
			can calculate from node->roll_ptr the file
			address of the new_val data */

			internal_offset = ((byte*)ufield->new_val.data)
				- node->undo_rec;

			ut_a(internal_offset < UNIV_PAGE_SIZE);

			trx_undo_decode_roll_ptr(node->roll_ptr,
						 &is_insert, &rseg_id,
						 &page_no, &offset);
			mtr_start(&mtr);

			/* We have to acquire an X-latch to the clustered
			index tree */

			index = dict_table_get_first_index(node->table);

			mtr_x_lock(dict_index_get_lock(index), &mtr);

			/* NOTE: we must also acquire an X-latch to the
			root page of the tree. We will need it when we
			free pages from the tree. If the tree is of height 1,
			the tree X-latch does NOT protect the root page,
			because it is also a leaf page. Since we will have a
			latch on an undo log page, we would break the
			latching order if we would only later latch the
			root page of such a tree! */

			btr_root_get(index, &mtr);

			/* We assume in purge of externally stored fields
			that the space id of the undo log record is 0! */

			data_field = buf_page_get(0, page_no, RW_X_LATCH, &mtr)
				+ offset + internal_offset;

#ifdef UNIV_SYNC_DEBUG
			buf_page_dbg_add_level(buf_frame_align(data_field),
					       SYNC_TRX_UNDO_PAGE);
#endif /* UNIV_SYNC_DEBUG */

			data_field_len = ufield->new_val.len;

			btr_free_externally_stored_field(index, data_field,
							 data_field_len,
							 FALSE, &mtr);
			mtr_commit(&mtr);
		}
	}
}