00001 /****************************************************** 00002 Mini-transaction log routines 00003 00004 (c) 1995 Innobase Oy 00005 00006 Created 12/7/1995 Heikki Tuuri 00007 *******************************************************/ 00008 00009 #include "mtr0log.h" 00010 00011 #ifdef UNIV_NONINL 00012 #include "mtr0log.ic" 00013 #endif 00014 00015 #include "buf0buf.h" 00016 #include "dict0boot.h" 00017 #include "log0recv.h" 00018 #include "page0page.h" 00019 00020 /************************************************************ 00021 Catenates n bytes to the mtr log. */ 00022 00023 void 00024 mlog_catenate_string( 00025 /*=================*/ 00026 mtr_t* mtr, /* in: mtr */ 00027 const byte* str, /* in: string to write */ 00028 ulint len) /* in: string length */ 00029 { 00030 dyn_array_t* mlog; 00031 00032 if (mtr_get_log_mode(mtr) == MTR_LOG_NONE) { 00033 00034 return; 00035 } 00036 00037 mlog = &(mtr->log); 00038 00039 dyn_push_string(mlog, str, len); 00040 } 00041 00042 /************************************************************ 00043 Writes the initial part of a log record consisting of one-byte item 00044 type and four-byte space and page numbers. Also pushes info 00045 to the mtr memo that a buffer page has been modified. */ 00046 00047 void 00048 mlog_write_initial_log_record( 00049 /*==========================*/ 00050 byte* ptr, /* in: pointer to (inside) a buffer frame holding the 00051 file page where modification is made */ 00052 byte type, /* in: log item type: MLOG_1BYTE, ... */ 00053 mtr_t* mtr) /* in: mini-transaction handle */ 00054 { 00055 byte* log_ptr; 00056 00057 ut_ad(type <= MLOG_BIGGEST_TYPE); 00058 ut_ad(type > MLOG_8BYTES); 00059 00060 if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) { 00061 fprintf(stderr, 00062 "InnoDB: Error: trying to write to a stray memory location %p\n", ptr); 00063 ut_error; 00064 } 00065 00066 log_ptr = mlog_open(mtr, 11); 00067 00068 /* If no logging is requested, we may return now */ 00069 if (log_ptr == NULL) { 00070 00071 return; 00072 } 00073 00074 log_ptr = mlog_write_initial_log_record_fast(ptr, type, log_ptr, mtr); 00075 00076 mlog_close(mtr, log_ptr); 00077 } 00078 00079 /************************************************************ 00080 Parses an initial log record written by mlog_write_initial_log_record. */ 00081 00082 byte* 00083 mlog_parse_initial_log_record( 00084 /*==========================*/ 00085 /* out: parsed record end, NULL if not a complete 00086 record */ 00087 byte* ptr, /* in: buffer */ 00088 byte* end_ptr,/* in: buffer end */ 00089 byte* type, /* out: log record type: MLOG_1BYTE, ... */ 00090 ulint* space, /* out: space id */ 00091 ulint* page_no)/* out: page number */ 00092 { 00093 if (end_ptr < ptr + 1) { 00094 00095 return(NULL); 00096 } 00097 00098 *type = (byte)((ulint)*ptr & ~MLOG_SINGLE_REC_FLAG); 00099 ut_ad(*type <= MLOG_BIGGEST_TYPE); 00100 00101 ptr++; 00102 00103 if (end_ptr < ptr + 2) { 00104 00105 return(NULL); 00106 } 00107 00108 ptr = mach_parse_compressed(ptr, end_ptr, space); 00109 00110 if (ptr == NULL) { 00111 00112 return(NULL); 00113 } 00114 00115 ptr = mach_parse_compressed(ptr, end_ptr, page_no); 00116 00117 return(ptr); 00118 } 00119 00120 /************************************************************ 00121 Parses a log record written by mlog_write_ulint or mlog_write_dulint. */ 00122 00123 byte* 00124 mlog_parse_nbytes( 00125 /*==============*/ 00126 /* out: parsed record end, NULL if not a complete 00127 record or a corrupt record */ 00128 ulint type, /* in: log record type: MLOG_1BYTE, ... */ 00129 byte* ptr, /* in: buffer */ 00130 byte* end_ptr,/* in: buffer end */ 00131 byte* page) /* in: page where to apply the log record, or NULL */ 00132 { 00133 ulint offset; 00134 ulint val; 00135 dulint dval; 00136 00137 ut_a(type <= MLOG_8BYTES); 00138 00139 if (end_ptr < ptr + 2) { 00140 00141 return(NULL); 00142 } 00143 00144 offset = mach_read_from_2(ptr); 00145 ptr += 2; 00146 00147 if (offset >= UNIV_PAGE_SIZE) { 00148 recv_sys->found_corrupt_log = TRUE; 00149 00150 return(NULL); 00151 } 00152 00153 if (type == MLOG_8BYTES) { 00154 ptr = mach_dulint_parse_compressed(ptr, end_ptr, &dval); 00155 00156 if (ptr == NULL) { 00157 00158 return(NULL); 00159 } 00160 00161 if (page) { 00162 mach_write_to_8(page + offset, dval); 00163 } 00164 00165 return(ptr); 00166 } 00167 00168 ptr = mach_parse_compressed(ptr, end_ptr, &val); 00169 00170 if (ptr == NULL) { 00171 00172 return(NULL); 00173 } 00174 00175 if (type == MLOG_1BYTE) { 00176 if (val > 0xFFUL) { 00177 recv_sys->found_corrupt_log = TRUE; 00178 00179 return(NULL); 00180 } 00181 } else if (type == MLOG_2BYTES) { 00182 if (val > 0xFFFFUL) { 00183 recv_sys->found_corrupt_log = TRUE; 00184 00185 return(NULL); 00186 } 00187 } else { 00188 if (type != MLOG_4BYTES) { 00189 recv_sys->found_corrupt_log = TRUE; 00190 00191 return(NULL); 00192 } 00193 } 00194 00195 if (page) { 00196 if (type == MLOG_1BYTE) { 00197 mach_write_to_1(page + offset, val); 00198 } else if (type == MLOG_2BYTES) { 00199 mach_write_to_2(page + offset, val); 00200 } else { 00201 ut_a(type == MLOG_4BYTES); 00202 mach_write_to_4(page + offset, val); 00203 } 00204 } 00205 00206 return(ptr); 00207 } 00208 00209 /************************************************************ 00210 Writes 1 - 4 bytes to a file page buffered in the buffer pool. 00211 Writes the corresponding log record to the mini-transaction log. */ 00212 00213 void 00214 mlog_write_ulint( 00215 /*=============*/ 00216 byte* ptr, /* in: pointer where to write */ 00217 ulint val, /* in: value to write */ 00218 byte type, /* in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */ 00219 mtr_t* mtr) /* in: mini-transaction handle */ 00220 { 00221 byte* log_ptr; 00222 00223 if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) { 00224 fprintf(stderr, 00225 "InnoDB: Error: trying to write to a stray memory location %p\n", ptr); 00226 ut_error; 00227 } 00228 00229 if (type == MLOG_1BYTE) { 00230 mach_write_to_1(ptr, val); 00231 } else if (type == MLOG_2BYTES) { 00232 mach_write_to_2(ptr, val); 00233 } else { 00234 ut_ad(type == MLOG_4BYTES); 00235 mach_write_to_4(ptr, val); 00236 } 00237 00238 log_ptr = mlog_open(mtr, 11 + 2 + 5); 00239 00240 /* If no logging is requested, we may return now */ 00241 if (log_ptr == NULL) { 00242 00243 return; 00244 } 00245 00246 log_ptr = mlog_write_initial_log_record_fast(ptr, type, log_ptr, mtr); 00247 00248 mach_write_to_2(log_ptr, ptr - buf_frame_align(ptr)); 00249 log_ptr += 2; 00250 00251 log_ptr += mach_write_compressed(log_ptr, val); 00252 00253 mlog_close(mtr, log_ptr); 00254 } 00255 00256 /************************************************************ 00257 Writes 8 bytes to a file page buffered in the buffer pool. 00258 Writes the corresponding log record to the mini-transaction log. */ 00259 00260 void 00261 mlog_write_dulint( 00262 /*==============*/ 00263 byte* ptr, /* in: pointer where to write */ 00264 dulint val, /* in: value to write */ 00265 mtr_t* mtr) /* in: mini-transaction handle */ 00266 { 00267 byte* log_ptr; 00268 00269 if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) { 00270 fprintf(stderr, 00271 "InnoDB: Error: trying to write to a stray memory location %p\n", ptr); 00272 ut_error; 00273 } 00274 00275 ut_ad(ptr && mtr); 00276 00277 mach_write_to_8(ptr, val); 00278 00279 log_ptr = mlog_open(mtr, 11 + 2 + 9); 00280 00281 /* If no logging is requested, we may return now */ 00282 if (log_ptr == NULL) { 00283 00284 return; 00285 } 00286 00287 log_ptr = mlog_write_initial_log_record_fast(ptr, MLOG_8BYTES, 00288 log_ptr, mtr); 00289 00290 mach_write_to_2(log_ptr, ptr - buf_frame_align(ptr)); 00291 log_ptr += 2; 00292 00293 log_ptr += mach_dulint_write_compressed(log_ptr, val); 00294 00295 mlog_close(mtr, log_ptr); 00296 } 00297 00298 /************************************************************ 00299 Writes a string to a file page buffered in the buffer pool. Writes the 00300 corresponding log record to the mini-transaction log. */ 00301 00302 void 00303 mlog_write_string( 00304 /*==============*/ 00305 byte* ptr, /* in: pointer where to write */ 00306 const byte* str, /* in: string to write */ 00307 ulint len, /* in: string length */ 00308 mtr_t* mtr) /* in: mini-transaction handle */ 00309 { 00310 byte* log_ptr; 00311 00312 if (UNIV_UNLIKELY(ptr < buf_pool->frame_zero) 00313 || UNIV_UNLIKELY(ptr >= buf_pool->high_end)) { 00314 fprintf(stderr, 00315 "InnoDB: Error: trying to write to a stray memory location %p\n", ptr); 00316 ut_error; 00317 } 00318 ut_ad(ptr && mtr); 00319 ut_a(len < UNIV_PAGE_SIZE); 00320 00321 ut_memcpy(ptr, str, len); 00322 00323 log_ptr = mlog_open(mtr, 30); 00324 00325 /* If no logging is requested, we may return now */ 00326 if (log_ptr == NULL) { 00327 00328 return; 00329 } 00330 00331 log_ptr = mlog_write_initial_log_record_fast(ptr, MLOG_WRITE_STRING, 00332 log_ptr, mtr); 00333 mach_write_to_2(log_ptr, ptr - buf_frame_align(ptr)); 00334 log_ptr += 2; 00335 00336 mach_write_to_2(log_ptr, len); 00337 log_ptr += 2; 00338 00339 mlog_close(mtr, log_ptr); 00340 00341 mlog_catenate_string(mtr, str, len); 00342 } 00343 00344 /************************************************************ 00345 Parses a log record written by mlog_write_string. */ 00346 00347 byte* 00348 mlog_parse_string( 00349 /*==============*/ 00350 /* out: parsed record end, NULL if not a complete 00351 record */ 00352 byte* ptr, /* in: buffer */ 00353 byte* end_ptr,/* in: buffer end */ 00354 byte* page) /* in: page where to apply the log record, or NULL */ 00355 { 00356 ulint offset; 00357 ulint len; 00358 00359 if (end_ptr < ptr + 4) { 00360 00361 return(NULL); 00362 } 00363 00364 offset = mach_read_from_2(ptr); 00365 ptr += 2; 00366 00367 if (offset >= UNIV_PAGE_SIZE) { 00368 recv_sys->found_corrupt_log = TRUE; 00369 00370 return(NULL); 00371 } 00372 00373 len = mach_read_from_2(ptr); 00374 ptr += 2; 00375 00376 ut_a(len + offset < UNIV_PAGE_SIZE); 00377 00378 if (end_ptr < ptr + len) { 00379 00380 return(NULL); 00381 } 00382 00383 if (page) { 00384 ut_memcpy(page + offset, ptr, len); 00385 } 00386 00387 return(ptr + len); 00388 } 00389 00390 /************************************************************ 00391 Opens a buffer for mlog, writes the initial log record and, 00392 if needed, the field lengths of an index. */ 00393 00394 byte* 00395 mlog_open_and_write_index( 00396 /*======================*/ 00397 /* out: buffer, NULL if log mode 00398 MTR_LOG_NONE */ 00399 mtr_t* mtr, /* in: mtr */ 00400 byte* rec, /* in: index record or page */ 00401 dict_index_t* index, /* in: record descriptor */ 00402 byte type, /* in: log item type */ 00403 ulint size) /* in: requested buffer size in bytes 00404 (if 0, calls mlog_close() and returns NULL) */ 00405 { 00406 byte* log_ptr; 00407 const byte* log_start; 00408 const byte* log_end; 00409 00410 ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table)); 00411 00412 if (!page_rec_is_comp(rec)) { 00413 log_start = log_ptr = mlog_open(mtr, 11 + size); 00414 if (!log_ptr) { 00415 return(NULL); /* logging is disabled */ 00416 } 00417 log_ptr = mlog_write_initial_log_record_fast(rec, type, 00418 log_ptr, mtr); 00419 log_end = log_ptr + 11 + size; 00420 } else { 00421 ulint i; 00422 ulint n = dict_index_get_n_fields(index); 00423 /* total size needed */ 00424 ulint total = 11 + size + (n + 2) * 2; 00425 ulint alloc = total; 00426 /* allocate at most DYN_ARRAY_DATA_SIZE at a time */ 00427 if (alloc > DYN_ARRAY_DATA_SIZE) { 00428 alloc = DYN_ARRAY_DATA_SIZE; 00429 } 00430 log_start = log_ptr = mlog_open(mtr, alloc); 00431 if (!log_ptr) { 00432 return(NULL); /* logging is disabled */ 00433 } 00434 log_end = log_ptr + alloc; 00435 log_ptr = mlog_write_initial_log_record_fast(rec, type, 00436 log_ptr, mtr); 00437 mach_write_to_2(log_ptr, n); 00438 log_ptr += 2; 00439 mach_write_to_2(log_ptr, 00440 dict_index_get_n_unique_in_tree(index)); 00441 log_ptr += 2; 00442 for (i = 0; i < n; i++) { 00443 dict_field_t* field; 00444 dtype_t* type; 00445 ulint len; 00446 field = dict_index_get_nth_field(index, i); 00447 type = dict_col_get_type(dict_field_get_col(field)); 00448 len = field->fixed_len; 00449 ut_ad(len < 0x7fff); 00450 if (len == 0 && (dtype_get_len(type) > 255 00451 || dtype_get_mtype(type) == DATA_BLOB)) { 00452 /* variable-length field 00453 with maximum length > 255 */ 00454 len = 0x7fff; 00455 } 00456 if (dtype_get_prtype(type) & DATA_NOT_NULL) { 00457 len |= 0x8000; 00458 } 00459 if (log_ptr + 2 > log_end) { 00460 mlog_close(mtr, log_ptr); 00461 ut_a(total > (ulint) (log_ptr - log_start)); 00462 total -= log_ptr - log_start; 00463 alloc = total; 00464 if (alloc > DYN_ARRAY_DATA_SIZE) { 00465 alloc = DYN_ARRAY_DATA_SIZE; 00466 } 00467 log_start = log_ptr = mlog_open(mtr, alloc); 00468 if (!log_ptr) { 00469 return(NULL); /* logging is disabled */ 00470 } 00471 log_end = log_ptr + alloc; 00472 } 00473 mach_write_to_2(log_ptr, len); 00474 log_ptr += 2; 00475 } 00476 } 00477 if (size == 0) { 00478 mlog_close(mtr, log_ptr); 00479 log_ptr = NULL; 00480 } else if (log_ptr + size > log_end) { 00481 mlog_close(mtr, log_ptr); 00482 log_ptr = mlog_open(mtr, size); 00483 } 00484 return(log_ptr); 00485 } 00486 00487 /************************************************************ 00488 Parses a log record written by mlog_open_and_write_index. */ 00489 00490 byte* 00491 mlog_parse_index( 00492 /*=============*/ 00493 /* out: parsed record end, 00494 NULL if not a complete record */ 00495 byte* ptr, /* in: buffer */ 00496 byte* end_ptr,/* in: buffer end */ 00497 /* out: new value of log_ptr */ 00498 ibool comp, /* in: TRUE=compact record format */ 00499 dict_index_t** index) /* out, own: dummy index */ 00500 { 00501 ulint i, n, n_uniq; 00502 dict_table_t* table; 00503 dict_index_t* ind; 00504 00505 ut_ad(comp == FALSE || comp == TRUE); 00506 00507 if (comp) { 00508 if (end_ptr < ptr + 4) { 00509 return(NULL); 00510 } 00511 n = mach_read_from_2(ptr); 00512 ptr += 2; 00513 n_uniq = mach_read_from_2(ptr); 00514 ut_ad(n_uniq <= n); 00515 if (end_ptr < ptr + (n + 1) * 2) { 00516 return(NULL); 00517 } 00518 } else { 00519 n = n_uniq = 1; 00520 } 00521 table = dict_mem_table_create("LOG_DUMMY", DICT_HDR_SPACE, n, 00522 comp ? DICT_TF_COMPACT : 0); 00523 ind = dict_mem_index_create("LOG_DUMMY", "LOG_DUMMY", 00524 DICT_HDR_SPACE, 0, n); 00525 ind->table = table; 00526 ind->n_uniq = n_uniq; 00527 if (n_uniq != n) { 00528 ind->type = DICT_CLUSTERED; 00529 } 00530 /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */ 00531 ind->cached = TRUE; 00532 if (comp) { 00533 for (i = 0; i < n; i++) { 00534 ulint len = mach_read_from_2(ptr += 2); 00535 /* The high-order bit of len is the NOT NULL flag; 00536 the rest is 0 or 0x7fff for variable-length fields, 00537 and 1..0x7ffe for fixed-length fields. */ 00538 dict_mem_table_add_col(table, "DUMMY", 00539 ((len + 1) & 0x7fff) <= 1 00540 ? DATA_BINARY 00541 : DATA_FIXBINARY, 00542 len & 0x8000 ? DATA_NOT_NULL : 0, 00543 len & 0x7fff, 0); 00544 dict_index_add_col(ind, 00545 dict_table_get_nth_col(table, i), 0); 00546 } 00547 ptr += 2; 00548 } 00549 *index = ind; 00550 return(ptr); 00551 }
1.4.7

