1/*****************************************************************************
2
3Copyright (c) 1995, 2021, Oracle and/or its affiliates.
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 "buf0dblwr.h"
35#include "fsp0types.h"
36#include "mach0data.h"
37#include "trx0types.h"
38
39/********************************************************//**
40Opens a buffer to mlog. It must be closed with mlog_close.
41@return buffer, NULL if log mode MTR_LOG_NONE or MTR_LOG_NO_REDO */
42UNIV_INLINE
43byte*
44mlog_open(
45/*======*/
46	mtr_t*	mtr,	/*!< in: mtr */
47	ulint	size)	/*!< in: buffer size in bytes; MUST be
48			smaller than mtr_t::buf_t::MAX_DATA_SIZE! */
49{
50	mtr->set_modified();
51
52	if (mtr_get_log_mode(mtr) == MTR_LOG_NONE
53	    || mtr_get_log_mode(mtr) == MTR_LOG_NO_REDO) {
54
55		return(NULL);
56	}
57
58	return(mtr->get_log()->open(size));
59}
60
61/********************************************************//**
62Closes a buffer opened to mlog. */
63UNIV_INLINE
64void
65mlog_close(
66/*=======*/
67	mtr_t*	mtr,	/*!< in: mtr */
68	byte*	ptr)	/*!< in: buffer space from ptr up was not used */
69{
70	ut_ad(mtr_get_log_mode(mtr) != MTR_LOG_NONE);
71	ut_ad(mtr_get_log_mode(mtr) != MTR_LOG_NO_REDO);
72
73	mtr->get_log()->close(ptr);
74}
75
76#ifndef UNIV_HOTBACKUP
77/********************************************************//**
78Catenates 1 - 4 bytes to the mtr log. The value is not compressed. */
79UNIV_INLINE
80void
81mlog_catenate_ulint(
82/*================*/
83	mtr_buf_t*	mtr_buf,	/*!< in/out: buffer to write */
84	ulint		val,		/*!< in: value to write */
85	mlog_id_t	type)		/*!< in: type of value to write */
86{
87	ut_ad(MLOG_1BYTE == 1);
88	ut_ad(MLOG_2BYTES == 2);
89	ut_ad(MLOG_4BYTES == 4);
90	ut_ad(MLOG_8BYTES == 8);
91
92	byte*	ptr = mtr_buf->push<byte*>(type);
93
94	switch (type) {
95	case MLOG_4BYTES:
96		mach_write_to_4(ptr, val);
97		break;
98	case MLOG_2BYTES:
99		mach_write_to_2(ptr, val);
100		break;
101	case MLOG_1BYTE:
102		mach_write_to_1(ptr, val);
103		break;
104	default:
105		ut_error;
106	}
107}
108
109/********************************************************//**
110Catenates 1 - 4 bytes to the mtr log. The value is not compressed. */
111UNIV_INLINE
112void
113mlog_catenate_ulint(
114/*================*/
115	mtr_t*		mtr,	/*!< in/out: mtr */
116	ulint		val,	/*!< in: value to write */
117	mlog_id_t	type)	/*!< in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */
118{
119	if (mtr_get_log_mode(mtr) == MTR_LOG_NONE
120	    || mtr_get_log_mode(mtr) == MTR_LOG_NO_REDO) {
121
122		return;
123	}
124
125	mlog_catenate_ulint(mtr->get_log(), val, type);
126}
127
128/********************************************************//**
129Catenates a compressed ulint to mlog. */
130UNIV_INLINE
131void
132mlog_catenate_ulint_compressed(
133/*===========================*/
134	mtr_t*	mtr,	/*!< in: mtr */
135	ulint	val)	/*!< in: value to write */
136{
137	byte*	log_ptr;
138
139	log_ptr = mlog_open(mtr, 10);
140
141	/* If no logging is requested, we may return now */
142	if (log_ptr == NULL) {
143
144		return;
145	}
146
147	log_ptr += mach_write_compressed(log_ptr, val);
148
149	mlog_close(mtr, log_ptr);
150}
151
152/********************************************************//**
153Catenates a compressed 64-bit integer to mlog. */
154UNIV_INLINE
155void
156mlog_catenate_ull_compressed(
157/*=========================*/
158	mtr_t*		mtr,	/*!< in: mtr */
159	ib_uint64_t	val)	/*!< in: value to write */
160{
161	byte*	log_ptr;
162
163	log_ptr = mlog_open(mtr, 15);
164
165	/* If no logging is requested, we may return now */
166	if (log_ptr == NULL) {
167
168		return;
169	}
170
171	log_ptr += mach_u64_write_compressed(log_ptr, val);
172
173	mlog_close(mtr, log_ptr);
174}
175
176/** Writes a log record about an operation.
177@param[in]	type		redo log record type
178@param[in]	space_id	tablespace identifier
179@param[in]	page_no		page number
180@param[in,out]	log_ptr		current end of mini-transaction log
181@param[in,out]	mtr		mini-transaction
182@return	end of mini-transaction log */
183UNIV_INLINE
184byte*
185mlog_write_initial_log_record_low(
186	mlog_id_t	type,
187	ulint		space_id,
188	ulint		page_no,
189	byte*		log_ptr,
190	mtr_t*		mtr)
191{
192	ut_ad(type <= MLOG_BIGGEST_TYPE);
193	ut_ad(type == MLOG_FILE_NAME
194	      || type == MLOG_FILE_DELETE
195	      || type == MLOG_FILE_CREATE2
196	      || type == MLOG_FILE_RENAME2
197	      || type == MLOG_INDEX_LOAD
198	      || type == MLOG_TRUNCATE
199	      || mtr->is_named_space(space_id));
200
201	mach_write_to_1(log_ptr, type);
202	log_ptr++;
203
204	log_ptr += mach_write_compressed(log_ptr, space_id);
205	log_ptr += mach_write_compressed(log_ptr, page_no);
206
207	mtr->added_rec();
208	return(log_ptr);
209}
210
211/********************************************************//**
212Writes the initial part of a log record (3..11 bytes).
213If the implementation of this function is changed, all
214size parameters to mlog_open() should be adjusted accordingly!
215@return new value of log_ptr */
216UNIV_INLINE
217byte*
218mlog_write_initial_log_record_fast(
219/*===============================*/
220	const byte*	ptr,	/*!< in: pointer to (inside) a buffer
221				frame holding the file page where
222				modification is made */
223	mlog_id_t	type,	/*!< in: log item type: MLOG_1BYTE, ... */
224	byte*		log_ptr,/*!< in: pointer to mtr log which has
225				been opened */
226	mtr_t*		mtr)	/*!< in/out: mtr */
227{
228	const byte*	page;
229	ulint		space;
230	ulint		offset;
231
232	ut_ad(log_ptr);
233	ut_d(mtr->memo_modify_page(ptr));
234
235	page = (const byte*) ut_align_down(ptr, UNIV_PAGE_SIZE);
236	space = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
237	offset = mach_read_from_4(page + FIL_PAGE_OFFSET);
238
239	/* check whether the page is in the doublewrite buffer;
240	the doublewrite buffer is located in pages
241	FSP_EXTENT_SIZE, ..., 3 * FSP_EXTENT_SIZE - 1 in the
242	system tablespace */
243
244	if (space == TRX_SYS_SPACE
245	    && offset >= FSP_EXTENT_SIZE && offset < 3 * FSP_EXTENT_SIZE) {
246		if (buf_dblwr_being_created) {
247			/* Do nothing: we only come to this branch in an
248			InnoDB database creation. We do not redo log
249			anything for the doublewrite buffer pages. */
250			return(log_ptr);
251		} else {
252			ib::error() << "Trying to redo log a record of type "
253				<< type << "  on page "
254				<< page_id_t(space, offset) << "in the"
255				" doublewrite buffer, continuing anyway."
256				" Please post a bug report to"
257				" bugs.mysql.com.";
258			ut_ad(0);
259		}
260	}
261
262	return(mlog_write_initial_log_record_low(type, space, offset,
263						 log_ptr, mtr));
264}
265#endif /* !UNIV_HOTBACKUP */
266