Пример #1
0
/***********************************************************************//**
Updates the last not yet purged history log info in rseg when we have purged
a whole undo log. Advances also purge_sys->purge_trx_no past the purged log. */
static
void
trx_purge_rseg_get_next_history_log(
    /*================================*/
    trx_rseg_t*	rseg)	/*!< in: rollback segment */
{
    page_t*		undo_page;
    trx_ulogf_t*	log_hdr;
    fil_addr_t	prev_log_addr;
    trx_id_t	trx_no;
    ibool		del_marks;
    mtr_t		mtr;
    rseg_queue_t	rseg_queue;
    const void*	ptr;

    mutex_enter(&(rseg->mutex));

    ut_a(rseg->last_page_no != FIL_NULL);

    purge_sys->purge_trx_no = rseg->last_trx_no + 1;
    purge_sys->purge_undo_no = 0;
    purge_sys->next_stored = FALSE;

    mtr_start(&mtr);

    undo_page = trx_undo_page_get_s_latched(
                    rseg->space, rseg->zip_size, rseg->last_page_no, &mtr);

    log_hdr = undo_page + rseg->last_offset;

    /* Increase the purge page count by one for every handled log */

    purge_sys->n_pages_handled++;

    prev_log_addr = trx_purge_get_log_from_hist(
                        flst_get_prev_addr(log_hdr + TRX_UNDO_HISTORY_NODE, &mtr));

    if (prev_log_addr.page == FIL_NULL) {
        /* No logs left in the history list */

        rseg->last_page_no = FIL_NULL;

        mutex_exit(&(rseg->mutex));
        mtr_commit(&mtr);

        mutex_enter(&kernel_mutex);

        /* Add debug code to track history list corruption reported
        on the MySQL mailing list on Nov 9, 2004. The fut0lst.c
        file-based list was corrupt. The prev node pointer was
        FIL_NULL, even though the list length was over 8 million nodes!
        We assume that purge truncates the history list in large
        size pieces, and if we here reach the head of the list, the
        list cannot be longer than 2000 000 undo logs now. */

        if (trx_sys->rseg_history_len > 2000000) {
            ut_print_timestamp(stderr);
            fprintf(stderr,
                    "  InnoDB: Warning: purge reached the"
                    " head of the history list,\n"
                    "InnoDB: but its length is still"
                    " reported as %lu! Make a detailed bug\n"
                    "InnoDB: report, and submit it"
                    " to http://bugs.mysql.com\n",
                    (ulong) trx_sys->rseg_history_len);
        }

        mutex_exit(&kernel_mutex);

        return;
    }

    mutex_exit(&(rseg->mutex));
    mtr_commit(&mtr);

    /* Read the trx number and del marks from the previous log header */
    mtr_start(&mtr);

    log_hdr = trx_undo_page_get_s_latched(rseg->space, rseg->zip_size,
                                          prev_log_addr.page, &mtr)
              + prev_log_addr.boffset;

    trx_no = mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO);

    del_marks = mach_read_from_2(log_hdr + TRX_UNDO_DEL_MARKS);

    mtr_commit(&mtr);

    mutex_enter(&(rseg->mutex));

    rseg->last_page_no = prev_log_addr.page;
    rseg->last_offset = prev_log_addr.boffset;
    rseg->last_trx_no = trx_no;
    rseg->last_del_marks = del_marks;

    rseg_queue.rseg = rseg;
    rseg_queue.trx_no = rseg->last_trx_no;

    /* Purge can also produce events, however these are already ordered
    in the rollback segment and any user generated event will be greater
    than the events that Purge produces. ie. Purge can never produce
    events from an empty rollback segment. */

    mutex_enter(&purge_sys->bh_mutex);

    ptr = ib_bh_push(purge_sys->ib_bh, &rseg_queue);
    ut_a(ptr != NULL);

    mutex_exit(&purge_sys->bh_mutex);

    mutex_exit(&(rseg->mutex));
}
Пример #2
0
/***************************************************************************
Creates and initializes a rollback segment object. The values for the
fields are read from the header. The object is inserted to the rseg
list of the trx system object and a pointer is inserted in the rseg
array in the trx system object.
@return	own: rollback segment object */
static
trx_rseg_t*
trx_rseg_mem_create(
/*================*/
	ulint	id,		/*!< in: rollback segment id */
	ulint	space,		/*!< in: space where the segment placed */
	ulint	zip_size,	/*!< in: compressed page size in bytes
				or 0 for uncompressed pages */
	ulint	page_no,	/*!< in: page number of the segment header */
	mtr_t*	mtr)		/*!< in: mtr */
{
	ulint		len;
	trx_rseg_t*	rseg;
	fil_addr_t	node_addr;
	trx_rsegf_t*	rseg_header;
	trx_ulogf_t*	undo_log_hdr;
	ulint		sum_of_undo_sizes;

	ut_ad(mutex_own(&kernel_mutex));

	rseg = mem_zalloc(sizeof(trx_rseg_t));

	rseg->id = id;
	rseg->space = space;
	rseg->zip_size = zip_size;
	rseg->page_no = page_no;

	mutex_create(rseg_mutex_key, &rseg->mutex, SYNC_RSEG);

	UT_LIST_ADD_LAST(rseg_list, trx_sys->rseg_list, rseg);

	trx_sys_set_nth_rseg(trx_sys, id, rseg);

	rseg_header = trx_rsegf_get_new(space, zip_size, page_no, mtr);

	rseg->max_size = mtr_read_ulint(rseg_header + TRX_RSEG_MAX_SIZE,
					MLOG_4BYTES, mtr);

	/* Initialize the undo log lists according to the rseg header */

	sum_of_undo_sizes = trx_undo_lists_init(rseg);

	rseg->curr_size = mtr_read_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
					 MLOG_4BYTES, mtr)
		+ 1 + sum_of_undo_sizes;

	len = flst_get_len(rseg_header + TRX_RSEG_HISTORY, mtr);
	if (len > 0) {
		trx_sys->rseg_history_len += len;

		node_addr = trx_purge_get_log_from_hist(
			flst_get_last(rseg_header + TRX_RSEG_HISTORY, mtr));
		rseg->last_page_no = node_addr.page;
		rseg->last_offset = node_addr.boffset;

		undo_log_hdr = trx_undo_page_get(rseg->space, rseg->zip_size,
						 node_addr.page,
						 mtr) + node_addr.boffset;

		rseg->last_trx_no = mtr_read_dulint(
			undo_log_hdr + TRX_UNDO_TRX_NO, mtr);
		rseg->last_del_marks = mtr_read_ulint(
			undo_log_hdr + TRX_UNDO_DEL_MARKS, MLOG_2BYTES, mtr);
	} else {
		rseg->last_page_no = FIL_NULL;
	}

	return(rseg);
}
Пример #3
0
/********************************************************************//**
Removes unnecessary history data from a rollback segment. */
static
void
trx_purge_truncate_rseg_history(
    /*============================*/
    trx_rseg_t*	rseg,		/*!< in: rollback segment */
    trx_id_t	limit_trx_no,	/*!< in: remove update undo logs whose
					trx number is < limit_trx_no */
    undo_no_t	limit_undo_no)	/*!< in: if transaction number is equal
					to limit_trx_no, truncate undo records
					with undo number < limit_undo_no */
{
    fil_addr_t	hdr_addr;
    fil_addr_t	prev_hdr_addr;
    trx_rsegf_t*	rseg_hdr;
    page_t*		undo_page;
    trx_ulogf_t*	log_hdr;
    trx_usegf_t*	seg_hdr;
    ulint		n_removed_logs	= 0;
    mtr_t		mtr;
    trx_id_t	undo_trx_no;

    mtr_start(&mtr);
    mutex_enter(&(rseg->mutex));

    rseg_hdr = trx_rsegf_get(rseg->space, rseg->zip_size,
                             rseg->page_no, &mtr);

    hdr_addr = trx_purge_get_log_from_hist(
                   flst_get_last(rseg_hdr + TRX_RSEG_HISTORY, &mtr));
loop:
    if (hdr_addr.page == FIL_NULL) {

        mutex_exit(&(rseg->mutex));

        mtr_commit(&mtr);

        return;
    }

    undo_page = trx_undo_page_get(rseg->space, rseg->zip_size,
                                  hdr_addr.page, &mtr);

    log_hdr = undo_page + hdr_addr.boffset;
    undo_trx_no = mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO);

    if (undo_trx_no >= limit_trx_no) {
        if (undo_trx_no == limit_trx_no) {
            trx_undo_truncate_start(rseg, rseg->space,
                                    hdr_addr.page,
                                    hdr_addr.boffset,
                                    limit_undo_no);
        }

        mutex_enter(&kernel_mutex);
        ut_a(trx_sys->rseg_history_len >= n_removed_logs);
        trx_sys->rseg_history_len -= n_removed_logs;
        mutex_exit(&kernel_mutex);

        flst_truncate_end(rseg_hdr + TRX_RSEG_HISTORY,
                          log_hdr + TRX_UNDO_HISTORY_NODE,
                          n_removed_logs, &mtr);

        mutex_exit(&(rseg->mutex));
        mtr_commit(&mtr);

        return;
    }

    prev_hdr_addr = trx_purge_get_log_from_hist(
                        flst_get_prev_addr(log_hdr + TRX_UNDO_HISTORY_NODE, &mtr));
    n_removed_logs++;

    seg_hdr = undo_page + TRX_UNDO_SEG_HDR;

    if ((mach_read_from_2(seg_hdr + TRX_UNDO_STATE) == TRX_UNDO_TO_PURGE)
            && (mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG) == 0)) {

        /* We can free the whole log segment */

        mutex_exit(&(rseg->mutex));
        mtr_commit(&mtr);

        trx_purge_free_segment(rseg, hdr_addr, n_removed_logs);

        n_removed_logs = 0;
    } else {
        mutex_exit(&(rseg->mutex));
        mtr_commit(&mtr);
    }

    mtr_start(&mtr);
    mutex_enter(&(rseg->mutex));

    rseg_hdr = trx_rsegf_get(rseg->space, rseg->zip_size,
                             rseg->page_no, &mtr);

    hdr_addr = prev_hdr_addr;

    goto loop;
}
Пример #4
0
/***************************************************************************
Updates the last not yet purged history log info in rseg when we have purged
a whole undo log. Advances also purge_sys->purge_trx_no past the purged log. */
static
void
trx_purge_rseg_get_next_history_log(
/*================================*/
	trx_rseg_t*	rseg)	/* in: rollback segment */
{
	page_t*		undo_page;
	trx_ulogf_t*	log_hdr;
	trx_usegf_t*	seg_hdr;
	fil_addr_t	prev_log_addr;
	dulint		trx_no;
	ibool		del_marks;
	mtr_t		mtr;

	ut_ad(mutex_own(&(purge_sys->mutex)));

	mutex_enter(&(rseg->mutex));

	ut_a(rseg->last_page_no != FIL_NULL);

	purge_sys->purge_trx_no = ut_dulint_add(rseg->last_trx_no, 1);
	purge_sys->purge_undo_no = ut_dulint_zero;
	purge_sys->next_stored = FALSE;

	mtr_start(&mtr);

	undo_page = trx_undo_page_get_s_latched(rseg->space,
						rseg->last_page_no, &mtr);
	log_hdr = undo_page + rseg->last_offset;
	seg_hdr = undo_page + TRX_UNDO_SEG_HDR;

	/* Increase the purge page count by one for every handled log */

	purge_sys->n_pages_handled++;

	prev_log_addr = trx_purge_get_log_from_hist(
		flst_get_prev_addr(log_hdr + TRX_UNDO_HISTORY_NODE, &mtr));
	if (prev_log_addr.page == FIL_NULL) {
		/* No logs left in the history list */

		rseg->last_page_no = FIL_NULL;

		mutex_exit(&(rseg->mutex));
		mtr_commit(&mtr);

		mutex_enter(&kernel_mutex);

		/* Add debug code to track history list corruption reported
		on the MySQL mailing list on Nov 9, 2004. The fut0lst.c
		file-based list was corrupt. The prev node pointer was
		FIL_NULL, even though the list length was over 8 million nodes!
		We assume that purge truncates the history list in moderate
		size pieces, and if we here reach the head of the list, the
		list cannot be longer than 20 000 undo logs now. */

		if (trx_sys->rseg_history_len > 20000) {
			ut_print_timestamp(stderr);
			fprintf(stderr,
				"  InnoDB: Warning: purge reached the"
				" head of the history list,\n"
				"InnoDB: but its length is still"
				" reported as %lu! Make a detailed bug\n"
				"InnoDB: report, and submit it"
				" to http://bugs.mysql.com\n",
				(ulong) trx_sys->rseg_history_len);
		}

		mutex_exit(&kernel_mutex);

		return;
	}

	mutex_exit(&(rseg->mutex));
	mtr_commit(&mtr);

	/* Read the trx number and del marks from the previous log header */
	mtr_start(&mtr);

	log_hdr = trx_undo_page_get_s_latched(rseg->space,
					      prev_log_addr.page, &mtr)
		+ prev_log_addr.boffset;

	trx_no = mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO);

	del_marks = mach_read_from_2(log_hdr + TRX_UNDO_DEL_MARKS);

	mtr_commit(&mtr);

	mutex_enter(&(rseg->mutex));

	rseg->last_page_no = prev_log_addr.page;
	rseg->last_offset = prev_log_addr.boffset;
	rseg->last_trx_no = trx_no;
	rseg->last_del_marks = del_marks;

	mutex_exit(&(rseg->mutex));
}