diff options
Diffstat (limited to 'storage/xtradb/mtr')
-rw-r--r-- | storage/xtradb/mtr/mtr0log.c | 609 | ||||
-rw-r--r-- | storage/xtradb/mtr/mtr0mtr.c | 345 |
2 files changed, 954 insertions, 0 deletions
diff --git a/storage/xtradb/mtr/mtr0log.c b/storage/xtradb/mtr/mtr0log.c new file mode 100644 index 00000000000..0fe66d08c05 --- /dev/null +++ b/storage/xtradb/mtr/mtr0log.c @@ -0,0 +1,609 @@ +/***************************************************************************** + +Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +/****************************************************** +Mini-transaction log routines + +Created 12/7/1995 Heikki Tuuri +*******************************************************/ + +#include "mtr0log.h" + +#ifdef UNIV_NONINL +#include "mtr0log.ic" +#endif + +#include "buf0buf.h" +#include "dict0boot.h" +#include "log0recv.h" +#include "page0page.h" + +/************************************************************ +Catenates n bytes to the mtr log. */ +UNIV_INTERN +void +mlog_catenate_string( +/*=================*/ + mtr_t* mtr, /* in: mtr */ + const byte* str, /* in: string to write */ + ulint len) /* in: string length */ +{ + dyn_array_t* mlog; + + if (mtr_get_log_mode(mtr) == MTR_LOG_NONE) { + + return; + } + + mlog = &(mtr->log); + + dyn_push_string(mlog, str, len); +} + +/************************************************************ +Writes the initial part of a log record consisting of one-byte item +type and four-byte space and page numbers. Also pushes info +to the mtr memo that a buffer page has been modified. */ +UNIV_INTERN +void +mlog_write_initial_log_record( +/*==========================*/ + const byte* ptr, /* in: pointer to (inside) a buffer + frame holding the file page where + modification is made */ + byte type, /* in: log item type: MLOG_1BYTE, ... */ + mtr_t* mtr) /* in: mini-transaction handle */ +{ + byte* log_ptr; + + ut_ad(type <= MLOG_BIGGEST_TYPE); + ut_ad(type > MLOG_8BYTES); + + log_ptr = mlog_open(mtr, 11); + + /* If no logging is requested, we may return now */ + if (log_ptr == NULL) { + + return; + } + + log_ptr = mlog_write_initial_log_record_fast(ptr, type, log_ptr, mtr); + + mlog_close(mtr, log_ptr); +} + +/************************************************************ +Parses an initial log record written by mlog_write_initial_log_record. */ +UNIV_INTERN +byte* +mlog_parse_initial_log_record( +/*==========================*/ + /* out: parsed record end, NULL if not a complete + record */ + byte* ptr, /* in: buffer */ + byte* end_ptr,/* in: buffer end */ + byte* type, /* out: log record type: MLOG_1BYTE, ... */ + ulint* space, /* out: space id */ + ulint* page_no)/* out: page number */ +{ + if (end_ptr < ptr + 1) { + + return(NULL); + } + + *type = (byte)((ulint)*ptr & ~MLOG_SINGLE_REC_FLAG); + ut_ad(*type <= MLOG_BIGGEST_TYPE); + + ptr++; + + if (end_ptr < ptr + 2) { + + return(NULL); + } + + ptr = mach_parse_compressed(ptr, end_ptr, space); + + if (ptr == NULL) { + + return(NULL); + } + + ptr = mach_parse_compressed(ptr, end_ptr, page_no); + + return(ptr); +} + +/************************************************************ +Parses a log record written by mlog_write_ulint or mlog_write_dulint. */ +UNIV_INTERN +byte* +mlog_parse_nbytes( +/*==============*/ + /* out: parsed record end, NULL if not a complete + record or a corrupt record */ + ulint type, /* in: log record type: MLOG_1BYTE, ... */ + byte* ptr, /* in: buffer */ + byte* end_ptr,/* in: buffer end */ + byte* page, /* in: page where to apply the log record, or NULL */ + void* page_zip)/* in/out: compressed page, or NULL */ +{ + ulint offset; + ulint val; + dulint dval; + + ut_a(type <= MLOG_8BYTES); + ut_a(!page || !page_zip || fil_page_get_type(page) != FIL_PAGE_INDEX); + + if (end_ptr < ptr + 2) { + + return(NULL); + } + + offset = mach_read_from_2(ptr); + ptr += 2; + + if (offset >= UNIV_PAGE_SIZE) { + recv_sys->found_corrupt_log = TRUE; + + return(NULL); + } + + if (type == MLOG_8BYTES) { + ptr = mach_dulint_parse_compressed(ptr, end_ptr, &dval); + + if (ptr == NULL) { + + return(NULL); + } + + if (page) { + if (UNIV_LIKELY_NULL(page_zip)) { + mach_write_to_8 + (((page_zip_des_t*) page_zip)->data + + offset, dval); + } + mach_write_to_8(page + offset, dval); + } + + return(ptr); + } + + ptr = mach_parse_compressed(ptr, end_ptr, &val); + + if (ptr == NULL) { + + return(NULL); + } + + switch (type) { + case MLOG_1BYTE: + if (UNIV_UNLIKELY(val > 0xFFUL)) { + goto corrupt; + } + if (page) { + if (UNIV_LIKELY_NULL(page_zip)) { + mach_write_to_1 + (((page_zip_des_t*) page_zip)->data + + offset, val); + } + mach_write_to_1(page + offset, val); + } + break; + case MLOG_2BYTES: + if (UNIV_UNLIKELY(val > 0xFFFFUL)) { + goto corrupt; + } + if (page) { + if (UNIV_LIKELY_NULL(page_zip)) { + mach_write_to_2 + (((page_zip_des_t*) page_zip)->data + + offset, val); + } + mach_write_to_2(page + offset, val); + } + break; + case MLOG_4BYTES: + if (page) { + if (UNIV_LIKELY_NULL(page_zip)) { + mach_write_to_4 + (((page_zip_des_t*) page_zip)->data + + offset, val); + } + mach_write_to_4(page + offset, val); + } + break; + default: + corrupt: + recv_sys->found_corrupt_log = TRUE; + ptr = NULL; + } + + return(ptr); +} + +/************************************************************ +Writes 1 - 4 bytes to a file page buffered in the buffer pool. +Writes the corresponding log record to the mini-transaction log. */ +UNIV_INTERN +void +mlog_write_ulint( +/*=============*/ + byte* ptr, /* in: pointer where to write */ + ulint val, /* in: value to write */ + byte type, /* in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */ + mtr_t* mtr) /* in: mini-transaction handle */ +{ + byte* log_ptr; + + switch (type) { + case MLOG_1BYTE: + mach_write_to_1(ptr, val); + break; + case MLOG_2BYTES: + mach_write_to_2(ptr, val); + break; + case MLOG_4BYTES: + mach_write_to_4(ptr, val); + break; + default: + ut_error; + } + + log_ptr = mlog_open(mtr, 11 + 2 + 5); + + /* If no logging is requested, we may return now */ + if (log_ptr == NULL) { + + return; + } + + log_ptr = mlog_write_initial_log_record_fast(ptr, type, log_ptr, mtr); + + mach_write_to_2(log_ptr, page_offset(ptr)); + log_ptr += 2; + + log_ptr += mach_write_compressed(log_ptr, val); + + mlog_close(mtr, log_ptr); +} + +/************************************************************ +Writes 8 bytes to a file page buffered in the buffer pool. +Writes the corresponding log record to the mini-transaction log. */ +UNIV_INTERN +void +mlog_write_dulint( +/*==============*/ + byte* ptr, /* in: pointer where to write */ + dulint val, /* in: value to write */ + mtr_t* mtr) /* in: mini-transaction handle */ +{ + byte* log_ptr; + + ut_ad(ptr && mtr); + + mach_write_to_8(ptr, val); + + log_ptr = mlog_open(mtr, 11 + 2 + 9); + + /* If no logging is requested, we may return now */ + if (log_ptr == NULL) { + + return; + } + + log_ptr = mlog_write_initial_log_record_fast(ptr, MLOG_8BYTES, + log_ptr, mtr); + + mach_write_to_2(log_ptr, page_offset(ptr)); + log_ptr += 2; + + log_ptr += mach_dulint_write_compressed(log_ptr, val); + + mlog_close(mtr, log_ptr); +} + +/************************************************************ +Writes a string to a file page buffered in the buffer pool. Writes the +corresponding log record to the mini-transaction log. */ +UNIV_INTERN +void +mlog_write_string( +/*==============*/ + byte* ptr, /* in: pointer where to write */ + const byte* str, /* in: string to write */ + ulint len, /* in: string length */ + mtr_t* mtr) /* in: mini-transaction handle */ +{ + ut_ad(ptr && mtr); + ut_a(len < UNIV_PAGE_SIZE); + + memcpy(ptr, str, len); + + mlog_log_string(ptr, len, mtr); +} + +/************************************************************ +Logs a write of a string to a file page buffered in the buffer pool. +Writes the corresponding log record to the mini-transaction log. */ +UNIV_INTERN +void +mlog_log_string( +/*============*/ + byte* ptr, /* in: pointer written to */ + ulint len, /* in: string length */ + mtr_t* mtr) /* in: mini-transaction handle */ +{ + byte* log_ptr; + + ut_ad(ptr && mtr); + ut_ad(len <= UNIV_PAGE_SIZE); + + log_ptr = mlog_open(mtr, 30); + + /* If no logging is requested, we may return now */ + if (log_ptr == NULL) { + + return; + } + + log_ptr = mlog_write_initial_log_record_fast(ptr, MLOG_WRITE_STRING, + log_ptr, mtr); + mach_write_to_2(log_ptr, page_offset(ptr)); + log_ptr += 2; + + mach_write_to_2(log_ptr, len); + log_ptr += 2; + + mlog_close(mtr, log_ptr); + + mlog_catenate_string(mtr, ptr, len); +} + +/************************************************************ +Parses a log record written by mlog_write_string. */ +UNIV_INTERN +byte* +mlog_parse_string( +/*==============*/ + /* out: parsed record end, NULL if not a complete + record */ + byte* ptr, /* in: buffer */ + byte* end_ptr,/* in: buffer end */ + byte* page, /* in: page where to apply the log record, or NULL */ + void* page_zip)/* in/out: compressed page, or NULL */ +{ + ulint offset; + ulint len; + + ut_a(!page || !page_zip || fil_page_get_type(page) != FIL_PAGE_INDEX); + + if (end_ptr < ptr + 4) { + + return(NULL); + } + + offset = mach_read_from_2(ptr); + ptr += 2; + len = mach_read_from_2(ptr); + ptr += 2; + + if (UNIV_UNLIKELY(offset >= UNIV_PAGE_SIZE) + || UNIV_UNLIKELY(len + offset) > UNIV_PAGE_SIZE) { + recv_sys->found_corrupt_log = TRUE; + + return(NULL); + } + + if (end_ptr < ptr + len) { + + return(NULL); + } + + if (page) { + if (UNIV_LIKELY_NULL(page_zip)) { + memcpy(((page_zip_des_t*) page_zip)->data + + offset, ptr, len); + } + memcpy(page + offset, ptr, len); + } + + return(ptr + len); +} + +/************************************************************ +Opens a buffer for mlog, writes the initial log record and, +if needed, the field lengths of an index. */ +UNIV_INTERN +byte* +mlog_open_and_write_index( +/*======================*/ + /* out: buffer, NULL if log mode + MTR_LOG_NONE */ + mtr_t* mtr, /* in: mtr */ + byte* rec, /* in: index record or page */ + dict_index_t* index, /* in: record descriptor */ + byte type, /* in: log item type */ + ulint size) /* in: requested buffer size in bytes + (if 0, calls mlog_close() and returns NULL) */ +{ + byte* log_ptr; + const byte* log_start; + const byte* log_end; + + ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table)); + + if (!page_rec_is_comp(rec)) { + log_start = log_ptr = mlog_open(mtr, 11 + size); + if (!log_ptr) { + return(NULL); /* logging is disabled */ + } + log_ptr = mlog_write_initial_log_record_fast(rec, type, + log_ptr, mtr); + log_end = log_ptr + 11 + size; + } else { + ulint i; + ulint n = dict_index_get_n_fields(index); + /* total size needed */ + ulint total = 11 + size + (n + 2) * 2; + ulint alloc = total; + /* allocate at most DYN_ARRAY_DATA_SIZE at a time */ + if (alloc > DYN_ARRAY_DATA_SIZE) { + alloc = DYN_ARRAY_DATA_SIZE; + } + log_start = log_ptr = mlog_open(mtr, alloc); + if (!log_ptr) { + return(NULL); /* logging is disabled */ + } + log_end = log_ptr + alloc; + log_ptr = mlog_write_initial_log_record_fast(rec, type, + log_ptr, mtr); + mach_write_to_2(log_ptr, n); + log_ptr += 2; + mach_write_to_2(log_ptr, + dict_index_get_n_unique_in_tree(index)); + log_ptr += 2; + for (i = 0; i < n; i++) { + dict_field_t* field; + const dict_col_t* col; + ulint len; + + field = dict_index_get_nth_field(index, i); + col = dict_field_get_col(field); + len = field->fixed_len; + ut_ad(len < 0x7fff); + if (len == 0 + && (col->len > 255 || col->mtype == DATA_BLOB)) { + /* variable-length field + with maximum length > 255 */ + len = 0x7fff; + } + if (col->prtype & DATA_NOT_NULL) { + len |= 0x8000; + } + if (log_ptr + 2 > log_end) { + mlog_close(mtr, log_ptr); + ut_a(total > (ulint) (log_ptr - log_start)); + total -= log_ptr - log_start; + alloc = total; + if (alloc > DYN_ARRAY_DATA_SIZE) { + alloc = DYN_ARRAY_DATA_SIZE; + } + log_start = log_ptr = mlog_open(mtr, alloc); + if (!log_ptr) { + return(NULL); /* logging is disabled */ + } + log_end = log_ptr + alloc; + } + mach_write_to_2(log_ptr, len); + log_ptr += 2; + } + } + if (size == 0) { + mlog_close(mtr, log_ptr); + log_ptr = NULL; + } else if (log_ptr + size > log_end) { + mlog_close(mtr, log_ptr); + log_ptr = mlog_open(mtr, size); + } + return(log_ptr); +} + +/************************************************************ +Parses a log record written by mlog_open_and_write_index. */ +UNIV_INTERN +byte* +mlog_parse_index( +/*=============*/ + /* out: parsed record end, + NULL if not a complete record */ + byte* ptr, /* in: buffer */ + byte* end_ptr,/* in: buffer end */ + /* out: new value of log_ptr */ + ibool comp, /* in: TRUE=compact record format */ + dict_index_t** index) /* out, own: dummy index */ +{ + ulint i, n, n_uniq; + dict_table_t* table; + dict_index_t* ind; + + ut_ad(comp == FALSE || comp == TRUE); + + if (comp) { + if (end_ptr < ptr + 4) { + return(NULL); + } + n = mach_read_from_2(ptr); + ptr += 2; + n_uniq = mach_read_from_2(ptr); + ptr += 2; + ut_ad(n_uniq <= n); + if (end_ptr < ptr + n * 2) { + return(NULL); + } + } else { + n = n_uniq = 1; + } + table = dict_mem_table_create("LOG_DUMMY", DICT_HDR_SPACE, n, + comp ? DICT_TF_COMPACT : 0); + ind = dict_mem_index_create("LOG_DUMMY", "LOG_DUMMY", + DICT_HDR_SPACE, 0, n); + ind->table = table; + ind->n_uniq = (unsigned int) n_uniq; + if (n_uniq != n) { + ut_a(n_uniq + DATA_ROLL_PTR <= n); + ind->type = DICT_CLUSTERED; + } + if (comp) { + for (i = 0; i < n; i++) { + ulint len = mach_read_from_2(ptr); + ptr += 2; + /* The high-order bit of len is the NOT NULL flag; + the rest is 0 or 0x7fff for variable-length fields, + and 1..0x7ffe for fixed-length fields. */ + dict_mem_table_add_col( + table, NULL, NULL, + ((len + 1) & 0x7fff) <= 1 + ? DATA_BINARY : DATA_FIXBINARY, + len & 0x8000 ? DATA_NOT_NULL : 0, + len & 0x7fff); + + dict_index_add_col(ind, table, + dict_table_get_nth_col(table, i), + 0); + } + dict_table_add_system_columns(table, table->heap); + if (n_uniq != n) { + /* Identify DB_TRX_ID and DB_ROLL_PTR in the index. */ + ut_a(DATA_TRX_ID_LEN + == dict_index_get_nth_col(ind, DATA_TRX_ID - 1 + + n_uniq)->len); + ut_a(DATA_ROLL_PTR_LEN + == dict_index_get_nth_col(ind, DATA_ROLL_PTR - 1 + + n_uniq)->len); + ind->fields[DATA_TRX_ID - 1 + n_uniq].col + = &table->cols[n + DATA_TRX_ID]; + ind->fields[DATA_ROLL_PTR - 1 + n_uniq].col + = &table->cols[n + DATA_ROLL_PTR]; + } + } + /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */ + ind->cached = TRUE; + *index = ind; + return(ptr); +} diff --git a/storage/xtradb/mtr/mtr0mtr.c b/storage/xtradb/mtr/mtr0mtr.c new file mode 100644 index 00000000000..881751b560e --- /dev/null +++ b/storage/xtradb/mtr/mtr0mtr.c @@ -0,0 +1,345 @@ +/***************************************************************************** + +Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +/****************************************************** +Mini-transaction buffer + +Created 11/26/1995 Heikki Tuuri +*******************************************************/ + +#include "mtr0mtr.h" + +#ifdef UNIV_NONINL +#include "mtr0mtr.ic" +#endif + +#include "buf0buf.h" +#include "page0types.h" +#include "mtr0log.h" +#include "log0log.h" + +/********************************************************************* +Releases the item in the slot given. */ +UNIV_INLINE +void +mtr_memo_slot_release( +/*==================*/ + mtr_t* mtr, /* in: mtr */ + mtr_memo_slot_t* slot) /* in: memo slot */ +{ + void* object; + ulint type; + + ut_ad(mtr && slot); + + object = slot->object; + type = slot->type; + + if (UNIV_LIKELY(object != NULL)) { + if (type <= MTR_MEMO_BUF_FIX) { + buf_page_release((buf_block_t*)object, type, mtr); + } else if (type == MTR_MEMO_S_LOCK) { + rw_lock_s_unlock((rw_lock_t*)object); +#ifdef UNIV_DEBUG + } else if (type != MTR_MEMO_X_LOCK) { + ut_ad(type == MTR_MEMO_MODIFY); + ut_ad(mtr_memo_contains(mtr, object, + MTR_MEMO_PAGE_X_FIX)); +#endif /* UNIV_DEBUG */ + } else { + rw_lock_x_unlock((rw_lock_t*)object); + } + } + + slot->object = NULL; +} + +/************************************************************** +Releases the mlocks and other objects stored in an mtr memo. They are released +in the order opposite to which they were pushed to the memo. NOTE! It is +essential that the x-rw-lock on a modified buffer page is not released before +buf_page_note_modification is called for that page! Otherwise, some thread +might race to modify it, and the flush list sort order on lsn would be +destroyed. */ +UNIV_INLINE +void +mtr_memo_pop_all( +/*=============*/ + mtr_t* mtr) /* in: mtr */ +{ + mtr_memo_slot_t* slot; + dyn_array_t* memo; + ulint offset; + + ut_ad(mtr); + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in + commit */ + memo = &(mtr->memo); + + offset = dyn_array_get_data_size(memo); + + while (offset > 0) { + offset -= sizeof(mtr_memo_slot_t); + slot = dyn_array_get_element(memo, offset); + + mtr_memo_slot_release(mtr, slot); + } +} + +/**************************************************************** +Writes the contents of a mini-transaction log, if any, to the database log. */ +static +void +mtr_log_reserve_and_write( +/*======================*/ + mtr_t* mtr) /* in: mtr */ +{ + dyn_array_t* mlog; + dyn_block_t* block; + ulint data_size; + ibool success; + byte* first_data; + + ut_ad(mtr); + + mlog = &(mtr->log); + + first_data = dyn_block_get_data(mlog); + + if (mtr->n_log_recs > 1) { + mlog_catenate_ulint(mtr, MLOG_MULTI_REC_END, MLOG_1BYTE); + } else { + *first_data = (byte)((ulint)*first_data + | MLOG_SINGLE_REC_FLAG); + } + + if (mlog->heap == NULL) { + mtr->end_lsn = log_reserve_and_write_fast( + first_data, dyn_block_get_used(mlog), + &(mtr->start_lsn), &success); + if (success) { + + return; + } + } + + data_size = dyn_array_get_data_size(mlog); + + /* Open the database log for log_write_low */ + mtr->start_lsn = log_reserve_and_open(data_size); + + if (mtr->log_mode == MTR_LOG_ALL) { + + block = mlog; + + while (block != NULL) { + log_write_low(dyn_block_get_data(block), + dyn_block_get_used(block)); + block = dyn_array_get_next_block(mlog, block); + } + } else { + ut_ad(mtr->log_mode == MTR_LOG_NONE); + /* Do nothing */ + } + + mtr->end_lsn = log_close(); +} + +/******************************************************************* +Commits a mini-transaction. */ +UNIV_INTERN +void +mtr_commit( +/*=======*/ + mtr_t* mtr) /* in: mini-transaction */ +{ + ibool write_log; + + ut_ad(mtr); + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_ACTIVE); + ut_d(mtr->state = MTR_COMMITTING); + + write_log = mtr->modifications && mtr->n_log_recs; + + if (write_log) { + mtr_log_reserve_and_write(mtr); + } + + /* We first update the modification info to buffer pages, and only + after that release the log mutex: this guarantees that when the log + mutex is free, all buffer pages contain an up-to-date info of their + modifications. This fact is used in making a checkpoint when we look + at the oldest modification of any page in the buffer pool. It is also + required when we insert modified buffer pages in to the flush list + which must be sorted on oldest_modification. */ + + mtr_memo_pop_all(mtr); + + if (write_log) { + log_release(); + } + + ut_d(mtr->state = MTR_COMMITTED); + dyn_array_free(&(mtr->memo)); + dyn_array_free(&(mtr->log)); +} + +/************************************************************** +Releases the latches stored in an mtr memo down to a savepoint. +NOTE! The mtr must not have made changes to buffer pages after the +savepoint, as these can be handled only by mtr_commit. */ +UNIV_INTERN +void +mtr_rollback_to_savepoint( +/*======================*/ + mtr_t* mtr, /* in: mtr */ + ulint savepoint) /* in: savepoint */ +{ + mtr_memo_slot_t* slot; + dyn_array_t* memo; + ulint offset; + + ut_ad(mtr); + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_ACTIVE); + + memo = &(mtr->memo); + + offset = dyn_array_get_data_size(memo); + ut_ad(offset >= savepoint); + + while (offset > savepoint) { + offset -= sizeof(mtr_memo_slot_t); + + slot = dyn_array_get_element(memo, offset); + + ut_ad(slot->type != MTR_MEMO_MODIFY); + mtr_memo_slot_release(mtr, slot); + } +} + +/******************************************************* +Releases an object in the memo stack. */ +UNIV_INTERN +void +mtr_memo_release( +/*=============*/ + mtr_t* mtr, /* in: mtr */ + void* object, /* in: object */ + ulint type) /* in: object type: MTR_MEMO_S_LOCK, ... */ +{ + mtr_memo_slot_t* slot; + dyn_array_t* memo; + ulint offset; + + ut_ad(mtr); + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_ACTIVE); + + memo = &(mtr->memo); + + offset = dyn_array_get_data_size(memo); + + while (offset > 0) { + offset -= sizeof(mtr_memo_slot_t); + + slot = dyn_array_get_element(memo, offset); + + if ((object == slot->object) && (type == slot->type)) { + + mtr_memo_slot_release(mtr, slot); + + break; + } + } +} + +/************************************************************ +Reads 1 - 4 bytes from a file page buffered in the buffer pool. */ +UNIV_INTERN +ulint +mtr_read_ulint( +/*===========*/ + /* out: value read */ + const byte* ptr, /* in: pointer from where to read */ + ulint type, /* in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */ + mtr_t* mtr __attribute__((unused))) + /* in: mini-transaction handle */ +{ + ut_ad(mtr->state == MTR_ACTIVE); + ut_ad(mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_S_FIX) + || mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_X_FIX)); + if (type == MLOG_1BYTE) { + return(mach_read_from_1(ptr)); + } else if (type == MLOG_2BYTES) { + return(mach_read_from_2(ptr)); + } else { + ut_ad(type == MLOG_4BYTES); + return(mach_read_from_4(ptr)); + } +} + +/************************************************************ +Reads 8 bytes from a file page buffered in the buffer pool. */ +UNIV_INTERN +dulint +mtr_read_dulint( +/*============*/ + /* out: value read */ + const byte* ptr, /* in: pointer from where to read */ + mtr_t* mtr __attribute__((unused))) + /* in: mini-transaction handle */ +{ + ut_ad(mtr->state == MTR_ACTIVE); + ut_ad(mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_S_FIX) + || mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_X_FIX)); + return(mach_read_from_8(ptr)); +} + +#ifdef UNIV_DEBUG +/************************************************************** +Checks if memo contains the given page. */ +UNIV_INTERN +ibool +mtr_memo_contains_page( +/*===================*/ + /* out: TRUE if contains */ + mtr_t* mtr, /* in: mtr */ + const byte* ptr, /* in: pointer to buffer frame */ + ulint type) /* in: type of object */ +{ + return(mtr_memo_contains(mtr, buf_block_align(ptr), type)); +} + +/************************************************************* +Prints info of an mtr handle. */ +UNIV_INTERN +void +mtr_print( +/*======*/ + mtr_t* mtr) /* in: mtr */ +{ + fprintf(stderr, + "Mini-transaction handle: memo size %lu bytes" + " log size %lu bytes\n", + (ulong) dyn_array_get_data_size(&(mtr->memo)), + (ulong) dyn_array_get_data_size(&(mtr->log))); +} +#endif /* UNIV_DEBUG */ |