1/*****************************************************************************
2
3Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
4
5This program is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License, version 2.0,
7as published by the Free Software Foundation.
8
9This program is also distributed with certain software (including
10but not limited to OpenSSL) that is licensed under separate terms,
11as designated in a particular file or component or in included license
12documentation.  The authors of MySQL hereby grant you an additional
13permission to link the program and your derivative works with the
14separately licensed software that they have included with MySQL.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19GNU General Public License, version 2.0, for more details.
20
21You should have received a copy of the GNU General Public License along with
22this program; if not, write to the Free Software Foundation, Inc.,
2351 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24
25*****************************************************************************/
26
27/**************************************************//**
28@file include/mtr0log.ic
29Mini-transaction logging routines
30
31Created 12/7/1995 Heikki Tuuri
32*******************************************************/
33
34#include "mach0data.h"
35#include "ut0lst.h"
36#include "buf0buf.h"
37#include "buf0dblwr.h"
38#include "fsp0types.h"
39#include "trx0sys.h"
40
41/********************************************************//**
42Opens a buffer to mlog. It must be closed with mlog_close.
43@return	buffer, NULL if log mode MTR_LOG_NONE */
44UNIV_INLINE
45byte*
46mlog_open(
47/*======*/
48	mtr_t*	mtr,	/*!< in: mtr */
49	ulint	size)	/*!< in: buffer size in bytes; MUST be
50			smaller than DYN_ARRAY_DATA_SIZE! */
51{
52	dyn_array_t*	mlog;
53
54	mtr->modifications = TRUE;
55
56	if (mtr_get_log_mode(mtr) == MTR_LOG_NONE) {
57
58		return(NULL);
59	}
60
61	mlog = &(mtr->log);
62
63	return(dyn_array_open(mlog, size));
64}
65
66/********************************************************//**
67Closes a buffer opened to mlog. */
68UNIV_INLINE
69void
70mlog_close(
71/*=======*/
72	mtr_t*	mtr,	/*!< in: mtr */
73	byte*	ptr)	/*!< in: buffer space from ptr up was not used */
74{
75	dyn_array_t*	mlog;
76
77	ut_ad(mtr_get_log_mode(mtr) != MTR_LOG_NONE);
78
79	mlog = &(mtr->log);
80
81	dyn_array_close(mlog, ptr);
82}
83
84#ifndef UNIV_HOTBACKUP
85/********************************************************//**
86Catenates 1 - 4 bytes to the mtr log. The value is not compressed. */
87UNIV_INLINE
88void
89mlog_catenate_ulint(
90/*================*/
91	mtr_t*	mtr,	/*!< in: mtr */
92	ulint	val,	/*!< in: value to write */
93	ulint	type)	/*!< in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */
94{
95	dyn_array_t*	mlog;
96	byte*		ptr;
97
98	if (mtr_get_log_mode(mtr) == MTR_LOG_NONE) {
99
100		return;
101	}
102
103	mlog = &(mtr->log);
104
105#if MLOG_1BYTE != 1
106# error "MLOG_1BYTE != 1"
107#endif
108#if MLOG_2BYTES != 2
109# error "MLOG_2BYTES != 2"
110#endif
111#if MLOG_4BYTES != 4
112# error "MLOG_4BYTES != 4"
113#endif
114#if MLOG_8BYTES != 8
115# error "MLOG_8BYTES != 8"
116#endif
117	ptr = (byte*) dyn_array_push(mlog, type);
118
119	if (type == MLOG_4BYTES) {
120		mach_write_to_4(ptr, val);
121	} else if (type == MLOG_2BYTES) {
122		mach_write_to_2(ptr, val);
123	} else {
124		ut_ad(type == MLOG_1BYTE);
125		mach_write_to_1(ptr, val);
126	}
127}
128
129/********************************************************//**
130Catenates a compressed ulint to mlog. */
131UNIV_INLINE
132void
133mlog_catenate_ulint_compressed(
134/*===========================*/
135	mtr_t*	mtr,	/*!< in: mtr */
136	ulint	val)	/*!< in: value to write */
137{
138	byte*	log_ptr;
139
140	log_ptr = mlog_open(mtr, 10);
141
142	/* If no logging is requested, we may return now */
143	if (log_ptr == NULL) {
144
145		return;
146	}
147
148	log_ptr += mach_write_compressed(log_ptr, val);
149
150	mlog_close(mtr, log_ptr);
151}
152
153/********************************************************//**
154Catenates a compressed 64-bit integer to mlog. */
155UNIV_INLINE
156void
157mlog_catenate_ull_compressed(
158/*=========================*/
159	mtr_t*		mtr,	/*!< in: mtr */
160	ib_uint64_t	val)	/*!< in: value to write */
161{
162	byte*	log_ptr;
163
164	log_ptr = mlog_open(mtr, 15);
165
166	/* If no logging is requested, we may return now */
167	if (log_ptr == NULL) {
168
169		return;
170	}
171
172	log_ptr += mach_ull_write_compressed(log_ptr, val);
173
174	mlog_close(mtr, log_ptr);
175}
176
177/********************************************************//**
178Writes the initial part of a log record (3..11 bytes).
179If the implementation of this function is changed, all
180size parameters to mlog_open() should be adjusted accordingly!
181@return	new value of log_ptr */
182UNIV_INLINE
183byte*
184mlog_write_initial_log_record_fast(
185/*===============================*/
186	const byte*	ptr,	/*!< in: pointer to (inside) a buffer
187				frame holding the file page where
188				modification is made */
189	byte		type,	/*!< in: log item type: MLOG_1BYTE, ... */
190	byte*		log_ptr,/*!< in: pointer to mtr log which has
191				been opened */
192	mtr_t*		mtr)	/*!< in: mtr */
193{
194#ifdef UNIV_DEBUG
195	buf_block_t*	block;
196#endif
197	const byte*	page;
198	ulint		space;
199	ulint		offset;
200
201	ut_ad(mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_X_FIX));
202	ut_ad(type <= MLOG_BIGGEST_TYPE);
203	ut_ad(ptr && log_ptr);
204
205	page = (const byte*) ut_align_down(ptr, UNIV_PAGE_SIZE);
206	space = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
207	offset = mach_read_from_4(page + FIL_PAGE_OFFSET);
208
209	/* check whether the page is in the doublewrite buffer;
210	the doublewrite buffer is located in pages
211	FSP_EXTENT_SIZE, ..., 3 * FSP_EXTENT_SIZE - 1 in the
212	system tablespace */
213	if (space == TRX_SYS_SPACE
214	    && offset >= FSP_EXTENT_SIZE && offset < 3 * FSP_EXTENT_SIZE) {
215		if (buf_dblwr_being_created) {
216			/* Do nothing: we only come to this branch in an
217			InnoDB database creation. We do not redo log
218			anything for the doublewrite buffer pages. */
219			return(log_ptr);
220		} else {
221			fprintf(stderr,
222				"Error: trying to redo log a record of type "
223				"%d on page %lu of space %lu in the "
224				"doublewrite buffer, continuing anyway.\n"
225				"Please post a bug report to "
226				"bugs.mysql.com.\n",
227				type, offset, space);
228			ut_ad(0);
229		}
230	}
231
232	mach_write_to_1(log_ptr, type);
233	log_ptr++;
234	log_ptr += mach_write_compressed(log_ptr, space);
235	log_ptr += mach_write_compressed(log_ptr, offset);
236
237	mtr->n_log_recs++;
238
239#ifdef UNIV_LOG_DEBUG
240	fprintf(stderr,
241		"Adding to mtr log record type %lu space %lu page no %lu\n",
242		(ulong) type, space, offset);
243#endif
244
245#ifdef UNIV_DEBUG
246	/* We now assume that all x-latched pages have been modified! */
247	block = (buf_block_t*) buf_block_align(ptr);
248
249	if (!mtr_memo_contains(mtr, block, MTR_MEMO_MODIFY)) {
250
251		mtr_memo_push(mtr, block, MTR_MEMO_MODIFY);
252	}
253#endif
254	return(log_ptr);
255}
256
257/********************************************************//**
258Writes a log record about an .ibd file create/delete/rename.
259@return	new value of log_ptr */
260UNIV_INLINE
261byte*
262mlog_write_initial_log_record_for_file_op(
263/*======================================*/
264	ulint	type,	/*!< in: MLOG_FILE_CREATE, MLOG_FILE_DELETE, or
265			MLOG_FILE_RENAME */
266	ulint	space_id,/*!< in: space id, if applicable */
267	ulint	page_no,/*!< in: page number (not relevant currently) */
268	byte*	log_ptr,/*!< in: pointer to mtr log which has been opened */
269	mtr_t*	mtr)	/*!< in: mtr */
270{
271	ut_ad(log_ptr);
272
273	mach_write_to_1(log_ptr, type);
274	log_ptr++;
275
276	/* We write dummy space id and page number */
277	log_ptr += mach_write_compressed(log_ptr, space_id);
278	log_ptr += mach_write_compressed(log_ptr, page_no);
279
280	mtr->n_log_recs++;
281
282	return(log_ptr);
283}
284#endif /* !UNIV_HOTBACKUP */
285