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