1/*****************************************************************************
2
3Copyright (c) 1995, 2010, 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/log0log.ic
29Database log
30
31Created 12/9/1995 Heikki Tuuri
32*******************************************************/
33
34#include "os0file.h"
35#include "mach0data.h"
36#include "mtr0mtr.h"
37#include "srv0mon.h"
38
39#ifdef UNIV_LOG_DEBUG
40/******************************************************//**
41Checks by parsing that the catenated log segment for a single mtr is
42consistent. */
43UNIV_INTERN
44ibool
45log_check_log_recs(
46/*===============*/
47	const byte*	buf,		/*!< in: pointer to the start of
48					the log segment in the
49					log_sys->buf log buffer */
50	ulint		len,		/*!< in: segment length in bytes */
51	ib_uint64_t	buf_start_lsn);	/*!< in: buffer start lsn */
52#endif /* UNIV_LOG_DEBUG */
53
54/************************************************************//**
55Gets a log block flush bit.
56@return	TRUE if this block was the first to be written in a log flush */
57UNIV_INLINE
58ibool
59log_block_get_flush_bit(
60/*====================*/
61	const byte*	log_block)	/*!< in: log block */
62{
63	if (LOG_BLOCK_FLUSH_BIT_MASK
64	    & mach_read_from_4(log_block + LOG_BLOCK_HDR_NO)) {
65
66		return(TRUE);
67	}
68
69	return(FALSE);
70}
71
72/************************************************************//**
73Sets the log block flush bit. */
74UNIV_INLINE
75void
76log_block_set_flush_bit(
77/*====================*/
78	byte*	log_block,	/*!< in/out: log block */
79	ibool	val)		/*!< in: value to set */
80{
81	ulint	field;
82
83	field = mach_read_from_4(log_block + LOG_BLOCK_HDR_NO);
84
85	if (val) {
86		field = field | LOG_BLOCK_FLUSH_BIT_MASK;
87	} else {
88		field = field & ~LOG_BLOCK_FLUSH_BIT_MASK;
89	}
90
91	mach_write_to_4(log_block + LOG_BLOCK_HDR_NO, field);
92}
93
94/************************************************************//**
95Gets a log block number stored in the header.
96@return	log block number stored in the block header */
97UNIV_INLINE
98ulint
99log_block_get_hdr_no(
100/*=================*/
101	const byte*	log_block)	/*!< in: log block */
102{
103	return(~LOG_BLOCK_FLUSH_BIT_MASK
104	       & mach_read_from_4(log_block + LOG_BLOCK_HDR_NO));
105}
106
107/************************************************************//**
108Sets the log block number stored in the header; NOTE that this must be set
109before the flush bit! */
110UNIV_INLINE
111void
112log_block_set_hdr_no(
113/*=================*/
114	byte*	log_block,	/*!< in/out: log block */
115	ulint	n)		/*!< in: log block number: must be > 0 and
116				< LOG_BLOCK_FLUSH_BIT_MASK */
117{
118	ut_ad(n > 0);
119	ut_ad(n < LOG_BLOCK_FLUSH_BIT_MASK);
120
121	mach_write_to_4(log_block + LOG_BLOCK_HDR_NO, n);
122}
123
124/************************************************************//**
125Gets a log block data length.
126@return	log block data length measured as a byte offset from the block start */
127UNIV_INLINE
128ulint
129log_block_get_data_len(
130/*===================*/
131	const byte*	log_block)	/*!< in: log block */
132{
133	return(mach_read_from_2(log_block + LOG_BLOCK_HDR_DATA_LEN));
134}
135
136/************************************************************//**
137Sets the log block data length. */
138UNIV_INLINE
139void
140log_block_set_data_len(
141/*===================*/
142	byte*	log_block,	/*!< in/out: log block */
143	ulint	len)		/*!< in: data length */
144{
145	mach_write_to_2(log_block + LOG_BLOCK_HDR_DATA_LEN, len);
146}
147
148/************************************************************//**
149Gets a log block first mtr log record group offset.
150@return first mtr log record group byte offset from the block start, 0
151if none */
152UNIV_INLINE
153ulint
154log_block_get_first_rec_group(
155/*==========================*/
156	const byte*	log_block)	/*!< in: log block */
157{
158	return(mach_read_from_2(log_block + LOG_BLOCK_FIRST_REC_GROUP));
159}
160
161/************************************************************//**
162Sets the log block first mtr log record group offset. */
163UNIV_INLINE
164void
165log_block_set_first_rec_group(
166/*==========================*/
167	byte*	log_block,	/*!< in/out: log block */
168	ulint	offset)		/*!< in: offset, 0 if none */
169{
170	mach_write_to_2(log_block + LOG_BLOCK_FIRST_REC_GROUP, offset);
171}
172
173/************************************************************//**
174Gets a log block checkpoint number field (4 lowest bytes).
175@return	checkpoint no (4 lowest bytes) */
176UNIV_INLINE
177ulint
178log_block_get_checkpoint_no(
179/*========================*/
180	const byte*	log_block)	/*!< in: log block */
181{
182	return(mach_read_from_4(log_block + LOG_BLOCK_CHECKPOINT_NO));
183}
184
185/************************************************************//**
186Sets a log block checkpoint number field (4 lowest bytes). */
187UNIV_INLINE
188void
189log_block_set_checkpoint_no(
190/*========================*/
191	byte*		log_block,	/*!< in/out: log block */
192	ib_uint64_t	no)		/*!< in: checkpoint no */
193{
194	mach_write_to_4(log_block + LOG_BLOCK_CHECKPOINT_NO, (ulint) no);
195}
196
197/************************************************************//**
198Converts a lsn to a log block number.
199@return	log block number, it is > 0 and <= 1G */
200UNIV_INLINE
201ulint
202log_block_convert_lsn_to_no(
203/*========================*/
204	lsn_t	lsn)	/*!< in: lsn of a byte within the block */
205{
206	return(((ulint) (lsn / OS_FILE_LOG_BLOCK_SIZE) & 0x3FFFFFFFUL) + 1);
207}
208
209/************************************************************//**
210Calculates the checksum for a log block.
211@return	checksum */
212UNIV_INLINE
213ulint
214log_block_calc_checksum(
215/*====================*/
216	const byte*	block)	/*!< in: log block */
217{
218	ulint	sum;
219	ulint	sh;
220	ulint	i;
221
222	sum = 1;
223	sh = 0;
224
225	for (i = 0; i < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE; i++) {
226		ulint	b = (ulint) block[i];
227		sum &= 0x7FFFFFFFUL;
228		sum += b;
229		sum += b << sh;
230		sh++;
231		if (sh > 24) {
232			sh = 0;
233		}
234	}
235
236	return(sum);
237}
238
239/************************************************************//**
240Gets a log block checksum field value.
241@return	checksum */
242UNIV_INLINE
243ulint
244log_block_get_checksum(
245/*===================*/
246	const byte*	log_block)	/*!< in: log block */
247{
248	return(mach_read_from_4(log_block + OS_FILE_LOG_BLOCK_SIZE
249				- LOG_BLOCK_CHECKSUM));
250}
251
252/************************************************************//**
253Sets a log block checksum field value. */
254UNIV_INLINE
255void
256log_block_set_checksum(
257/*===================*/
258	byte*	log_block,	/*!< in/out: log block */
259	ulint	checksum)	/*!< in: checksum */
260{
261	mach_write_to_4(log_block + OS_FILE_LOG_BLOCK_SIZE
262			- LOG_BLOCK_CHECKSUM,
263			checksum);
264}
265
266/************************************************************//**
267Initializes a log block in the log buffer. */
268UNIV_INLINE
269void
270log_block_init(
271/*===========*/
272	byte*	log_block,	/*!< in: pointer to the log buffer */
273	lsn_t	lsn)		/*!< in: lsn within the log block */
274{
275	ulint	no;
276
277	ut_ad(mutex_own(&(log_sys->mutex)));
278
279	no = log_block_convert_lsn_to_no(lsn);
280
281	log_block_set_hdr_no(log_block, no);
282
283	log_block_set_data_len(log_block, LOG_BLOCK_HDR_SIZE);
284	log_block_set_first_rec_group(log_block, 0);
285}
286
287/************************************************************//**
288Initializes a log block in the log buffer in the old format, where there
289was no checksum yet. */
290UNIV_INLINE
291void
292log_block_init_in_old_format(
293/*=========================*/
294	byte*	log_block,	/*!< in: pointer to the log buffer */
295	lsn_t	lsn)		/*!< in: lsn within the log block */
296{
297	ulint	no;
298
299	ut_ad(mutex_own(&(log_sys->mutex)));
300
301	no = log_block_convert_lsn_to_no(lsn);
302
303	log_block_set_hdr_no(log_block, no);
304	mach_write_to_4(log_block + OS_FILE_LOG_BLOCK_SIZE
305			- LOG_BLOCK_CHECKSUM, no);
306	log_block_set_data_len(log_block, LOG_BLOCK_HDR_SIZE);
307	log_block_set_first_rec_group(log_block, 0);
308}
309
310#ifndef UNIV_HOTBACKUP
311/************************************************************//**
312Writes to the log the string given. The log must be released with
313log_release.
314@return	end lsn of the log record, zero if did not succeed */
315UNIV_INLINE
316lsn_t
317log_reserve_and_write_fast(
318/*=======================*/
319	const void*	str,	/*!< in: string */
320	ulint		len,	/*!< in: string length */
321	lsn_t*		start_lsn)/*!< out: start lsn of the log record */
322{
323	ulint		data_len;
324#ifdef UNIV_LOG_LSN_DEBUG
325	/* length of the LSN pseudo-record */
326	ulint		lsn_len;
327#endif /* UNIV_LOG_LSN_DEBUG */
328
329	mutex_enter(&log_sys->mutex);
330#ifdef UNIV_LOG_LSN_DEBUG
331	lsn_len = 1
332		+ mach_get_compressed_size(log_sys->lsn >> 32)
333		+ mach_get_compressed_size(log_sys->lsn & 0xFFFFFFFFUL);
334#endif /* UNIV_LOG_LSN_DEBUG */
335
336	data_len = len
337#ifdef UNIV_LOG_LSN_DEBUG
338		+ lsn_len
339#endif /* UNIV_LOG_LSN_DEBUG */
340		+ log_sys->buf_free % OS_FILE_LOG_BLOCK_SIZE;
341
342	if (data_len >= OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) {
343
344		/* The string does not fit within the current log block
345		or the log block would become full */
346
347		mutex_exit(&log_sys->mutex);
348
349		return(0);
350	}
351
352	*start_lsn = log_sys->lsn;
353
354#ifdef UNIV_LOG_LSN_DEBUG
355	{
356		/* Write the LSN pseudo-record. */
357		byte* b = &log_sys->buf[log_sys->buf_free];
358		*b++ = MLOG_LSN | (MLOG_SINGLE_REC_FLAG & *(const byte*) str);
359		/* Write the LSN in two parts,
360		as a pseudo page number and space id. */
361		b += mach_write_compressed(b, log_sys->lsn >> 32);
362		b += mach_write_compressed(b, log_sys->lsn & 0xFFFFFFFFUL);
363		ut_a(b - lsn_len == &log_sys->buf[log_sys->buf_free]);
364
365		memcpy(b, str, len);
366		len += lsn_len;
367	}
368#else /* UNIV_LOG_LSN_DEBUG */
369	memcpy(log_sys->buf + log_sys->buf_free, str, len);
370#endif /* UNIV_LOG_LSN_DEBUG */
371
372	log_block_set_data_len((byte*) ut_align_down(log_sys->buf
373						     + log_sys->buf_free,
374						     OS_FILE_LOG_BLOCK_SIZE),
375			       data_len);
376#ifdef UNIV_LOG_DEBUG
377	log_sys->old_buf_free = log_sys->buf_free;
378	log_sys->old_lsn = log_sys->lsn;
379#endif
380	log_sys->buf_free += len;
381
382	ut_ad(log_sys->buf_free <= log_sys->buf_size);
383
384	log_sys->lsn += len;
385
386	MONITOR_SET(MONITOR_LSN_CHECKPOINT_AGE,
387		    log_sys->lsn - log_sys->last_checkpoint_lsn);
388
389#ifdef UNIV_LOG_DEBUG
390	log_check_log_recs(log_sys->buf + log_sys->old_buf_free,
391			   log_sys->buf_free - log_sys->old_buf_free,
392			   log_sys->old_lsn);
393#endif
394	return(log_sys->lsn);
395}
396
397/***********************************************************************//**
398Releases the log mutex. */
399UNIV_INLINE
400void
401log_release(void)
402/*=============*/
403{
404	mutex_exit(&(log_sys->mutex));
405}
406
407/************************************************************//**
408Gets the current lsn.
409@return	current lsn */
410UNIV_INLINE
411lsn_t
412log_get_lsn(void)
413/*=============*/
414{
415	lsn_t	lsn;
416
417	mutex_enter(&(log_sys->mutex));
418
419	lsn = log_sys->lsn;
420
421	mutex_exit(&(log_sys->mutex));
422
423	return(lsn);
424}
425
426/****************************************************************
427Gets the log group capacity. It is OK to read the value without
428holding log_sys->mutex because it is constant.
429@return	log group capacity */
430UNIV_INLINE
431lsn_t
432log_get_capacity(void)
433/*==================*/
434{
435	return(log_sys->log_group_capacity);
436}
437
438/****************************************************************
439Get log_sys::max_modified_age_async. It is OK to read the value without
440holding log_sys::mutex because it is constant.
441@return	max_modified_age_async */
442UNIV_INLINE
443lsn_t
444log_get_max_modified_age_async(void)
445/*================================*/
446{
447	return(log_sys->max_modified_age_async);
448}
449
450/***********************************************************************//**
451Checks if there is need for a log buffer flush or a new checkpoint, and does
452this if yes. Any database operation should call this when it has modified
453more than about 4 pages. NOTE that this function may only be called when the
454OS thread owns no synchronization objects except the dictionary mutex. */
455UNIV_INLINE
456void
457log_free_check(void)
458/*================*/
459{
460
461#ifdef UNIV_SYNC_DEBUG
462	ut_ad(sync_thread_levels_empty_except_dict());
463#endif /* UNIV_SYNC_DEBUG */
464
465	if (log_sys->check_flush_or_checkpoint) {
466
467		log_check_margins();
468	}
469}
470#endif /* !UNIV_HOTBACKUP */
471