/*****************************************************************************

Copyright (c) 1996, 2009, Oracle and/or its affiliates. All Rights Reserved.

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA

*****************************************************************************/

/**************************************************//**
@file include/trx0rseg.ic
Rollback segment

Created 3/26/1996 Heikki Tuuri
*******************************************************/

#include "srv0srv.h"
#include "mtr0log.h"
#include "trx0sys.h"

/******************************************************************//**
Gets a rollback segment header.
@return	rollback segment header, page x-latched */
UNIV_INLINE
trx_rsegf_t*
trx_rsegf_get(
/*==========*/
	ulint	space,		/*!< in: space where placed */
	ulint	zip_size,	/*!< in: compressed page size in bytes
				or 0 for uncompressed pages */
	ulint	page_no,	/*!< in: page number of the header */
	mtr_t*	mtr)		/*!< in: mtr */
{
	buf_block_t*	block;
	trx_rsegf_t*	header;

	block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
	buf_block_dbg_add_level(block, SYNC_RSEG_HEADER);

	header = TRX_RSEG + buf_block_get_frame(block);

	return(header);
}

/******************************************************************//**
Gets a newly created rollback segment header.
@return	rollback segment header, page x-latched */
UNIV_INLINE
trx_rsegf_t*
trx_rsegf_get_new(
/*==============*/
	ulint	space,		/*!< in: space where placed */
	ulint	zip_size,	/*!< in: compressed page size in bytes
				or 0 for uncompressed pages */
	ulint	page_no,	/*!< in: page number of the header */
	mtr_t*	mtr)		/*!< in: mtr */
{
	buf_block_t*	block;
	trx_rsegf_t*	header;

	block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
	buf_block_dbg_add_level(block, SYNC_RSEG_HEADER_NEW);

	header = TRX_RSEG + buf_block_get_frame(block);

	return(header);
}

/***************************************************************//**
Gets the file page number of the nth undo log slot.
@return	page number of the undo log segment */
UNIV_INLINE
ulint
trx_rsegf_get_nth_undo(
/*===================*/
	trx_rsegf_t*	rsegf,	/*!< in: rollback segment header */
	ulint		n,	/*!< in: index of slot */
	mtr_t*		mtr)	/*!< in: mtr */
{
	if (n >= TRX_RSEG_N_SLOTS) {
		fprintf(stderr,
			"InnoDB: Error: trying to get slot %lu of rseg\n",
			(ulong) n);
		ut_error;
	}

	return(mtr_read_ulint(rsegf + TRX_RSEG_UNDO_SLOTS
			      + n * TRX_RSEG_SLOT_SIZE, MLOG_4BYTES, mtr));
}

/***************************************************************//**
Sets the file page number of the nth undo log slot. */
UNIV_INLINE
void
trx_rsegf_set_nth_undo(
/*===================*/
	trx_rsegf_t*	rsegf,	/*!< in: rollback segment header */
	ulint		n,	/*!< in: index of slot */
	ulint		page_no,/*!< in: page number of the undo log segment */
	mtr_t*		mtr)	/*!< in: mtr */
{
	if (n >= TRX_RSEG_N_SLOTS) {
		fprintf(stderr,
			"InnoDB: Error: trying to set slot %lu of rseg\n",
			(ulong) n);
		ut_error;
	}

	mlog_write_ulint(rsegf + TRX_RSEG_UNDO_SLOTS + n * TRX_RSEG_SLOT_SIZE,
			 page_no, MLOG_4BYTES, mtr);
}

/****************************************************************//**
Looks for a free slot for an undo log segment.
@return	slot index or ULINT_UNDEFINED if not found */
UNIV_INLINE
ulint
trx_rsegf_undo_find_free(
/*=====================*/
	trx_rsegf_t*	rsegf,	/*!< in: rollback segment header */
	mtr_t*		mtr)	/*!< in: mtr */
{
	ulint		i;
	ulint		page_no;

	for (i = 0;
#ifndef UNIV_DEBUG
	     i < TRX_RSEG_N_SLOTS;
#else
	     i < (trx_rseg_n_slots_debug ? trx_rseg_n_slots_debug : TRX_RSEG_N_SLOTS);
#endif
	     i++) {

		page_no = trx_rsegf_get_nth_undo(rsegf, i, mtr);

		if (page_no == FIL_NULL) {

			return(i);
		}
	}

	return(ULINT_UNDEFINED);
}

/******************************************************************//**
Looks for a rollback segment, based on the rollback segment id.
@return	rollback segment */
UNIV_INLINE
trx_rseg_t*
trx_rseg_get_on_id(
/*===============*/
	ulint	id)	/*!< in: rollback segment id */
{
	ut_a(id < TRX_SYS_N_RSEGS);

	return(trx_sys->rseg_array[id]);
}