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