mtr0log.c 13.4 KB
Newer Older
osku's avatar
osku committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
/******************************************************
Mini-transaction log routines

(c) 1995 Innobase Oy

Created 12/7/1995 Heikki Tuuri
*******************************************************/

#include "mtr0log.h"

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

#include "buf0buf.h"
#include "dict0boot.h"
#include "log0recv.h"
#include "page0page.h"

/************************************************************
Catenates n bytes to the mtr log. */

void
mlog_catenate_string(
/*=================*/
	mtr_t*		mtr,	/* in: mtr */
	const byte*	str,	/* in: string to write */
	ulint		len)	/* in: string length */
{
	dyn_array_t*	mlog;

	if (mtr_get_log_mode(mtr) == MTR_LOG_NONE) {

		return;
	}

	mlog = &(mtr->log);

	dyn_push_string(mlog, str, len);
}

/************************************************************
Writes the initial part of a log record consisting of one-byte item
type and four-byte space and page numbers. Also pushes info
to the mtr memo that a buffer page has been modified. */

void
mlog_write_initial_log_record(
/*==========================*/
	byte*	ptr,	/* in: pointer to (inside) a buffer frame holding the
			file page where modification is made */
	byte	type,	/* in: log item type: MLOG_1BYTE, ... */
	mtr_t*	mtr)	/* in: mini-transaction handle */
{
	byte*	log_ptr;

	ut_ad(type <= MLOG_BIGGEST_TYPE);
	ut_ad(type > MLOG_8BYTES);

	log_ptr = mlog_open(mtr, 11);

	/* If no logging is requested, we may return now */
	if (log_ptr == NULL) {

		return;
	}

	log_ptr = mlog_write_initial_log_record_fast(ptr, type, log_ptr, mtr);

	mlog_close(mtr, log_ptr);
71
}
osku's avatar
osku committed
72 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

/************************************************************
Parses an initial log record written by mlog_write_initial_log_record. */

byte*
mlog_parse_initial_log_record(
/*==========================*/
			/* out: parsed record end, NULL if not a complete
			record */
	byte*	ptr,	/* in: buffer */
	byte*	end_ptr,/* in: buffer end */
	byte*	type,	/* out: log record type: MLOG_1BYTE, ... */
	ulint*	space,	/* out: space id */
	ulint*	page_no)/* out: page number */
{
	if (end_ptr < ptr + 1) {

		return(NULL);
	}

	*type = (byte)((ulint)*ptr & ~MLOG_SINGLE_REC_FLAG);
	ut_ad(*type <= MLOG_BIGGEST_TYPE);

	ptr++;

	if (end_ptr < ptr + 2) {

		return(NULL);
	}

	ptr = mach_parse_compressed(ptr, end_ptr, space);

	if (ptr == NULL) {

		return(NULL);
	}

	ptr = mach_parse_compressed(ptr, end_ptr, page_no);

	return(ptr);
}

/************************************************************
Parses a log record written by mlog_write_ulint or mlog_write_dulint. */

byte*
mlog_parse_nbytes(
/*==============*/
			/* out: parsed record end, NULL if not a complete
			record or a corrupt record */
	ulint	type,	/* in: log record type: MLOG_1BYTE, ... */
	byte*	ptr,	/* in: buffer */
	byte*	end_ptr,/* in: buffer end */
125 126
	byte*	page,	/* in: page where to apply the log record, or NULL */
	void*	page_zip)/* in/out: compressed page, or NULL */
osku's avatar
osku committed
127 128 129 130 131 132
{
	ulint	offset;
	ulint	val;
	dulint	dval;

	ut_a(type <= MLOG_8BYTES);
133
	ut_a(!page || !page_zip || fil_page_get_type(page) != FIL_PAGE_INDEX);
osku's avatar
osku committed
134 135 136 137 138 139 140 141

	if (end_ptr < ptr + 2) {

		return(NULL);
	}

	offset = mach_read_from_2(ptr);
	ptr += 2;
142

osku's avatar
osku committed
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
	if (offset >= UNIV_PAGE_SIZE) {
		recv_sys->found_corrupt_log = TRUE;

		return(NULL);
	}

	if (type == MLOG_8BYTES) {
		ptr = mach_dulint_parse_compressed(ptr, end_ptr, &dval);

		if (ptr == NULL) {

			return(NULL);
		}

		if (page) {
158
			if (UNIV_LIKELY_NULL(page_zip)) {
159 160 161
				mach_write_to_8
					(((page_zip_des_t*) page_zip)->data
					 + offset, dval);
162
			}
osku's avatar
osku committed
163 164 165 166 167 168 169 170 171 172 173 174 175
			mach_write_to_8(page + offset, dval);
		}

		return(ptr);
	}

	ptr = mach_parse_compressed(ptr, end_ptr, &val);

	if (ptr == NULL) {

		return(NULL);
	}

176 177 178 179
	switch (type) {
	case MLOG_1BYTE:
		if (UNIV_UNLIKELY(val > 0xFFUL)) {
			goto corrupt;
osku's avatar
osku committed
180
		}
181 182
		if (page) {
			if (UNIV_LIKELY_NULL(page_zip)) {
183 184 185
				mach_write_to_1
					(((page_zip_des_t*) page_zip)->data
					 + offset, val);
186 187
			}
			mach_write_to_1(page + offset, val);
osku's avatar
osku committed
188
		}
189 190 191 192
		break;
	case MLOG_2BYTES:
		if (UNIV_UNLIKELY(val > 0xFFFFUL)) {
			goto corrupt;
osku's avatar
osku committed
193
		}
194 195
		if (page) {
			if (UNIV_LIKELY_NULL(page_zip)) {
196 197 198
				mach_write_to_2
					(((page_zip_des_t*) page_zip)->data
					 + offset, val);
199
			}
osku's avatar
osku committed
200
			mach_write_to_2(page + offset, val);
201 202 203 204 205
		}
		break;
	case MLOG_4BYTES:
		if (page) {
			if (UNIV_LIKELY_NULL(page_zip)) {
206 207 208
				mach_write_to_4
					(((page_zip_des_t*) page_zip)->data
					 + offset, val);
209
			}
osku's avatar
osku committed
210 211
			mach_write_to_4(page + offset, val);
		}
212 213 214 215 216
		break;
	default:
	corrupt:
		recv_sys->found_corrupt_log = TRUE;
		ptr = NULL;
osku's avatar
osku committed
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
	}

	return(ptr);
}

/************************************************************
Writes 1 - 4 bytes to a file page buffered in the buffer pool.
Writes the corresponding log record to the mini-transaction log. */

void
mlog_write_ulint(
/*=============*/
	byte*	ptr,	/* in: pointer where to write */
	ulint	val,	/* in: value to write */
	byte	type,	/* in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */
	mtr_t*	mtr)	/* in: mini-transaction handle */
{
	byte*	log_ptr;
235 236 237

	switch (type) {
	case MLOG_1BYTE:
osku's avatar
osku committed
238
		mach_write_to_1(ptr, val);
239 240
		break;
	case MLOG_2BYTES:
osku's avatar
osku committed
241
		mach_write_to_2(ptr, val);
242 243
		break;
	case MLOG_4BYTES:
osku's avatar
osku committed
244
		mach_write_to_4(ptr, val);
245 246 247
		break;
	default:
		ut_error;
osku's avatar
osku committed
248 249 250
	}

	log_ptr = mlog_open(mtr, 11 + 2 + 5);
251

osku's avatar
osku committed
252 253 254 255 256 257 258 259
	/* If no logging is requested, we may return now */
	if (log_ptr == NULL) {

		return;
	}

	log_ptr = mlog_write_initial_log_record_fast(ptr, type, log_ptr, mtr);

260
	mach_write_to_2(log_ptr, page_offset(ptr));
osku's avatar
osku committed
261
	log_ptr += 2;
262

osku's avatar
osku committed
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
	log_ptr += mach_write_compressed(log_ptr, val);

	mlog_close(mtr, log_ptr);
}

/************************************************************
Writes 8 bytes to a file page buffered in the buffer pool.
Writes the corresponding log record to the mini-transaction log. */

void
mlog_write_dulint(
/*==============*/
	byte*	ptr,	/* in: pointer where to write */
	dulint	val,	/* in: value to write */
	mtr_t*	mtr)	/* in: mini-transaction handle */
{
	byte*	log_ptr;

	ut_ad(ptr && mtr);

	mach_write_to_8(ptr, val);

	log_ptr = mlog_open(mtr, 11 + 2 + 9);
286

osku's avatar
osku committed
287 288 289 290 291 292 293
	/* If no logging is requested, we may return now */
	if (log_ptr == NULL) {

		return;
	}

	log_ptr = mlog_write_initial_log_record_fast(ptr, MLOG_8BYTES,
294
						     log_ptr, mtr);
osku's avatar
osku committed
295

296
	mach_write_to_2(log_ptr, page_offset(ptr));
osku's avatar
osku committed
297
	log_ptr += 2;
298

osku's avatar
osku committed
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
	log_ptr += mach_dulint_write_compressed(log_ptr, val);

	mlog_close(mtr, log_ptr);
}

/************************************************************
Writes a string to a file page buffered in the buffer pool. Writes the
corresponding log record to the mini-transaction log. */

void
mlog_write_string(
/*==============*/
	byte*		ptr,	/* in: pointer where to write */
	const byte*	str,	/* in: string to write */
	ulint		len,	/* in: string length */
	mtr_t*		mtr)	/* in: mini-transaction handle */
{
	ut_ad(ptr && mtr);
	ut_a(len < UNIV_PAGE_SIZE);

319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
	memcpy(ptr, str, len);

	mlog_log_string(ptr, len, mtr);
}

/************************************************************
Logs a write of a string to a file page buffered in the buffer pool.
Writes the corresponding log record to the mini-transaction log. */

void
mlog_log_string(
/*============*/
	byte*	ptr,	/* in: pointer written to */
	ulint	len,	/* in: string length */
	mtr_t*	mtr)	/* in: mini-transaction handle */
{
	byte*	log_ptr;

	ut_ad(ptr && mtr);
	ut_ad(len <= UNIV_PAGE_SIZE);
osku's avatar
osku committed
339 340

	log_ptr = mlog_open(mtr, 30);
341

osku's avatar
osku committed
342 343 344 345 346 347 348
	/* If no logging is requested, we may return now */
	if (log_ptr == NULL) {

		return;
	}

	log_ptr = mlog_write_initial_log_record_fast(ptr, MLOG_WRITE_STRING,
349
						     log_ptr, mtr);
350
	mach_write_to_2(log_ptr, page_offset(ptr));
osku's avatar
osku committed
351
	log_ptr += 2;
352

osku's avatar
osku committed
353 354 355 356 357
	mach_write_to_2(log_ptr, len);
	log_ptr += 2;

	mlog_close(mtr, log_ptr);

358
	mlog_catenate_string(mtr, ptr, len);
osku's avatar
osku committed
359 360 361 362 363 364 365 366 367 368 369 370
}

/************************************************************
Parses a log record written by mlog_write_string. */

byte*
mlog_parse_string(
/*==============*/
			/* out: parsed record end, NULL if not a complete
			record */
	byte*	ptr,	/* in: buffer */
	byte*	end_ptr,/* in: buffer end */
371 372
	byte*	page,	/* in: page where to apply the log record, or NULL */
	void*	page_zip)/* in/out: compressed page, or NULL */
osku's avatar
osku committed
373 374 375 376
{
	ulint	offset;
	ulint	len;

377 378
	ut_a(!page || !page_zip || fil_page_get_type(page) != FIL_PAGE_INDEX);

osku's avatar
osku committed
379 380 381 382 383 384 385
	if (end_ptr < ptr + 4) {

		return(NULL);
	}

	offset = mach_read_from_2(ptr);
	ptr += 2;
386 387
	len = mach_read_from_2(ptr);
	ptr += 2;
osku's avatar
osku committed
388

389 390
	if (UNIV_UNLIKELY(offset >= UNIV_PAGE_SIZE)
			|| UNIV_UNLIKELY(len + offset) > UNIV_PAGE_SIZE) {
osku's avatar
osku committed
391 392 393 394 395 396 397 398 399 400 401
		recv_sys->found_corrupt_log = TRUE;

		return(NULL);
	}

	if (end_ptr < ptr + len) {

		return(NULL);
	}

	if (page) {
402 403 404 405 406
		if (UNIV_LIKELY_NULL(page_zip)) {
			memcpy(((page_zip_des_t*) page_zip)->data
				+ offset, ptr, len);
		}
		memcpy(page + offset, ptr, len);
osku's avatar
osku committed
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
	}

	return(ptr + len);
}

/************************************************************
Opens a buffer for mlog, writes the initial log record and,
if needed, the field lengths of an index. */

byte*
mlog_open_and_write_index(
/*======================*/
				/* out: buffer, NULL if log mode
				MTR_LOG_NONE */
	mtr_t*		mtr,	/* in: mtr */
	byte*		rec,	/* in: index record or page */
	dict_index_t*	index,	/* in: record descriptor */
	byte		type,	/* in: log item type */
	ulint		size)	/* in: requested buffer size in bytes
				(if 0, calls mlog_close() and returns NULL) */
{
	byte*		log_ptr;
	const byte*	log_start;
	const byte*	log_end;

432
	ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
osku's avatar
osku committed
433 434 435 436 437 438 439

	if (!page_rec_is_comp(rec)) {
		log_start = log_ptr = mlog_open(mtr, 11 + size);
		if (!log_ptr) {
			return(NULL); /* logging is disabled */
		}
		log_ptr = mlog_write_initial_log_record_fast(rec, type,
440
							     log_ptr, mtr);
osku's avatar
osku committed
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
		log_end = log_ptr + 11 + size;
	} else {
		ulint	i;
		ulint	n	= dict_index_get_n_fields(index);
		/* total size needed */
		ulint	total	= 11 + size + (n + 2) * 2;
		ulint	alloc	= total;
		/* allocate at most DYN_ARRAY_DATA_SIZE at a time */
		if (alloc > DYN_ARRAY_DATA_SIZE) {
			alloc = DYN_ARRAY_DATA_SIZE;
		}
		log_start = log_ptr = mlog_open(mtr, alloc);
		if (!log_ptr) {
			return(NULL); /* logging is disabled */
		}
		log_end = log_ptr + alloc;
		log_ptr = mlog_write_initial_log_record_fast(rec, type,
458
							     log_ptr, mtr);
osku's avatar
osku committed
459 460 461 462 463 464
		mach_write_to_2(log_ptr, n);
		log_ptr += 2;
		mach_write_to_2(log_ptr,
				dict_index_get_n_unique_in_tree(index));
		log_ptr += 2;
		for (i = 0; i < n; i++) {
465 466 467 468
			dict_field_t*		field;
			const dict_col_t*	col;
			ulint			len;

osku's avatar
osku committed
469
			field = dict_index_get_nth_field(index, i);
470
			col = dict_field_get_col(field);
osku's avatar
osku committed
471 472
			len = field->fixed_len;
			ut_ad(len < 0x7fff);
473
			if (len == 0
474
			    && (col->len > 255 || col->mtype == DATA_BLOB)) {
osku's avatar
osku committed
475 476 477 478
				/* variable-length field
				with maximum length > 255 */
				len = 0x7fff;
			}
479
			if (col->prtype & DATA_NOT_NULL) {
osku's avatar
osku committed
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
				len |= 0x8000;
			}
			if (log_ptr + 2 > log_end) {
				mlog_close(mtr, log_ptr);
				ut_a(total > (ulint) (log_ptr - log_start));
				total -= log_ptr - log_start;
				alloc = total;
				if (alloc > DYN_ARRAY_DATA_SIZE) {
					alloc = DYN_ARRAY_DATA_SIZE;
				}
				log_start = log_ptr = mlog_open(mtr, alloc);
				if (!log_ptr) {
					return(NULL); /* logging is disabled */
				}
				log_end = log_ptr + alloc;
			}
			mach_write_to_2(log_ptr, len);
			log_ptr += 2;
		}
	}
	if (size == 0) {
		mlog_close(mtr, log_ptr);
		log_ptr = NULL;
	} else if (log_ptr + size > log_end) {
		mlog_close(mtr, log_ptr);
		log_ptr = mlog_open(mtr, size);
	}
	return(log_ptr);
}

/************************************************************
Parses a log record written by mlog_open_and_write_index. */

byte*
mlog_parse_index(
/*=============*/
				/* out: parsed record end,
				NULL if not a complete record */
	byte*		ptr,	/* in: buffer */
	byte*		end_ptr,/* in: buffer end */
				/* out: new value of log_ptr */
	ibool		comp,	/* in: TRUE=compact record format */
	dict_index_t**	index)	/* out, own: dummy index */
{
	ulint		i, n, n_uniq;
	dict_table_t*	table;
	dict_index_t*	ind;

	ut_ad(comp == FALSE || comp == TRUE);

	if (comp) {
		if (end_ptr < ptr + 4) {
			return(NULL);
		}
		n = mach_read_from_2(ptr);
		ptr += 2;
		n_uniq = mach_read_from_2(ptr);
537
		ptr += 2;
osku's avatar
osku committed
538
		ut_ad(n_uniq <= n);
539
		if (end_ptr < ptr + n * 2) {
osku's avatar
osku committed
540 541 542 543 544
			return(NULL);
		}
	} else {
		n = n_uniq = 1;
	}
545
	table = dict_mem_table_create("LOG_DUMMY", DICT_HDR_SPACE, n,
546
				      comp ? DICT_TF_COMPACT : 0);
osku's avatar
osku committed
547
	ind = dict_mem_index_create("LOG_DUMMY", "LOG_DUMMY",
548
				    DICT_HDR_SPACE, 0, n);
osku's avatar
osku committed
549
	ind->table = table;
550
	ind->n_uniq = (unsigned int) n_uniq;
osku's avatar
osku committed
551
	if (n_uniq != n) {
552
		ut_a(n_uniq + DATA_ROLL_PTR <= n);
osku's avatar
osku committed
553 554 555 556
		ind->type = DICT_CLUSTERED;
	}
	if (comp) {
		for (i = 0; i < n; i++) {
557 558
			ulint	len = mach_read_from_2(ptr);
			ptr += 2;
osku's avatar
osku committed
559 560 561
			/* The high-order bit of len is the NOT NULL flag;
			the rest is 0 or 0x7fff for variable-length fields,
			and 1..0x7ffe for fixed-length fields. */
562
			dict_mem_table_add_col(
563
				table, NULL, NULL,
564 565 566 567 568
				((len + 1) & 0x7fff) <= 1
				? DATA_BINARY : DATA_FIXBINARY,
				len & 0x8000 ? DATA_NOT_NULL : 0,
				len & 0x7fff);

569
			dict_index_add_col(ind, table,
570 571
					   dict_table_get_nth_col(table, i),
					   0);
osku's avatar
osku committed
572
		}
573
		dict_table_add_system_columns(table, table->heap);
574 575 576 577 578 579 580 581 582 583 584 585 586
		if (n_uniq != n) {
			/* Identify DB_TRX_ID and DB_ROLL_PTR in the index. */
			ut_a(DATA_TRX_ID_LEN
			     == dict_index_get_nth_col(ind, DATA_TRX_ID - 1
						       + n_uniq)->len);
			ut_a(DATA_ROLL_PTR_LEN
			     == dict_index_get_nth_col(ind, DATA_ROLL_PTR - 1
						       + n_uniq)->len);
			ind->fields[DATA_TRX_ID - 1 + n_uniq].col
				= &table->cols[n + DATA_TRX_ID];
			ind->fields[DATA_ROLL_PTR - 1 + n_uniq].col
				= &table->cols[n + DATA_ROLL_PTR];
		}
osku's avatar
osku committed
587
	}
588 589
	/* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
	ind->cached = TRUE;
osku's avatar
osku committed
590 591 592
	*index = ind;
	return(ptr);
}