log0log.inl 9.43 KB
Newer Older
1 2
/*****************************************************************************

3
Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
4
Copyright (c) 2017, 2020, MariaDB Corporation.
5 6 7 8 9 10 11 12 13 14

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
15
this program; if not, write to the Free Software Foundation, Inc.,
Vicențiu Ciorbaru's avatar
Vicențiu Ciorbaru committed
16
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
17 18 19

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

20 21
/**************************************************//**
@file include/log0log.ic
osku's avatar
osku committed
22 23 24 25 26 27
Database log

Created 12/9/1995 Heikki Tuuri
*******************************************************/

#include "mach0data.h"
28
#include "assume_aligned.h"
29
#include "ut0crc32.h"
osku's avatar
osku committed
30

31
extern ulong srv_log_buffer_size;
osku's avatar
osku committed
32

33
/************************************************************//**
34
Gets a log block flush bit.
35
@return TRUE if this block was the first to be written in a log flush */
osku's avatar
osku committed
36 37 38 39
UNIV_INLINE
ibool
log_block_get_flush_bit(
/*====================*/
40
	const byte*	log_block)	/*!< in: log block */
osku's avatar
osku committed
41
{
42 43
  static_assert(LOG_BLOCK_HDR_NO == 0, "compatibility");
  static_assert(LOG_BLOCK_FLUSH_BIT_MASK == 0x80000000, "compatibility");
osku's avatar
osku committed
44

45
  return *log_block & 0x80;
osku's avatar
osku committed
46 47
}

48
/************************************************************//**
osku's avatar
osku committed
49 50 51 52 53
Sets the log block flush bit. */
UNIV_INLINE
void
log_block_set_flush_bit(
/*====================*/
54 55
	byte*	log_block,	/*!< in/out: log block */
	ibool	val)		/*!< in: value to set */
osku's avatar
osku committed
56
{
57 58
  static_assert(LOG_BLOCK_HDR_NO == 0, "compatibility");
  static_assert(LOG_BLOCK_FLUSH_BIT_MASK == 0x80000000, "compatibility");
osku's avatar
osku committed
59

60 61 62 63
  if (val)
    *log_block|= 0x80;
  else
    *log_block&= 0x7f;
64
}
osku's avatar
osku committed
65

66
/************************************************************//**
67
Gets a log block number stored in the header.
68
@return log block number stored in the block header */
osku's avatar
osku committed
69 70 71 72
UNIV_INLINE
ulint
log_block_get_hdr_no(
/*=================*/
73
	const byte*	log_block)	/*!< in: log block */
osku's avatar
osku committed
74
{
75 76 77
  static_assert(LOG_BLOCK_HDR_NO == 0, "compatibility");
  return mach_read_from_4(my_assume_aligned<4>(log_block)) &
    ~LOG_BLOCK_FLUSH_BIT_MASK;
osku's avatar
osku committed
78 79
}

80
/************************************************************//**
osku's avatar
osku committed
81 82 83 84 85 86
Sets the log block number stored in the header; NOTE that this must be set
before the flush bit! */
UNIV_INLINE
void
log_block_set_hdr_no(
/*=================*/
87 88
	byte*	log_block,	/*!< in/out: log block */
	ulint	n)		/*!< in: log block number: must be > 0 and
osku's avatar
osku committed
89 90
				< LOG_BLOCK_FLUSH_BIT_MASK */
{
91 92 93
  static_assert(LOG_BLOCK_HDR_NO == 0, "compatibility");
  ut_ad(n > 0);
  ut_ad(n < LOG_BLOCK_FLUSH_BIT_MASK);
94

95
  mach_write_to_4(my_assume_aligned<4>(log_block), n);
osku's avatar
osku committed
96 97
}

98
/************************************************************//**
99
Gets a log block data length.
100
@return log block data length measured as a byte offset from the block start */
osku's avatar
osku committed
101 102 103 104
UNIV_INLINE
ulint
log_block_get_data_len(
/*===================*/
105
	const byte*	log_block)	/*!< in: log block */
osku's avatar
osku committed
106
{
107 108
  return mach_read_from_2(my_assume_aligned<2>
                          (log_block + LOG_BLOCK_HDR_DATA_LEN));
osku's avatar
osku committed
109 110
}

111
/************************************************************//**
osku's avatar
osku committed
112 113 114 115 116
Sets the log block data length. */
UNIV_INLINE
void
log_block_set_data_len(
/*===================*/
117 118
	byte*	log_block,	/*!< in/out: log block */
	ulint	len)		/*!< in: data length */
osku's avatar
osku committed
119
{
120 121
  mach_write_to_2(my_assume_aligned<2>(log_block + LOG_BLOCK_HDR_DATA_LEN),
                  len);
osku's avatar
osku committed
122 123
}

124
/************************************************************//**
125
Gets a log block first mtr log record group offset.
126 127
@return first mtr log record group byte offset from the block start, 0
if none */
osku's avatar
osku committed
128 129 130 131
UNIV_INLINE
ulint
log_block_get_first_rec_group(
/*==========================*/
132
	const byte*	log_block)	/*!< in: log block */
osku's avatar
osku committed
133
{
134 135
  return mach_read_from_2(my_assume_aligned<2>
                          (log_block + LOG_BLOCK_FIRST_REC_GROUP));
osku's avatar
osku committed
136 137
}

138
/************************************************************//**
osku's avatar
osku committed
139 140 141 142 143
Sets the log block first mtr log record group offset. */
UNIV_INLINE
void
log_block_set_first_rec_group(
/*==========================*/
144 145
	byte*	log_block,	/*!< in/out: log block */
	ulint	offset)		/*!< in: offset, 0 if none */
osku's avatar
osku committed
146
{
147 148
  mach_write_to_2(my_assume_aligned<2>
                  (log_block + LOG_BLOCK_FIRST_REC_GROUP), offset);
osku's avatar
osku committed
149 150
}

151
/************************************************************//**
152
Gets a log block checkpoint number field (4 lowest bytes).
153
@return checkpoint no (4 lowest bytes) */
osku's avatar
osku committed
154 155 156 157
UNIV_INLINE
ulint
log_block_get_checkpoint_no(
/*========================*/
158
	const byte*	log_block)	/*!< in: log block */
osku's avatar
osku committed
159
{
160 161
  return mach_read_from_4(my_assume_aligned<4>
                          (log_block + LOG_BLOCK_CHECKPOINT_NO));
osku's avatar
osku committed
162 163
}

164
/************************************************************//**
osku's avatar
osku committed
165 166 167 168 169
Sets a log block checkpoint number field (4 lowest bytes). */
UNIV_INLINE
void
log_block_set_checkpoint_no(
/*========================*/
170 171
	byte*		log_block,	/*!< in/out: log block */
	ib_uint64_t	no)		/*!< in: checkpoint no */
osku's avatar
osku committed
172
{
173 174
  mach_write_to_4(my_assume_aligned<4>(log_block + LOG_BLOCK_CHECKPOINT_NO),
                  static_cast<uint32_t>(no));
osku's avatar
osku committed
175 176
}

177
/************************************************************//**
178
Converts a lsn to a log block number.
179
@return log block number, it is > 0 and <= 1G */
osku's avatar
osku committed
180 181 182 183
UNIV_INLINE
ulint
log_block_convert_lsn_to_no(
/*========================*/
184
	lsn_t	lsn)	/*!< in: lsn of a byte within the block */
osku's avatar
osku committed
185
{
186 187 188
	return(((ulint) (lsn / OS_FILE_LOG_BLOCK_SIZE) &
		DBUG_EVALUATE_IF("innodb_small_log_block_no_limit",
			0xFUL, 0x3FFFFFFFUL)) + 1);
osku's avatar
osku committed
189 190
}

191
/** Calculate the CRC-32C checksum of a log block.
192 193
@param[in]	block	log block
@return checksum */
194
inline ulint log_block_calc_checksum_crc32(const byte* block)
195
{
196
	return ut_crc32(block, OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_CHECKSUM);
197 198
}

199
/************************************************************//**
200
Gets a log block checksum field value.
201
@return checksum */
osku's avatar
osku committed
202 203 204 205
UNIV_INLINE
ulint
log_block_get_checksum(
/*===================*/
206
	const byte*	log_block)	/*!< in: log block */
osku's avatar
osku committed
207
{
208 209 210
  return mach_read_from_4(my_assume_aligned<4>
                          (OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_CHECKSUM +
                           log_block));
osku's avatar
osku committed
211 212
}

213
/************************************************************//**
osku's avatar
osku committed
214 215 216 217 218
Sets a log block checksum field value. */
UNIV_INLINE
void
log_block_set_checksum(
/*===================*/
219 220
	byte*	log_block,	/*!< in/out: log block */
	ulint	checksum)	/*!< in: checksum */
osku's avatar
osku committed
221
{
222 223 224
  mach_write_to_4(my_assume_aligned<4>
                  (OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_CHECKSUM +
                   log_block), checksum);
osku's avatar
osku committed
225 226
}

227
/************************************************************//**
osku's avatar
osku committed
228 229 230 231 232
Initializes a log block in the log buffer. */
UNIV_INLINE
void
log_block_init(
/*===========*/
233 234
	byte*	log_block,	/*!< in: pointer to the log buffer */
	lsn_t	lsn)		/*!< in: lsn within the log block */
osku's avatar
osku committed
235 236 237 238
{
	ulint	no;

	no = log_block_convert_lsn_to_no(lsn);
239

osku's avatar
osku committed
240 241 242 243 244 245
	log_block_set_hdr_no(log_block, no);

	log_block_set_data_len(log_block, LOG_BLOCK_HDR_SIZE);
	log_block_set_first_rec_group(log_block, 0);
}

246 247 248 249 250
/** Append a string to the log.
@param[in]	str		string
@param[in]	len		string length
@param[out]	start_lsn	start LSN of the log record
@return end lsn of the log record, zero if did not succeed */
osku's avatar
osku committed
251
UNIV_INLINE
252
lsn_t
osku's avatar
osku committed
253
log_reserve_and_write_fast(
254 255 256
	const void*	str,
	ulint		len,
	lsn_t*		start_lsn)
osku's avatar
osku committed
257
{
258
	mysql_mutex_assert_owner(&log_sys.mutex);
259
	ut_ad(len > 0);
osku's avatar
osku committed
260

261
	const ulint	data_len = len
262
		+ log_sys.buf_free % OS_FILE_LOG_BLOCK_SIZE;
osku's avatar
osku committed
263

264
	if (data_len >= log_sys.trailer_offset()) {
osku's avatar
osku committed
265

266 267
		/* The string does not fit within the current log block
		or the log block would become full */
osku's avatar
osku committed
268

269
		return(0);
osku's avatar
osku committed
270 271
	}

272 273
	lsn_t lsn = log_sys.get_lsn();
	*start_lsn = lsn;
274

275
	memcpy(log_sys.buf + log_sys.buf_free, str, len);
276 277 278

	log_block_set_data_len(
                reinterpret_cast<byte*>(ut_align_down(
279
                        log_sys.buf + log_sys.buf_free,
280 281
                        OS_FILE_LOG_BLOCK_SIZE)),
                data_len);
osku's avatar
osku committed
282

283
	log_sys.buf_free += len;
284

285
	ut_ad(log_sys.buf_free <= size_t{srv_log_buffer_size});
osku's avatar
osku committed
286

287 288
	lsn += len;
	log_sys.set_lsn(lsn);
osku's avatar
osku committed
289

290
	return lsn;
osku's avatar
osku committed
291 292
}

293
/***********************************************************************//**
osku's avatar
osku committed
294 295 296 297 298 299 300 301 302
Checks if there is need for a log buffer flush or a new checkpoint, and does
this if yes. Any database operation should call this when it has modified
more than about 4 pages. NOTE that this function may only be called when the
OS thread owns no synchronization objects except the dictionary mutex. */
UNIV_INLINE
void
log_free_check(void)
/*================*/
{
303 304 305 306
	/* During row_log_table_apply(), this function will be called while we
	are holding some latches. This is OK, as long as we are not holding
	any latches on buffer blocks. */

307
#ifdef UNIV_DEBUG
308
	static const latch_level_t latches[] = {
309
		SYNC_REDO_RSEG,		/* trx_purge_free_segment() */
310
		SYNC_DICT,		/* dict_sys.mutex during
311
					commit_try_rebuild() */
312
		SYNC_DICT_OPERATION,	/* dict_sys.latch X-latch during
313
					commit_try_rebuild() */
314
		SYNC_FTS_CACHE,		/* fts_cache_t::lock */
315 316 317
		SYNC_INDEX_TREE		/* index->lock */
	};
#endif /* UNIV_DEBUG */
osku's avatar
osku committed
318

319 320 321 322
	ut_ad(!sync_check_iterate(
		      sync_allowed_latches(latches,
					   latches + UT_ARR_SIZE(latches))));

323
	if (log_sys.check_flush_or_checkpoint()) {
osku's avatar
osku committed
324 325 326 327

		log_check_margins();
	}
}