trx0rseg.c 8.38 KB
Newer Older
Vadim Tkachenko's avatar
Vadim Tkachenko committed
1 2
/*****************************************************************************

3
Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
Vadim Tkachenko's avatar
Vadim Tkachenko committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

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., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA

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

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
19 20
/**************************************************//**
@file trx/trx0rseg.c
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
Rollback segment

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

#include "trx0rseg.h"

#ifdef UNIV_NONINL
#include "trx0rseg.ic"
#endif

#include "trx0undo.h"
#include "fut0lst.h"
#include "srv0srv.h"
#include "trx0purge.h"

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
37 38 39
/******************************************************************//**
Looks for a rollback segment, based on the rollback segment id.
@return	rollback segment */
40 41 42 43
UNIV_INTERN
trx_rseg_t*
trx_rseg_get_on_id(
/*===============*/
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
44
	ulint	id)	/*!< in: rollback segment id */
45 46 47 48 49 50 51 52 53 54 55 56 57 58
{
	trx_rseg_t*	rseg;

	rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
	ut_ad(rseg);

	while (rseg->id != id) {
		rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
		ut_ad(rseg);
	}

	return(rseg);
}

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
59
/****************************************************************//**
60
Creates a rollback segment header. This function is called only when
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
61 62
a new rollback segment is created in the database.
@return	page number of the created segment, FIL_NULL if fail */
63 64 65 66
UNIV_INTERN
ulint
trx_rseg_header_create(
/*===================*/
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
67 68
	ulint	space,		/*!< in: space id */
	ulint	zip_size,	/*!< in: compressed page size in bytes
69
				or 0 for uncompressed pages */
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
70 71 72
	ulint	max_size,	/*!< in: max size in pages */
	ulint*	slot_no,	/*!< out: rseg id == slot number in trx sys */
	mtr_t*	mtr)		/*!< in: mtr */
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
{
	ulint		page_no;
	trx_rsegf_t*	rsegf;
	trx_sysf_t*	sys_header;
	ulint		i;
	buf_block_t*	block;

	ut_ad(mtr);
	ut_ad(mutex_own(&kernel_mutex));
	ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
				MTR_MEMO_X_LOCK));
	sys_header = trx_sysf_get(mtr);

	*slot_no = trx_sysf_rseg_find_free(mtr);

	if (*slot_no == ULINT_UNDEFINED) {

		return(FIL_NULL);
	}

	/* Allocate a new file segment for the rollback segment */
	block = fseg_create(space, 0,
			    TRX_RSEG + TRX_RSEG_FSEG_HEADER, mtr);

	if (block == NULL) {
		/* No space left */

		return(FIL_NULL);
	}

	buf_block_dbg_add_level(block, SYNC_RSEG_HEADER_NEW);

	page_no = buf_block_get_page_no(block);

	/* Get the rollback segment file page */
	rsegf = trx_rsegf_get_new(space, zip_size, page_no, mtr);

	/* Initialize max size field */
	mlog_write_ulint(rsegf + TRX_RSEG_MAX_SIZE, max_size,
			 MLOG_4BYTES, mtr);

	/* Initialize the history list */

	mlog_write_ulint(rsegf + TRX_RSEG_HISTORY_SIZE, 0, MLOG_4BYTES, mtr);
	flst_init(rsegf + TRX_RSEG_HISTORY, mtr);

	/* Reset the undo log slots */
	for (i = 0; i < TRX_RSEG_N_SLOTS; i++) {

		trx_rsegf_set_nth_undo(rsegf, i, FIL_NULL, mtr);
	}

	/* Add the rollback segment info to the free slot in the trx system
	header */

	trx_sysf_rseg_set_space(sys_header, *slot_no, space, mtr);
	trx_sysf_rseg_set_page_no(sys_header, *slot_no, page_no, mtr);

	return(page_no);
}

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
134
/***********************************************************************//**
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
Free's an instance of the rollback segment in memory. */
UNIV_INTERN
void
trx_rseg_mem_free(
/*==============*/
	trx_rseg_t*	rseg)	/* in, own: instance to free */
{
	trx_undo_t*	undo;

	mutex_free(&rseg->mutex);

	/* There can't be any active transactions. */
	ut_a(UT_LIST_GET_LEN(rseg->update_undo_list) == 0);
	ut_a(UT_LIST_GET_LEN(rseg->insert_undo_list) == 0);

	undo = UT_LIST_GET_FIRST(rseg->update_undo_cached);

	while (undo != NULL) {
		trx_undo_t*	prev_undo = undo;

		undo = UT_LIST_GET_NEXT(undo_list, undo);
		UT_LIST_REMOVE(undo_list, rseg->update_undo_cached, prev_undo);

		trx_undo_mem_free(prev_undo);
	}

	undo = UT_LIST_GET_FIRST(rseg->insert_undo_cached);

	while (undo != NULL) {
		trx_undo_t*	prev_undo = undo;

		undo = UT_LIST_GET_NEXT(undo_list, undo);
		UT_LIST_REMOVE(undo_list, rseg->insert_undo_cached, prev_undo);

		trx_undo_mem_free(prev_undo);
	}

	trx_sys_set_nth_rseg(trx_sys, rseg->id, NULL);

	mem_free(rseg);
}

/***************************************************************************
178 179 180
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
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
181 182
array in the trx system object.
@return	own: rollback segment object */
183 184 185 186
static
trx_rseg_t*
trx_rseg_mem_create(
/*================*/
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
187 188 189
	ulint	id,		/*!< in: rollback segment id */
	ulint	space,		/*!< in: space where the segment placed */
	ulint	zip_size,	/*!< in: compressed page size in bytes
190
				or 0 for uncompressed pages */
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
191 192
	ulint	page_no,	/*!< in: page number of the segment header */
	mtr_t*	mtr)		/*!< in: mtr */
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
{
	trx_rsegf_t*	rseg_header;
	trx_rseg_t*	rseg;
	trx_ulogf_t*	undo_log_hdr;
	fil_addr_t	node_addr;
	ulint		sum_of_undo_sizes;
	ulint		len;

	ut_ad(mutex_own(&kernel_mutex));

	rseg = mem_alloc(sizeof(trx_rseg_t));

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

	mutex_create(&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);
}

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
253
/*********************************************************************//**
254 255 256 257 258 259
Creates the memory copies for rollback segments and initializes the
rseg list and array in trx_sys at a database startup. */
UNIV_INTERN
void
trx_rseg_list_and_array_init(
/*=========================*/
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
260 261
	trx_sysf_t*	sys_header,	/*!< in: trx system header */
	mtr_t*		mtr)		/*!< in: mtr */
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
{
	ulint	i;
	ulint	page_no;
	ulint	space;

	UT_LIST_INIT(trx_sys->rseg_list);

	trx_sys->rseg_history_len = 0;

	for (i = 0; i < TRX_SYS_N_RSEGS; i++) {

		page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr);

		if (page_no == FIL_NULL) {

			trx_sys_set_nth_rseg(trx_sys, i, NULL);
		} else {
			ulint	zip_size;

			space = trx_sysf_rseg_get_space(sys_header, i, mtr);

			zip_size = space ? fil_space_get_zip_size(space) : 0;

			trx_rseg_mem_create(i, space, zip_size, page_no, mtr);
		}
	}
}

Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
290 291 292
/****************************************************************//**
Creates a new rollback segment to the database.
@return	the created segment object, NULL if fail */
293 294 295 296
UNIV_INTERN
trx_rseg_t*
trx_rseg_create(
/*============*/
Aleksandr Kuzminsky's avatar
Aleksandr Kuzminsky committed
297 298 299 300
	ulint	space,		/*!< in: space id */
	ulint	max_size,	/*!< in: max size in pages */
	ulint*	id,		/*!< out: rseg id */
	mtr_t*	mtr)		/*!< in: mtr */
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
{
	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);
}