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