diff options
author | monty@donna.mysql.com <> | 2001-02-17 14:19:19 +0200 |
---|---|---|
committer | monty@donna.mysql.com <> | 2001-02-17 14:19:19 +0200 |
commit | c533308a158795f91247e9fe3c7304fa5e7d2b3c (patch) | |
tree | bfe39951a73e906579ab819bf5198ad8f3a64a36 /innobase/mtr | |
parent | 024e2f39c9a3812243778ebe64b43e8edd22a4a1 (diff) | |
download | mariadb-git-c533308a158795f91247e9fe3c7304fa5e7d2b3c.tar.gz |
Added Innobase to source distribution
Diffstat (limited to 'innobase/mtr')
-rw-r--r-- | innobase/mtr/Makefile.am | 24 | ||||
-rw-r--r-- | innobase/mtr/makefilewin | 14 | ||||
-rw-r--r-- | innobase/mtr/mtr0log.c | 327 | ||||
-rw-r--r-- | innobase/mtr/mtr0mtr.c | 522 | ||||
-rw-r--r-- | innobase/mtr/ts/makefile | 8 | ||||
-rw-r--r-- | innobase/mtr/ts/tsbuf.c | 531 | ||||
-rw-r--r-- | innobase/mtr/ts/tsmtr.c | 158 |
7 files changed, 1584 insertions, 0 deletions
diff --git a/innobase/mtr/Makefile.am b/innobase/mtr/Makefile.am new file mode 100644 index 00000000000..972dcaca80e --- /dev/null +++ b/innobase/mtr/Makefile.am @@ -0,0 +1,24 @@ +# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +# & Innobase Oy +# +# 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; either version 2 of the License, or +# (at your option) any later version. +# +# 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 + +include ../include/Makefile.i + +libs_LIBRARIES = libmtr.a + +libmtr_a_SOURCES = mtr0mtr.c mtr0log.c + +EXTRA_PROGRAMS = diff --git a/innobase/mtr/makefilewin b/innobase/mtr/makefilewin new file mode 100644 index 00000000000..9da0863bd28 --- /dev/null +++ b/innobase/mtr/makefilewin @@ -0,0 +1,14 @@ +include ..\include\makefile.i + +mtr.lib: mtr0mtr.obj mtr0log.obj + lib -out:..\libs\mtr.lib mtr0mtr.obj mtr0log.obj + +mtr0mtr.obj: mtr0mtr.c + $(CCOM) $(CFL) -c mtr0mtr.c + +mtr0log.obj: mtr0log.c + $(CCOM) $(CFL) -c mtr0log.c + + + + diff --git a/innobase/mtr/mtr0log.c b/innobase/mtr/mtr0log.c new file mode 100644 index 00000000000..11c0c476fcb --- /dev/null +++ b/innobase/mtr/mtr0log.c @@ -0,0 +1,327 @@ +/****************************************************** +Mini-transaction log routines + +(c) 1995 Innobase Oy + +Created 12/7/1995 Heikki Tuuri +*******************************************************/ + +#include "mtr0log.h" + +#ifdef UNIV_NONINL +#include "mtr0log.ic" +#endif + +#include "buf0buf.h" +#include "dict0boot.h" + +/************************************************************ +Catenates n bytes to the mtr log. */ + +void +mlog_catenate_string( +/*=================*/ + mtr_t* mtr, /* in: mtr */ + 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. */ + +void +mlog_write_initial_log_record( +/*==========================*/ + 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); + + log_ptr = mlog_open(mtr, 20); + + /* 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. */ + +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); + + 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. */ + +byte* +mlog_parse_nbytes( +/*==============*/ + /* out: parsed record end, NULL if not a complete + 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 */ +{ + ulint offset; + ulint val; + dulint dval; + + ut_a(type <= MLOG_8BYTES); + + if (end_ptr < ptr + 2) { + + return(NULL); + } + + offset = mach_read_from_2(ptr); + ptr += 2; + + if (type == MLOG_8BYTES) { + ptr = mach_dulint_parse_compressed(ptr, end_ptr, &dval); + + if (ptr == NULL) { + + return(NULL); + } + + if (page) { + mach_write_to_8(page + offset, dval); + } + + return(ptr); + } + + ptr = mach_parse_compressed(ptr, end_ptr, &val); + + if (ptr == NULL) { + + return(NULL); + } + + if (page) { + if (type == MLOG_1BYTE) { + mach_write_to_1(page + offset, val); + } else if (type == MLOG_2BYTES) { + mach_write_to_2(page + offset, val); + } else { + ut_ad(type == MLOG_4BYTES); + mach_write_to_4(page + offset, val); + } + } + + 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. */ + +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; + + if (type == MLOG_1BYTE) { + mach_write_to_1(ptr, val); + } else if (type == MLOG_2BYTES) { + mach_write_to_2(ptr, val); + } else { + ut_ad(type == MLOG_4BYTES); + mach_write_to_4(ptr, val); + } + + 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, type, log_ptr, mtr); + + mach_write_to_2(log_ptr, ptr - buf_frame_align(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. */ + +void +mlog_write_dulint( +/*==============*/ + byte* ptr, /* in: pointer where to write */ + dulint val, /* in: value to write */ + byte type, /* in: MLOG_8BYTES */ + mtr_t* mtr) /* in: mini-transaction handle */ +{ + byte* log_ptr; + + ut_ad(ptr && mtr); + ut_ad(type == MLOG_8BYTES); + + mach_write_to_8(ptr, val); + + 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, type, log_ptr, mtr); + + mach_write_to_2(log_ptr, ptr - buf_frame_align(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. */ + +void +mlog_write_string( +/*==============*/ + byte* ptr, /* in: pointer where to write */ + byte* str, /* in: string to write */ + 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); + + ut_memcpy(ptr, str, len); + + 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, ptr - buf_frame_align(ptr)); + log_ptr += 2; + + mach_write_to_2(log_ptr, len); + log_ptr += 2; + + mlog_close(mtr, log_ptr); + + mlog_catenate_string(mtr, str, len); +} + +/************************************************************ +Parses a log record written by mlog_write_string. */ + +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 */ +{ + ulint offset; + ulint len; + + if (end_ptr < ptr + 4) { + + return(NULL); + } + + offset = mach_read_from_2(ptr); + ptr += 2; + + len = mach_read_from_2(ptr); + ptr += 2; + + if (end_ptr < ptr + len) { + + return(NULL); + } + + if (page) { + ut_memcpy(page + offset, ptr, len); + } + + return(ptr + len); +} diff --git a/innobase/mtr/mtr0mtr.c b/innobase/mtr/mtr0mtr.c new file mode 100644 index 00000000000..f38aa6793b9 --- /dev/null +++ b/innobase/mtr/mtr0mtr.c @@ -0,0 +1,522 @@ +/****************************************************** +Mini-transaction buffer + +(c) 1995 Innobase Oy + +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" + +/******************************************************************* +Starts a mini-transaction and creates a mini-transaction handle +and buffer in the memory buffer given by the caller. */ + +mtr_t* +mtr_start_noninline( +/*================*/ + /* out: mtr buffer which also acts as + the mtr handle */ + mtr_t* mtr) /* in: memory buffer for the mtr buffer */ +{ + return(mtr_start(mtr)); +} + +/********************************************************************* +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 (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); +#ifndef UNIV_DEBUG + } else { + rw_lock_x_unlock((rw_lock_t*)object); + } +#endif +#ifdef UNIV_DEBUG + } else if (type == MTR_MEMO_X_LOCK) { + rw_lock_x_unlock((rw_lock_t*)object); + } else { + ut_ad(type == MTR_MEMO_MODIFY); + ut_ad(mtr_memo_contains(mtr, object, + MTR_MEMO_PAGE_X_FIX)); + } +#endif + } + + 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 to the log the contents of a full page. This is called when the +database is in the online backup state. */ +static +void +mtr_log_write_full_page( +/*====================*/ + page_t* page, /* in: page to write */ + ulint i, /* in: i'th page for mtr */ + ulint n_pages,/* in: total number of pages for mtr */ + mtr_t* mtr) /* in: mtr */ +{ + byte* buf; + byte* ptr; + ulint len; + + buf = mem_alloc(UNIV_PAGE_SIZE + 50); + + ptr = mlog_write_initial_log_record_fast(page, MLOG_FULL_PAGE, buf, + mtr); + ut_memcpy(ptr, page, UNIV_PAGE_SIZE); + + len = (ptr - buf) + UNIV_PAGE_SIZE; + + if (i == n_pages - 1) { + if (n_pages > 1) { + *(buf + len) = MLOG_MULTI_REC_END; + len++; + } else { + *buf = (byte)((ulint)*buf | MLOG_SINGLE_REC_FLAG); + } + } + + ut_ad(len < UNIV_PAGE_SIZE + 50); + + log_write_low(buf, len); + + mem_free(buf); +} + +/**************************************************************** +Parses a log record which contains the full contents of a page. */ + +byte* +mtr_log_parse_full_page( +/*====================*/ + /* out: end of log record or NULL */ + byte* ptr, /* in: buffer */ + byte* end_ptr,/* in: buffer end */ + page_t* page) /* in: page or NULL */ +{ + if (end_ptr < ptr + UNIV_PAGE_SIZE) { + + return(NULL); + } + + if (page) { + ut_memcpy(page, ptr, UNIV_PAGE_SIZE); + } + + return(ptr + UNIV_PAGE_SIZE); +} + +/**************************************************************** +Writes to the database log the full contents of the pages that this mtr has +modified. */ + +void +mtr_log_write_backup_full_pages( +/*============================*/ + mtr_t* mtr, /* in: mini-transaction */ + ulint n_pages)/* in: number of pages modified by mtr */ +{ + mtr_memo_slot_t* slot; + dyn_array_t* memo; + buf_block_t* block; + ulint offset; + ulint type; + ulint i; + + ut_ad(mtr); + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_COMMITTING); + + /* Open the database log for log_write_low */ + mtr->start_lsn = log_reserve_and_open(n_pages * (UNIV_PAGE_SIZE + 50)); + + memo = &(mtr->memo); + + offset = dyn_array_get_data_size(memo); + + i = 0; + + while (offset > 0) { + offset -= sizeof(mtr_memo_slot_t); + slot = dyn_array_get_element(memo, offset); + + block = slot->object; + type = slot->type; + + if ((block != NULL) && (type == MTR_MEMO_PAGE_X_FIX)) { + + mtr_log_write_full_page(block->frame, i, n_pages, mtr); + + i++; + } + } + + ut_ad(i == n_pages); +} + +/**************************************************************** +Checks if mtr is the first to modify any page after online_backup_lsn. */ +static +ibool +mtr_first_to_modify_page_after_backup( +/*==================================*/ + /* out: TRUE if first for a page */ + mtr_t* mtr, /* in: mini-transaction */ + ulint* n_pages) /* out: number of modified pages (all modified + pages, backup_lsn does not matter here) */ +{ + mtr_memo_slot_t* slot; + dyn_array_t* memo; + ulint offset; + buf_block_t* block; + ulint type; + dulint backup_lsn; + ibool ret = FALSE; + + ut_ad(mtr); + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_COMMITTING); + + backup_lsn = log_get_online_backup_lsn_low(); + + memo = &(mtr->memo); + + offset = dyn_array_get_data_size(memo); + + *n_pages = 0; + + while (offset > 0) { + offset -= sizeof(mtr_memo_slot_t); + slot = dyn_array_get_element(memo, offset); + + block = slot->object; + type = slot->type; + + if ((block != NULL) && (type == MTR_MEMO_PAGE_X_FIX)) { + + *n_pages = *n_pages + 1; + + if (ut_dulint_cmp(buf_frame_get_newest_modification( + block->frame), + backup_lsn) <= 0) { + + printf("Page %lu newest %lu backup %lu\n", + block->offset, + ut_dulint_get_low( + buf_frame_get_newest_modification( + block->frame)), + ut_dulint_get_low(backup_lsn)); + + ret = TRUE; + } + } + } + + return(ret); +} + +/**************************************************************** +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; + ulint n_modified_pages; + + 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) { + + if (log_get_online_backup_state_low() + && mtr_first_to_modify_page_after_backup(mtr, + &n_modified_pages)) { + + /* The database is in the online backup state: write + to the log the full contents of all the pages if this + mtr is the first to modify any page in the buffer pool + after online_backup_lsn */ + + log_close(); + log_release(); + + mtr_log_write_backup_full_pages(mtr, n_modified_pages); + } else { + 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. */ + +void +mtr_commit( +/*=======*/ + mtr_t* mtr) /* in: mini-transaction */ +{ + ut_ad(mtr); + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_ACTIVE); +#ifdef UNIV_DEBUG + mtr->state = MTR_COMMITTING; +#endif + if (mtr->modifications) { + 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 (mtr->modifications) { + log_release(); + } + +#ifdef UNIV_DEBUG + mtr->state = MTR_COMMITTED; +#endif + 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. */ + +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. */ + +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. */ + +ulint +mtr_read_ulint( +/*===========*/ + /* out: value read */ + byte* ptr, /* in: pointer from where to read */ + ulint type, /* in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */ + mtr_t* mtr) /* in: mini-transaction handle */ +{ + ut_ad(mtr->state == MTR_ACTIVE); + ut_ad(mtr_memo_contains(mtr, buf_block_align(ptr), + MTR_MEMO_PAGE_S_FIX) || + mtr_memo_contains(mtr, buf_block_align(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. */ + +dulint +mtr_read_dulint( +/*===========*/ + /* out: value read */ + byte* ptr, /* in: pointer from where to read */ + ulint type, /* in: MLOG_8BYTES */ + mtr_t* mtr) /* in: mini-transaction handle */ +{ + ut_ad(mtr->state == MTR_ACTIVE); + ut_ad(ptr && mtr); + ut_ad(type == MLOG_8BYTES); + ut_ad(mtr_memo_contains(mtr, buf_block_align(ptr), + MTR_MEMO_PAGE_S_FIX) || + mtr_memo_contains(mtr, buf_block_align(ptr), + MTR_MEMO_PAGE_X_FIX)); + return(mach_read_from_8(ptr)); +} + +/************************************************************* +Prints info of an mtr handle. */ + +void +mtr_print( +/*======*/ + mtr_t* mtr) /* in: mtr */ +{ + printf( + "Mini-transaction handle: memo size %lu bytes log size %lu bytes\n", + dyn_array_get_data_size(&(mtr->memo)), + dyn_array_get_data_size(&(mtr->log))); +} diff --git a/innobase/mtr/ts/makefile b/innobase/mtr/ts/makefile new file mode 100644 index 00000000000..3a155fb1401 --- /dev/null +++ b/innobase/mtr/ts/makefile @@ -0,0 +1,8 @@ + + + +include ..\..\makefile.i + +tsmtr: ..\mtr.lib tsmtr.c + $(CCOM) $(CFL) -I.. -I..\.. ..\mtr.lib ..\..\dyn.lib ..\..\log.lib ..\..\mach.lib ..\..\buf.lib ..\..\fil.lib ..\..\ha.lib ..\..\ut.lib ..\..\sync.lib ..\..\mem.lib ..\..\os.lib tsmtr.c $(LFL) + diff --git a/innobase/mtr/ts/tsbuf.c b/innobase/mtr/ts/tsbuf.c new file mode 100644 index 00000000000..a2a18d7afaf --- /dev/null +++ b/innobase/mtr/ts/tsbuf.c @@ -0,0 +1,531 @@ +/************************************************************************ +The test module for the file system and buffer manager + +(c) 1995 Innobase Oy + +Created 11/16/1995 Heikki Tuuri +*************************************************************************/ + +#include "os0thread.h" +#include "os0file.h" +#include "ut0ut.h" +#include "sync0sync.h" +#include "mem0mem.h" +#include "fil0fil.h" +#include "..\buf0buf.h" +#include "..\buf0flu.h" +#include "..\buf0lru.h" + +os_file_t files[1000]; + +mutex_t ios_mutex; +ulint ios; +ulint n[5]; + + +/************************************************************************ +Io-handler thread function. */ + +ulint +handler_thread( +/*===========*/ + void* arg) +{ + ulint segment; + void* mess; + ulint i; + bool ret; + + segment = *((ulint*)arg); + + printf("Thread %lu starts\n", segment); + + for (i = 0;; i++) { + ret = fil_aio_wait(segment, &mess); + ut_a(ret); + + buf_page_io_complete((buf_block_t*)mess); + + mutex_enter(&ios_mutex); + ios++; + mutex_exit(&ios_mutex); + + } + + return(0); +} + +/************************************************************************ +Creates the test database files. */ + +void +create_db(void) +/*===========*/ +{ + ulint i; + buf_block_t* block; + byte* frame; + ulint j; + ulint tm, oldtm; + + oldtm = ut_clock(); + + for (i = 0; i < 1; i++) { + for (j = 0; j < 4096; j++) { + block = buf_page_create(i, j); + + frame = buf_block_get_frame(block); + + rw_lock_x_lock(buf_page_get_lock(block)); + + if (j > 0) { + fil_page_set_prev(frame, j - 1); + } else { + fil_page_set_prev(frame, 0); + } + + if (j < 4095) { + fil_page_set_next(frame, j + 1); + } else { + fil_page_set_next(frame, 0); + } + + *((ulint*)(frame + 16)) = j; + + buf_page_note_modification(block); + + rw_lock_x_unlock(buf_page_get_lock(block)); + + buf_page_release(block); + } + } + + tm = ut_clock(); + printf("Wall clock time for test %lu milliseconds\n", tm - oldtm); + +/* buf_LRU_print(); */ + + /* Flush the pool of dirty pages by reading low-offset pages */ + for (i = 0; i < 1000; i++) { + + block = buf_page_get(0, i, NULL); + + frame = buf_block_get_frame(block); + + rw_lock_s_lock(buf_page_get_lock(block)); + + ut_a(*((ulint*)(frame + 16)) == i); + + rw_lock_s_unlock(buf_page_get_lock(block)); + + buf_page_release(block); + } + +/* buf_LRU_print(); */ + + os_thread_sleep(1000000); + + ut_a(buf_all_freed()); +} + +/************************************************************************* +Creates the files for the file system test and inserts them to +the file system. */ + +void +create_files(void) +/*==============*/ +{ + bool ret; + ulint i, k; + char name[10]; + os_thread_t thr[5]; + os_thread_id_t id[5]; + + name[0] = 't'; + name[1] = 's'; + name[2] = 'f'; + name[3] = 'i'; + name[4] = 'l'; + name[5] = 'e'; + name[8] = '\0'; + + for (k = 0; k < 1; k++) { + for (i = 0; i < 1; i++) { + + name[6] = (char)(k + (ulint)'a'); + name[7] = (char)(i + (ulint)'a'); + + files[i] = os_file_create("j:\\tsfile4", OS_FILE_CREATE, + OS_FILE_TABLESPACE, &ret); + + if (ret == FALSE) { + ut_a(os_file_get_last_error() == + OS_FILE_ALREADY_EXISTS); + + files[i] = os_file_create( + "j:\\tsfile4", OS_FILE_OPEN, + OS_FILE_TABLESPACE, &ret); + + ut_a(ret); + } + + ret = os_file_set_size(files[i], 4096 * 8192, 0); + ut_a(ret); + + ret = os_file_close(files[i]); + ut_a(ret); + + if (i == 0) { + fil_space_create("noname", k, OS_FILE_TABLESPACE); + } + + ut_a(fil_validate()); + + fil_node_create("j:\\tsfile4", 4096, k); + } + } + + ios = 0; + + mutex_create(&ios_mutex); + + for (i = 0; i < 5; i++) { + n[i] = i; + + thr[i] = os_thread_create(handler_thread, n + i, id + i); + } +} + +/************************************************************************ +Reads the test database files. */ + +void +test1(void) +/*=======*/ +{ + ulint i, j, k; + buf_block_t* block; + byte* frame; + ulint tm, oldtm; + + buf_flush_batch(BUF_FLUSH_LIST, 1000); + + os_thread_sleep(1000000); + + buf_all_freed(); + + oldtm = ut_clock(); + + for (k = 0; k < 1; k++) { + for (i = 0; i < 1; i++) { + for (j = 0; j < 409; j++) { + block = buf_page_get(i, j, NULL); + + frame = buf_block_get_frame(block); + + rw_lock_s_lock(buf_page_get_lock(block)); + + ut_a(*((ulint*)(frame + 16)) == j); + + rw_lock_s_unlock(buf_page_get_lock(block)); + + buf_page_release(block); + } + } + } + + tm = ut_clock(); + printf("Wall clock time for test %lu milliseconds\n", tm - oldtm); + +} + +/************************************************************************ +Reads the test database files. */ + +void +test2(void) +/*=======*/ +{ + ulint i, j, k, rnd; + buf_block_t* block; + byte* frame; + ulint tm, oldtm; + + oldtm = ut_clock(); + + rnd = 123; + + for (k = 0; k < 100; k++) { + rnd += 23651; + rnd = rnd % 4096; + + i = rnd / 4096; + j = rnd % 2048; + + block = buf_page_get(i, j, NULL); + + frame = buf_block_get_frame(block); + + rw_lock_s_lock(buf_page_get_lock(block)); + + ut_a(*((ulint*)(frame + 16)) == j); + + rw_lock_s_unlock(buf_page_get_lock(block)); + + buf_page_release(block); + } + + tm = ut_clock(); + printf("Wall clock time for random read %lu milliseconds\n", + tm - oldtm); +} + +/************************************************************************ +Reads the test database files. */ + +void +test4(void) +/*=======*/ +{ + ulint i, j, k, rnd; + buf_block_t* block; + byte* frame; + ulint tm, oldtm; + + /* Flush the pool of high-offset pages */ + for (i = 0; i < 1000; i++) { + + block = buf_page_get(0, i, NULL); + + frame = buf_block_get_frame(block); + + rw_lock_s_lock(buf_page_get_lock(block)); + + ut_a(*((ulint*)(frame + 16)) == i); + + rw_lock_s_unlock(buf_page_get_lock(block)); + + buf_page_release(block); + } + + printf("Test starts\n"); + + oldtm = ut_clock(); + + rnd = 123; + + for (k = 0; k < 400; k++) { + + rnd += 4357; + + i = 0; + j = 1001 + rnd % 3000; + + block = buf_page_get(i, j, NULL); + + frame = buf_block_get_frame(block); + + rw_lock_s_lock(buf_page_get_lock(block)); + + ut_a(*((ulint*)(frame + 16)) == j); + + rw_lock_s_unlock(buf_page_get_lock(block)); + + buf_page_release(block); + } + + tm = ut_clock(); + printf( + "Wall clock time for %lu random no read-ahead %lu milliseconds\n", + k, tm - oldtm); + + /* Flush the pool of high-offset pages */ + for (i = 0; i < 1000; i++) { + + block = buf_page_get(0, i, NULL); + + frame = buf_block_get_frame(block); + + rw_lock_s_lock(buf_page_get_lock(block)); + + ut_a(*((ulint*)(frame + 16)) == i); + + rw_lock_s_unlock(buf_page_get_lock(block)); + + buf_page_release(block); + } + + printf("Test starts\n"); + + oldtm = ut_clock(); + + rnd = 123; + + for (k = 0; k < 400; k++) { + + rnd += 4357; + + i = 0; + j = 1001 + rnd % 400; + + block = buf_page_get(i, j, NULL); + + frame = buf_block_get_frame(block); + + rw_lock_s_lock(buf_page_get_lock(block)); + + ut_a(*((ulint*)(frame + 16)) == j); + + rw_lock_s_unlock(buf_page_get_lock(block)); + + buf_page_release(block); + } + + tm = ut_clock(); + printf( + "Wall clock time for %lu random read-ahead %lu milliseconds\n", + k, tm - oldtm); + +} + +/************************************************************************ +Tests speed of CPU algorithms. */ + +void +test3(void) +/*=======*/ +{ + ulint i, j; + buf_block_t* block; + ulint tm, oldtm; + + for (i = 0; i < 400; i++) { + + block = buf_page_get(0, i, NULL); + + buf_page_release(block); + } + + os_thread_sleep(2000000); + + oldtm = ut_clock(); + + for (j = 0; j < 500; j++) { + for (i = 0; i < 200; i++) { + + block = buf_page_get(0, i, NULL); + +/* + rw_lock_s_lock(buf_page_get_lock(block)); + + rw_lock_s_unlock(buf_page_get_lock(block)); +*/ + + buf_page_release(block); + + } + } + + tm = ut_clock(); + printf("Wall clock time for %lu page get-release %lu milliseconds\n", + i * j, tm - oldtm); + + oldtm = ut_clock(); + + for (j = 0; j < 500; j++) { + for (i = 0; i < 200; i++) { + + buf_block_get(block); +/* + rw_lock_s_lock(buf_page_get_lock(block)); + + rw_lock_s_unlock(buf_page_get_lock(block)); +*/ + buf_page_release(block); + } + } + + tm = ut_clock(); + printf("Wall clock time for %lu block get-release %lu milliseconds\n", + i * j, tm - oldtm); + + + oldtm = ut_clock(); + + for (i = 0; i < 100000; i++) { + block = buf_block_alloc(); + buf_block_free(block); + } + + tm = ut_clock(); + printf("Wall clock time for %lu block alloc-free %lu milliseconds\n", + i, tm - oldtm); + + ha_print_info(buf_pool->page_hash); +} + +/************************************************************************ +Frees the spaces in the file system. */ + +void +free_system(void) +/*=============*/ +{ + ulint i; + + for (i = 0; i < 1; i++) { + fil_space_free(i); + } +} + +/************************************************************************ +Main test function. */ + +void +main(void) +/*======*/ +{ + ulint tm, oldtm; + ulint n; + + oldtm = ut_clock(); + + os_aio_init(160, 5); + sync_init(); + mem_init(); + fil_init(26); /* Allow 25 open files at a time */ + buf_pool_init(1000, 1000); + + buf_validate(); + + ut_a(fil_validate()); + + create_files(); + + create_db(); + + buf_validate(); + + test1(); + + test3(); + + test4(); + + test2(); + + buf_validate(); + + n = buf_flush_batch(BUF_FLUSH_LIST, 500); + + os_thread_sleep(1000000); + + buf_all_freed(); + + free_system(); + + tm = ut_clock(); + printf("Wall clock time for test %lu milliseconds\n", tm - oldtm); + printf("TESTS COMPLETED SUCCESSFULLY!\n"); +} diff --git a/innobase/mtr/ts/tsmtr.c b/innobase/mtr/ts/tsmtr.c new file mode 100644 index 00000000000..42997cd2699 --- /dev/null +++ b/innobase/mtr/ts/tsmtr.c @@ -0,0 +1,158 @@ +/************************************************************************ +The test module for the mini-transaction utilities + +(c) 1995 Innobase Oy + +Created 11/26/1995 Heikki Tuuri +*************************************************************************/ + +#include "sync0sync.h" +#include "sync0rw.h" +#include "mem0mem.h" +#include "log0log.h" +#include "..\mtr0mtr.h" +#include "..\mtr0log.h" + +rw_lock_t rwl[MTR_BUF_MEMO_SIZE]; + +/********************************************************************* +Test for mtr buffer */ + +void +test1(void) +/*=======*/ +{ + ulint i; + mtr_t mtr; + + printf("-------------------------------------------\n"); + printf("MTR-TEST 1. Test of mtr buffer\n"); + + mtr_start(&mtr); + + for (i = 0; i < MTR_BUF_MEMO_SIZE; i++) { + rw_lock_create(rwl + i); + } + + for (i = 0; i < MTR_BUF_MEMO_SIZE; i++) { + rw_lock_s_lock(rwl + i); + mtr_memo_push(&mtr, rwl + i, MTR_MEMO_S_LOCK); + } + + mtr_commit(&mtr); + + rw_lock_list_print_info(); + ut_ad(rw_lock_n_locked() == 0); + +} + +/************************************************************************ +Speed test function. */ +void +speed_mtr(void) +/*===========*/ +{ + mtr_t mtr; + + mtr_start(&mtr); + + mtr_s_lock(rwl, &mtr); + mtr_s_lock(rwl + 1, &mtr); + mtr_s_lock(rwl + 2, &mtr); + + mtr_commit(&mtr); +} + +/************************************************************************ +Speed test function without mtr. */ +void +speed_no_mtr(void) +/*===========*/ +{ + rw_lock_s_lock(rwl); + rw_lock_s_lock(rwl + 1); + rw_lock_s_lock(rwl + 2); + rw_lock_s_unlock(rwl + 2); + rw_lock_s_unlock(rwl + 1); + rw_lock_s_unlock(rwl); +} + +/************************************************************************ +Speed test function. */ + +void +test2(void) +/*======*/ +{ + ulint tm, oldtm; + ulint i, j; + mtr_t mtr; + byte buf[50]; + + oldtm = ut_clock(); + + for (i = 0; i < 1000 * UNIV_DBC * UNIV_DBC; i++) { + speed_mtr(); + } + + tm = ut_clock(); + printf("Wall clock time for %lu mtrs %lu milliseconds\n", + i, tm - oldtm); + oldtm = ut_clock(); + + for (i = 0; i < 1000 * UNIV_DBC * UNIV_DBC; i++) { + speed_no_mtr(); + } + + tm = ut_clock(); + printf("Wall clock time for %lu no-mtrs %lu milliseconds\n", + i, tm - oldtm); + + oldtm = ut_clock(); + for (i = 0; i < 4 * UNIV_DBC * UNIV_DBC; i++) { + mtr_start(&mtr); + for (j = 0; j < 250; j++) { + mlog_catenate_ulint(&mtr, 5, MLOG_1BYTE); + mlog_catenate_ulint(&mtr, i, MLOG_4BYTES); + mlog_catenate_ulint(&mtr, i + 1, MLOG_4BYTES); + mlog_catenate_string(&mtr, buf, 50); + } + mtr_commit(&mtr); + } + tm = ut_clock(); + printf("Wall clock time for %lu log writes %lu milliseconds\n", + i * j, tm - oldtm); + mtr_start(&mtr); + for (j = 0; j < 250; j++) { + mlog_catenate_ulint(&mtr, 5, MLOG_1BYTE); + mlog_catenate_ulint(&mtr, i, MLOG_4BYTES); + mlog_catenate_ulint(&mtr, i + 1, MLOG_4BYTES); + mlog_catenate_string(&mtr, buf, 50); + } + + mtr_print(&mtr); + mtr_commit(&mtr); +} + +/************************************************************************ +Main test function. */ + +void +main(void) +/*======*/ +{ + ulint tm, oldtm; + + oldtm = ut_clock(); + + sync_init(); + mem_init(); + log_init(); + + test1(); + test2(); + + tm = ut_clock(); + printf("Wall clock time for test %lu milliseconds\n", tm - oldtm); + printf("TESTS COMPLETED SUCCESSFULLY!\n"); +} |