Merge with 3.23.51

Fixed wrong usage of sprintf() in ha_innodb.cc
This commit is contained in:
monty@mashka.mysql.fi 2002-07-25 22:46:28 +03:00
commit bc035c71f1
134 changed files with 4227 additions and 4734 deletions

View File

@ -8,6 +8,7 @@ akishkin@work.mysql.com
arjen@co3064164-a.bitbike.com arjen@co3064164-a.bitbike.com
arjen@fred.bitbike.com arjen@fred.bitbike.com
arjen@george.bitbike.com arjen@george.bitbike.com
bar@bar.udmsearch.izhnet.ru
bell@sanja.is.com.ua bell@sanja.is.com.ua
davida@isil.mysql.com davida@isil.mysql.com
heikki@donna.mysql.fi heikki@donna.mysql.fi
@ -46,6 +47,8 @@ paul@central.snake.net
paul@teton.kitebird.com paul@teton.kitebird.com
peter@linux.local peter@linux.local
root@x3.internalnet root@x3.internalnet
salle@geopard.(none)
salle@geopard.online.bg
sasha@mysql.sashanet.com sasha@mysql.sashanet.com
serg@serg.mysql.com serg@serg.mysql.com
serg@sergbook.mysql.com serg@sergbook.mysql.com
@ -64,10 +67,8 @@ tonu@volk.internalnet
tonu@x153.internalnet tonu@x153.internalnet
tonu@x3.internalnet tonu@x3.internalnet
venu@work.mysql.com venu@work.mysql.com
walrus@mysql.com
worm@altair.is.lan worm@altair.is.lan
zak@balfor.local zak@balfor.local
zak@linux.local zak@linux.local
salle@geopard.(none)
walrus@mysql.com
zgreant@mysql.com zgreant@mysql.com
salle@geopard.online.bg

View File

@ -34271,7 +34271,7 @@ Some small changes to the join table optimizer to make some joins faster.
@code{MYSQL} ととしてコールできず、この代わりに @code{mysql_field_count()} を @code{MYSQL} ととしてコールできず、この代わりに @code{mysql_field_count()} を
使用しなくてはなりません。 使用しなくてはなりません。
@item @item
@code{LIBEWRAP} の追加; Patch by Henning P . Schmiedehausen. @code{LIBWRAP} の追加; Patch by Henning P . Schmiedehausen.
@item @item
Don't allow @code{AUTO_INCREMENT} for other than numerical columns. Don't allow @code{AUTO_INCREMENT} for other than numerical columns.
@item @item

View File

@ -50610,11 +50610,28 @@ not yet 100% confident in this code.
@appendixsubsec Changes in release 3.23.52 @appendixsubsec Changes in release 3.23.52
@itemize @bullet @itemize @bullet
@item @item
Fixed bug with creating an auto-increment value on second part of a
@code{UNIQUE()} key where first part could contain NULL values.
@item
Don't write slave-timeout reconnects to the error log.
@item
Fixed bug with slave net read timeouting
@item
Fixed bug in ALTERing TABLE of BDB type.
@item
Fixed bug when logging @code{LOAD DATA INFILE} to binary log with no
active database.
@item
Fixed a bug in range optimiser (causing crashes).
@item
Fixed possible problem in replication when doing @code{DROP DATABASE} on a Fixed possible problem in replication when doing @code{DROP DATABASE} on a
database with @code{InnoDB} tables. database with @code{InnoDB} tables.
@item @item
Fixed @code{mysql_info()} to return 0 for the 'Duplicates' value for Fixed that @code{mysql_info()} returns 0 for 'Duplicates' when using
@code{INSERT DELAYED IGNORE} statements. @code{INSERT DELAYED IGNORE}.
@item
Added @code{-DHAVE_BROKEN_REALPATH} to the Mac OS X (darwin) compile
options in @file{configure.in} to fix a failure under high load.
@end itemize @end itemize
@node News-3.23.51, News-3.23.50, News-3.23.52, News-3.23.x @node News-3.23.51, News-3.23.50, News-3.23.52, News-3.23.x
@ -53411,7 +53428,7 @@ All C client API macros are now functions to make shared libraries more
reliable. Because of this, you can no longer call @code{mysql_num_fields()} on reliable. Because of this, you can no longer call @code{mysql_num_fields()} on
a @code{MYSQL} object, you must use @code{mysql_field_count()} instead. a @code{MYSQL} object, you must use @code{mysql_field_count()} instead.
@item @item
Added use of @code{LIBEWRAP}; patch by Henning P. Schmiedehausen. Added use of @code{LIBWRAP}; patch by Henning P. Schmiedehausen.
@item @item
Don't allow @code{AUTO_INCREMENT} for other than numerical columns. Don't allow @code{AUTO_INCREMENT} for other than numerical columns.
@item @item

1
bdb/dist/acconfig.h vendored
View File

@ -52,6 +52,7 @@
#undef HAVE_MUTEX_WIN16 #undef HAVE_MUTEX_WIN16
#undef HAVE_MUTEX_WIN32 #undef HAVE_MUTEX_WIN32
#undef HAVE_MUTEX_X86_GCC_ASSEMBLY #undef HAVE_MUTEX_X86_GCC_ASSEMBLY
#undef HAVE_MUTEX_X86_64_GCC_ASSEMBLY
/* Define if building on QNX. */ /* Define if building on QNX. */
#undef HAVE_QNX #undef HAVE_QNX

View File

@ -314,6 +314,18 @@ AC_TRY_RUN([main(){
}], [db_cv_mutex="x86/gcc-assembly"]) }], [db_cv_mutex="x86/gcc-assembly"])
fi fi
dnl x86_64/gcc: FreeBSD, NetBSD, BSD/OS, Linux
if test "$db_cv_mutex" = no; then
AC_TRY_RUN([main(){
#if defined(x86_64) || defined(__x86_64__)
#if defined(__GNUC__)
exit(0);
#endif
#endif
exit(1);
}], [db_cv_mutex="x86_64/gcc-assembly"])
fi
dnl ia86/gcc: Linux dnl ia86/gcc: Linux
if test "$db_cv_mutex" = no; then if test "$db_cv_mutex" = no; then
AC_TRY_RUN([main(){ AC_TRY_RUN([main(){

View File

@ -611,6 +611,28 @@ typedef unsigned char tsl_t;
#endif #endif
#endif #endif
#ifdef HAVE_MUTEX_X86_64_GCC_ASSEMBLY
typedef unsigned char tsl_t;
#ifdef LOAD_ACTUAL_MUTEX_CODE
/*
* For gcc/x86, 0 is clear, 1 is set.
*/
#define MUTEX_SET(tsl) ({ \
register tsl_t *__l = (tsl); \
int __r; \
asm volatile("mov $1,%%rax; lock; xchgb %1,%%al; xor $1,%%rax"\
: "=&a" (__r), "=m" (*__l) \
: "1" (*__l) \
); \
__r & 1; \
})
#define MUTEX_UNSET(tsl) (*(tsl) = 0)
#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
#endif
#endif
/* /*
* Mutex alignment defaults to one byte. * Mutex alignment defaults to one byte.
* *

View File

@ -2375,6 +2375,7 @@ AC_OUTPUT(Makefile extra/Makefile mysys/Makefile isam/Makefile \
strings/Makefile regex/Makefile heap/Makefile \ strings/Makefile regex/Makefile heap/Makefile \
bdb/Makefile \ bdb/Makefile \
myisam/Makefile myisammrg/Makefile \ myisam/Makefile myisammrg/Makefile \
os2/Makefile os2/include/Makefile os2/include/sys/Makefile \
man/Makefile BUILD/Makefile readline/Makefile vio/Makefile \ man/Makefile BUILD/Makefile readline/Makefile vio/Makefile \
libmysql_r/Makefile libmysqld/Makefile libmysqld/examples/Makefile \ libmysql_r/Makefile libmysqld/Makefile libmysqld/examples/Makefile \
libmysql/Makefile client/Makefile os2/Makefile \ libmysql/Makefile client/Makefile os2/Makefile \

View File

@ -22,7 +22,7 @@ pkginclude_HEADERS = dbug.h m_string.h my_sys.h my_list.h \
errmsg.h my_global.h my_net.h my_alloc.h\ errmsg.h my_global.h my_net.h my_alloc.h\
sslopt-case.h sslopt-longopts.h sslopt-usage.h \ sslopt-case.h sslopt-longopts.h sslopt-usage.h \
sslopt-vars.h $(BUILT_SOURCES) sslopt-vars.h $(BUILT_SOURCES)
noinst_HEADERS = config-win.h \ noinst_HEADERS = config-win.h config-os2.h \
nisam.h heap.h merge.h my_bitmap.h\ nisam.h heap.h merge.h my_bitmap.h\
myisam.h myisampack.h myisammrg.h ft_global.h\ myisam.h myisampack.h myisammrg.h ft_global.h\
my_dir.h mysys_err.h my_base.h \ my_dir.h mysys_err.h my_base.h \

View File

@ -26,6 +26,7 @@
#include <os2.h> #include <os2.h>
#include <math.h> #include <math.h>
#include <io.h> #include <io.h>
#include <types.h>
/* Define to name of system eg solaris*/ /* Define to name of system eg solaris*/
#define SYSTEM_TYPE "IBM OS/2 Warp" #define SYSTEM_TYPE "IBM OS/2 Warp"
@ -55,6 +56,8 @@
#define FILE_BINARY O_BINARY /* my_fopen in binary mode */ #define FILE_BINARY O_BINARY /* my_fopen in binary mode */
#define S_IROTH S_IREAD /* for my_lib */ #define S_IROTH S_IREAD /* for my_lib */
#define CANT_DELETE_OPEN_FILES /* saves open files in a list, for delayed delete */
#define O_NONBLOCK 0x10 #define O_NONBLOCK 0x10
#define NO_OPEN_3 /* For my_create() */ #define NO_OPEN_3 /* For my_create() */
@ -84,7 +87,7 @@
#define F_WRLCK 2 /* Write lock. */ #define F_WRLCK 2 /* Write lock. */
#define F_UNLCK 0 /* Remove lock. */ #define F_UNLCK 0 /* Remove lock. */
#define S_IFMT 0xF000 /* Mask for file type */ #define S_IFMT 0x17000 /* Mask for file type */
#define F_TO_EOF 0L /* Param to lockf() to lock rest of file */ #define F_TO_EOF 0L /* Param to lockf() to lock rest of file */
#define HUGE_PTR #define HUGE_PTR
@ -268,7 +271,7 @@ typedef unsigned long long os_off_t;
/* #undef HAVE_NONPOSIX_PTHREAD_MUTEX_INIT */ /* #undef HAVE_NONPOSIX_PTHREAD_MUTEX_INIT */
/* READLINE: */ /* READLINE: */
#define HAVE_POSIX_SIGNALS 1 #define HAVE_POSIX_SIGNALS 0
/* sigwait with one argument */ /* sigwait with one argument */
/* #undef HAVE_NONPOSIX_SIGWAIT */ /* #undef HAVE_NONPOSIX_SIGWAIT */

View File

@ -572,6 +572,13 @@ btr_page_get_father_for_rec(
if (btr_node_ptr_get_child_page_no(node_ptr) != if (btr_node_ptr_get_child_page_no(node_ptr) !=
buf_frame_get_page_no(page)) { buf_frame_get_page_no(page)) {
fprintf(stderr,
"InnoDB: Dump of the child page:\n");
buf_page_print(buf_frame_align(page));
fprintf(stderr,
"InnoDB: Dump of the parent page:\n");
buf_page_print(buf_frame_align(node_ptr));
fprintf(stderr, fprintf(stderr,
"InnoDB: Corruption of an index tree: table %s, index %s,\n" "InnoDB: Corruption of an index tree: table %s, index %s,\n"
"InnoDB: father ptr page no %lu, child page no %lu\n", "InnoDB: father ptr page no %lu, child page no %lu\n",
@ -581,6 +588,12 @@ btr_page_get_father_for_rec(
buf_frame_get_page_no(page)); buf_frame_get_page_no(page));
page_rec_print(page_rec_get_next(page_get_infimum_rec(page))); page_rec_print(page_rec_get_next(page_get_infimum_rec(page)));
page_rec_print(node_ptr); page_rec_print(node_ptr);
fprintf(stderr,
"InnoDB: You should dump + drop + reimport the table to fix the\n"
"InnoDB: corruption. If the crash happens at the database startup, see\n"
"InnoDB: section 6.1 of http://www.innodb.com/ibman.html about forcing\n"
"InnoDB: recovery. Then dump + drop + reimport.\n");
} }
ut_a(btr_node_ptr_get_child_page_no(node_ptr) == ut_a(btr_node_ptr_get_child_page_no(node_ptr) ==
@ -780,12 +793,14 @@ top_loop:
/***************************************************************** /*****************************************************************
Reorganizes an index page. */ Reorganizes an index page. */
static
void void
btr_page_reorganize_low( btr_page_reorganize_low(
/*====================*/ /*====================*/
ibool low, /* in: TRUE if locks should not be updated, i.e., ibool recovery,/* in: TRUE if called in recovery: locks should not
there cannot exist locks on the page */ be updated, i.e., there cannot exist locks on the
page, and a hash index should not be dropped: it
cannot exist */
page_t* page, /* in: page to be reorganized */ page_t* page, /* in: page to be reorganized */
mtr_t* mtr) /* in: mtr */ mtr_t* mtr) /* in: mtr */
{ {
@ -805,7 +820,9 @@ btr_page_reorganize_low(
/* Copy the old page to temporary space */ /* Copy the old page to temporary space */
buf_frame_copy(new_page, page); buf_frame_copy(new_page, page);
btr_search_drop_page_hash_index(page); if (!recovery) {
btr_search_drop_page_hash_index(page);
}
/* Recreate the page: note that global data on page (possible /* Recreate the page: note that global data on page (possible
segment headers, next page-field, etc.) is preserved intact */ segment headers, next page-field, etc.) is preserved intact */
@ -820,7 +837,7 @@ btr_page_reorganize_low(
/* Copy max trx id to recreated page */ /* Copy max trx id to recreated page */
page_set_max_trx_id(page, page_get_max_trx_id(new_page)); page_set_max_trx_id(page, page_get_max_trx_id(new_page));
if (!low) { if (!recovery) {
/* Update the record lock bitmaps */ /* Update the record lock bitmaps */
lock_move_reorganize_page(page, new_page); lock_move_reorganize_page(page, new_page);
} }
@ -2059,8 +2076,7 @@ btr_discard_page(
btr_search_drop_page_hash_index(page); btr_search_drop_page_hash_index(page);
if ((left_page_no == FIL_NULL) if (left_page_no == FIL_NULL && btr_page_get_level(page, mtr) > 0) {
&& (btr_page_get_level(page, mtr) > 0)) {
/* We have to mark the leftmost node pointer on the right /* We have to mark the leftmost node pointer on the right
side page as the predefined minimum record */ side page as the predefined minimum record */

View File

@ -36,9 +36,16 @@ Created 10/16/1994 Heikki Tuuri
#include "ibuf0ibuf.h" #include "ibuf0ibuf.h"
#include "lock0lock.h" #include "lock0lock.h"
/* If the following is set to TRUE, this module prints a lot of
trace information of individual record operations */
ibool btr_cur_print_record_ops = FALSE;
ulint btr_cur_rnd = 0; ulint btr_cur_rnd = 0;
ulint btr_cur_n_non_sea = 0; ulint btr_cur_n_non_sea = 0;
ulint btr_cur_n_sea = 0;
ulint btr_cur_n_non_sea_old = 0;
ulint btr_cur_n_sea_old = 0;
/* In the optimistic insert, if the insert does not fit, but this much space /* In the optimistic insert, if the insert does not fit, but this much space
can be released by page reorganize, then it is reorganized */ can be released by page reorganize, then it is reorganized */
@ -187,11 +194,7 @@ btr_cur_search_to_nth_level(
tuple must be set so that it cannot get tuple must be set so that it cannot get
compared to the node ptr page number field! */ compared to the node ptr page number field! */
ulint mode, /* in: PAGE_CUR_L, ...; ulint mode, /* in: PAGE_CUR_L, ...;
NOTE that if the search is made using a unique Inserts should always be made using
prefix of a record, mode should be
PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
may end up on the previous page relative to the
record! Inserts should always be made using
PAGE_CUR_LE to search the position! */ PAGE_CUR_LE to search the position! */
ulint latch_mode, /* in: BTR_SEARCH_LEAF, ..., ORed with ulint latch_mode, /* in: BTR_SEARCH_LEAF, ..., ORed with
BTR_INSERT and BTR_ESTIMATE; BTR_INSERT and BTR_ESTIMATE;
@ -268,7 +271,7 @@ btr_cur_search_to_nth_level(
#ifdef UNIV_SEARCH_PERF_STAT #ifdef UNIV_SEARCH_PERF_STAT
info->n_searches++; info->n_searches++;
#endif #endif
if (btr_search_latch.writer != RW_LOCK_NOT_LOCKED if (btr_search_latch.writer == RW_LOCK_NOT_LOCKED
&& latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ && latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ
&& !estimate && !estimate
&& btr_search_guess_on_hash(index, info, tuple, mode, && btr_search_guess_on_hash(index, info, tuple, mode,
@ -283,14 +286,14 @@ btr_cur_search_to_nth_level(
|| mode != PAGE_CUR_LE); || mode != PAGE_CUR_LE);
ut_ad(cursor->low_match != ULINT_UNDEFINED ut_ad(cursor->low_match != ULINT_UNDEFINED
|| mode != PAGE_CUR_LE); || mode != PAGE_CUR_LE);
btr_cur_n_sea++;
return; return;
} }
#endif #endif
#endif #endif
#ifdef UNIV_SEARCH_PERF_STAT
btr_cur_n_non_sea++; btr_cur_n_non_sea++;
#endif
/* If the hash search did not succeed, do binary search down the /* If the hash search did not succeed, do binary search down the
tree */ tree */
@ -796,15 +799,28 @@ btr_cur_optimistic_insert(
ulint data_size; ulint data_size;
ulint extra_size; ulint extra_size;
ulint type; ulint type;
ulint err; ulint err;
ut_ad(dtuple_check_typed(entry));
*big_rec = NULL; *big_rec = NULL;
page = btr_cur_get_page(cursor); page = btr_cur_get_page(cursor);
index = cursor->index; index = cursor->index;
if (!dtuple_check_typed_no_assert(entry)) {
fprintf(stderr,
"InnoDB: Error in a tuple to insert into table %lu index %lu\n",
index->table_name, index->name);
}
if (btr_cur_print_record_ops && thr) {
printf(
"Trx with id %lu %lu going to insert to table %s index %s\n",
ut_dulint_get_high(thr_get_trx(thr)->id),
ut_dulint_get_low(thr_get_trx(thr)->id),
index->table_name, index->name);
dtuple_print(entry);
}
ut_ad(mtr_memo_contains(mtr, buf_block_align(page), ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
MTR_MEMO_PAGE_X_FIX)); MTR_MEMO_PAGE_X_FIX));
max_size = page_get_max_insert_size_after_reorganize(page, 1); max_size = page_get_max_insert_size_after_reorganize(page, 1);
@ -928,7 +944,7 @@ calculate_sizes_again:
buf_frame_get_page_no(page), max_size, buf_frame_get_page_no(page), max_size,
rec_size + PAGE_DIR_SLOT_SIZE, type); rec_size + PAGE_DIR_SLOT_SIZE, type);
*/ */
if (!(type & (DICT_CLUSTERED | DICT_UNIQUE))) { if (!(type & DICT_CLUSTERED)) {
/* We have added a record to page: update its free bits */ /* We have added a record to page: update its free bits */
ibuf_update_free_bits_if_full(cursor->index, page, max_size, ibuf_update_free_bits_if_full(cursor->index, page, max_size,
rec_size + PAGE_DIR_SLOT_SIZE); rec_size + PAGE_DIR_SLOT_SIZE);
@ -1258,6 +1274,15 @@ btr_cur_update_sec_rec_in_place(
rec = btr_cur_get_rec(cursor); rec = btr_cur_get_rec(cursor);
if (btr_cur_print_record_ops && thr) {
printf(
"Trx with id %lu %lu going to update table %s index %s\n",
ut_dulint_get_high(thr_get_trx(thr)->id),
ut_dulint_get_low(thr_get_trx(thr)->id),
index->table_name, index->name);
rec_print(rec);
}
err = lock_sec_rec_modify_check_and_lock(0, rec, index, thr); err = lock_sec_rec_modify_check_and_lock(0, rec, index, thr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
@ -1312,6 +1337,15 @@ btr_cur_update_in_place(
index = cursor->index; index = cursor->index;
trx = thr_get_trx(thr); trx = thr_get_trx(thr);
if (btr_cur_print_record_ops && thr) {
printf(
"Trx with id %lu %lu going to update table %s index %s\n",
ut_dulint_get_high(thr_get_trx(thr)->id),
ut_dulint_get_low(thr_get_trx(thr)->id),
index->table_name, index->name);
rec_print(rec);
}
/* Do lock checking and undo logging */ /* Do lock checking and undo logging */
err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info, err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info,
thr, &roll_ptr); thr, &roll_ptr);
@ -1323,6 +1357,12 @@ btr_cur_update_in_place(
block = buf_block_align(rec); block = buf_block_align(rec);
if (block->is_hashed) { if (block->is_hashed) {
if (row_upd_changes_ord_field_binary(NULL, index, update)) {
/* Remove possible hash index pointer to this record */
btr_search_update_hash_on_delete(cursor);
}
rw_lock_x_lock(&btr_search_latch); rw_lock_x_lock(&btr_search_latch);
} }
@ -1398,6 +1438,15 @@ btr_cur_optimistic_update(
rec = btr_cur_get_rec(cursor); rec = btr_cur_get_rec(cursor);
index = cursor->index; index = cursor->index;
if (btr_cur_print_record_ops && thr) {
printf(
"Trx with id %lu %lu going to update table %s index %s\n",
ut_dulint_get_high(thr_get_trx(thr)->id),
ut_dulint_get_low(thr_get_trx(thr)->id),
index->table_name, index->name);
rec_print(rec);
}
ut_ad(mtr_memo_contains(mtr, buf_block_align(page), ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
MTR_MEMO_PAGE_X_FIX)); MTR_MEMO_PAGE_X_FIX));
if (!row_upd_changes_field_size(rec, index, update)) { if (!row_upd_changes_field_size(rec, index, update)) {
@ -1973,6 +2022,15 @@ btr_cur_del_mark_set_clust_rec(
rec = btr_cur_get_rec(cursor); rec = btr_cur_get_rec(cursor);
index = cursor->index; index = cursor->index;
if (btr_cur_print_record_ops && thr) {
printf(
"Trx with id %lu %lu going to del mark table %s index %s\n",
ut_dulint_get_high(thr_get_trx(thr)->id),
ut_dulint_get_low(thr_get_trx(thr)->id),
index->table_name, index->name);
rec_print(rec);
}
ut_ad(index->type & DICT_CLUSTERED); ut_ad(index->type & DICT_CLUSTERED);
ut_ad(rec_get_deleted_flag(rec) == FALSE); ut_ad(rec_get_deleted_flag(rec) == FALSE);
@ -2102,6 +2160,15 @@ btr_cur_del_mark_set_sec_rec(
rec = btr_cur_get_rec(cursor); rec = btr_cur_get_rec(cursor);
if (btr_cur_print_record_ops && thr) {
printf(
"Trx with id %lu %lu going to del mark table %s index %s\n",
ut_dulint_get_high(thr_get_trx(thr)->id),
ut_dulint_get_low(thr_get_trx(thr)->id),
cursor->index->table_name, cursor->index->name);
rec_print(rec);
}
err = lock_sec_rec_modify_check_and_lock(flags, rec, cursor->index, err = lock_sec_rec_modify_check_and_lock(flags, rec, cursor->index,
thr); thr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {

View File

@ -15,6 +15,7 @@ Created 2/17/1996 Heikki Tuuri
#include "page0page.h" #include "page0page.h"
#include "page0cur.h" #include "page0cur.h"
#include "btr0cur.h" #include "btr0cur.h"
#include "btr0pcur.h"
#include "btr0btr.h" #include "btr0btr.h"
ulint btr_search_n_succ = 0; ulint btr_search_n_succ = 0;
@ -145,6 +146,8 @@ btr_search_info_create(
info = mem_heap_alloc(heap, sizeof(btr_search_t)); info = mem_heap_alloc(heap, sizeof(btr_search_t));
info->magic_n = BTR_SEARCH_MAGIC_N;
info->last_search = NULL; info->last_search = NULL;
info->n_direction = 0; info->n_direction = 0;
info->root_guess = NULL; info->root_guess = NULL;
@ -159,6 +162,12 @@ btr_search_info_create(
info->n_patt_succ = 0; info->n_patt_succ = 0;
info->n_searches = 0; info->n_searches = 0;
/* Set some sensible values */
info->n_fields = 1;
info->n_bytes = 0;
info->side = BTR_SEARCH_LEFT_SIDE;
return(info); return(info);
} }
@ -197,7 +206,7 @@ btr_search_info_update_hash(
/* Test if the search would have succeeded using the recommended /* Test if the search would have succeeded using the recommended
hash prefix */ hash prefix */
if ((info->n_fields >= n_unique) && (cursor->up_match >= n_unique)) { if (info->n_fields >= n_unique && cursor->up_match >= n_unique) {
info->n_hash_potential++; info->n_hash_potential++;
@ -207,8 +216,8 @@ btr_search_info_update_hash(
cmp = ut_pair_cmp(info->n_fields, info->n_bytes, cmp = ut_pair_cmp(info->n_fields, info->n_bytes,
cursor->low_match, cursor->low_bytes); cursor->low_match, cursor->low_bytes);
if (((info->side == BTR_SEARCH_LEFT_SIDE) && (cmp <= 0)) if ((info->side == BTR_SEARCH_LEFT_SIDE && cmp <= 0)
|| ((info->side == BTR_SEARCH_RIGHT_SIDE) && (cmp > 0))) { || (info->side == BTR_SEARCH_RIGHT_SIDE && cmp > 0)) {
goto set_new_recomm; goto set_new_recomm;
} }
@ -216,8 +225,8 @@ btr_search_info_update_hash(
cmp = ut_pair_cmp(info->n_fields, info->n_bytes, cmp = ut_pair_cmp(info->n_fields, info->n_bytes,
cursor->up_match, cursor->up_bytes); cursor->up_match, cursor->up_bytes);
if (((info->side == BTR_SEARCH_LEFT_SIDE) && (cmp > 0)) if ((info->side == BTR_SEARCH_LEFT_SIDE && cmp > 0)
|| ((info->side == BTR_SEARCH_RIGHT_SIDE) && (cmp <= 0))) { || (info->side == BTR_SEARCH_RIGHT_SIDE && cmp <= 0)) {
goto set_new_recomm; goto set_new_recomm;
} }
@ -233,19 +242,18 @@ set_new_recomm:
info->hash_analysis = 0; info->hash_analysis = 0;
if ((cursor->up_match >= n_unique)
|| (cursor->low_match >= n_unique)) {
info->n_fields = n_unique;
info->n_bytes = 0;
info->side = BTR_SEARCH_LEFT_SIDE;
}
cmp = ut_pair_cmp(cursor->up_match, cursor->up_bytes, cmp = ut_pair_cmp(cursor->up_match, cursor->up_bytes,
cursor->low_match, cursor->low_bytes); cursor->low_match, cursor->low_bytes);
if (cmp == 0) { if (cmp == 0) {
info->n_hash_potential = 0; info->n_hash_potential = 0;
/* For extra safety, we set some sensible values here */
info->n_fields = 1;
info->n_bytes = 0;
info->side = BTR_SEARCH_LEFT_SIDE;
} else if (cmp > 0) { } else if (cmp > 0) {
info->n_hash_potential = 1; info->n_hash_potential = 1;
@ -305,6 +313,9 @@ btr_search_update_block_hash_info(
info->last_hash_succ = FALSE; info->last_hash_succ = FALSE;
ut_a(block->magic_n == BUF_BLOCK_MAGIC_N);
ut_a(info->magic_n == BTR_SEARCH_MAGIC_N);
if ((block->n_hash_helps > 0) if ((block->n_hash_helps > 0)
&& (info->n_hash_potential > 0) && (info->n_hash_potential > 0)
&& (block->n_fields == info->n_fields) && (block->n_fields == info->n_fields)
@ -440,7 +451,9 @@ btr_search_info_update_slow(
rw_lock_x_unlock(&btr_search_latch); rw_lock_x_unlock(&btr_search_latch);
} }
if (build_index) { if (build_index) {
ut_a(block->n_fields + block->n_bytes > 0);
btr_search_build_page_hash_index(block->frame, btr_search_build_page_hash_index(block->frame,
block->n_fields, block->n_fields,
block->n_bytes, block->n_bytes,
@ -622,6 +635,7 @@ btr_search_guess_on_hash(
dulint tree_id; dulint tree_id;
#ifdef notdefined #ifdef notdefined
btr_cur_t cursor2; btr_cur_t cursor2;
btr_pcur_t pcur;
#endif #endif
ut_ad(index && info && tuple && cursor && mtr); ut_ad(index && info && tuple && cursor && mtr);
ut_ad((latch_mode == BTR_SEARCH_LEAF) ut_ad((latch_mode == BTR_SEARCH_LEAF)
@ -664,6 +678,9 @@ btr_search_guess_on_hash(
rw_lock_s_lock(&btr_search_latch); rw_lock_s_lock(&btr_search_latch);
} }
ut_a(btr_search_latch.writer != RW_LOCK_EX);
ut_a(btr_search_latch.reader_count > 0);
rec = ha_search_and_get_data(btr_search_sys->hash_index, fold); rec = ha_search_and_get_data(btr_search_sys->hash_index, fold);
if (!rec) { if (!rec) {
@ -754,7 +771,26 @@ btr_search_guess_on_hash(
btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode, btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
&cursor2, 0, mtr); &cursor2, 0, mtr);
ut_a(btr_cur_get_rec(&cursor2) == btr_cur_get_rec(cursor)); if (mode == PAGE_CUR_GE
&& btr_cur_get_rec(&cursor2) == page_get_supremum_rec(
buf_frame_align(btr_cur_get_rec(&cursor2)))) {
/* If mode is PAGE_CUR_GE, then the binary search
in the index tree may actually take us to the supremum
of the previous page */
info->last_hash_succ = FALSE;
btr_pcur_open_on_user_rec(index, tuple, mode, latch_mode,
&pcur, mtr);
ut_a(btr_pcur_get_rec(&pcur) == btr_cur_get_rec(cursor));
} else {
ut_a(btr_cur_get_rec(&cursor2) == btr_cur_get_rec(cursor));
}
/* NOTE that it is theoretically possible that the above assertions
fail if the page of the cursor gets removed from the buffer pool
meanwhile! Thus it might not be a bug. */
info->last_hash_succ = TRUE; info->last_hash_succ = TRUE;
#endif #endif
@ -835,6 +871,8 @@ btr_search_drop_page_hash_index(
n_fields = block->curr_n_fields; n_fields = block->curr_n_fields;
n_bytes = block->curr_n_bytes; n_bytes = block->curr_n_bytes;
ut_a(n_fields + n_bytes > 0);
rw_lock_s_unlock(&btr_search_latch); rw_lock_s_unlock(&btr_search_latch);
n_recs = page_get_n_recs(page); n_recs = page_get_n_recs(page);
@ -851,6 +889,14 @@ btr_search_drop_page_hash_index(
rec = page_get_infimum_rec(page); rec = page_get_infimum_rec(page);
rec = page_rec_get_next(rec); rec = page_rec_get_next(rec);
if (rec != sup) {
ut_a(n_fields <= rec_get_n_fields(rec));
if (n_bytes > 0) {
ut_a(n_fields < rec_get_n_fields(rec));
}
}
tree_id = btr_page_get_index_id(page); tree_id = btr_page_get_index_id(page);
prev_fold = 0; prev_fold = 0;
@ -861,7 +907,7 @@ btr_search_drop_page_hash_index(
fold = rec_fold(rec, n_fields, n_bytes, tree_id); fold = rec_fold(rec, n_fields, n_bytes, tree_id);
if ((fold == prev_fold) && (prev_fold != 0)) { if (fold == prev_fold && prev_fold != 0) {
goto next_rec; goto next_rec;
} }
@ -873,6 +919,7 @@ btr_search_drop_page_hash_index(
n_cached++; n_cached++;
next_rec: next_rec:
rec = page_rec_get_next(rec); rec = page_rec_get_next(rec);
prev_fold = fold;
} }
rw_lock_x_lock(&btr_search_latch); rw_lock_x_lock(&btr_search_latch);
@ -913,7 +960,7 @@ btr_search_drop_page_hash_when_freed(
mtr_start(&mtr); mtr_start(&mtr);
/* We assume that if the caller has a latch on the page, /* We assume that if the caller has a latch on the page,
then the caller has already drooped the hash index for the page, then the caller has already dropped the hash index for the page,
and we never get here. Therefore we can acquire the s-latch to and we never get here. Therefore we can acquire the s-latch to
the page without fearing a deadlock. */ the page without fearing a deadlock. */
@ -980,6 +1027,8 @@ btr_search_build_page_hash_index(
return; return;
} }
ut_a(n_fields + n_bytes > 0);
/* Calculate and cache fold values and corresponding records into /* Calculate and cache fold values and corresponding records into
an array for fast insertion to the hash index */ an array for fast insertion to the hash index */
@ -995,6 +1044,14 @@ btr_search_build_page_hash_index(
rec = page_get_infimum_rec(page); rec = page_get_infimum_rec(page);
rec = page_rec_get_next(rec); rec = page_rec_get_next(rec);
if (rec != sup) {
ut_a(n_fields <= rec_get_n_fields(rec));
if (n_bytes > 0) {
ut_a(n_fields < rec_get_n_fields(rec));
}
}
/* FIXME: in a mixed tree, all records may not have enough ordering /* FIXME: in a mixed tree, all records may not have enough ordering
fields: */ fields: */
@ -1126,6 +1183,8 @@ btr_search_move_or_delete_hash_entries(
rw_lock_s_unlock(&btr_search_latch); rw_lock_s_unlock(&btr_search_latch);
ut_a(n_fields + n_bytes > 0);
btr_search_build_page_hash_index(new_page, n_fields, n_bytes, btr_search_build_page_hash_index(new_page, n_fields, n_bytes,
side); side);
ut_a(n_fields == block->curr_n_fields); ut_a(n_fields == block->curr_n_fields);
@ -1166,9 +1225,11 @@ btr_search_update_hash_on_delete(
return; return;
} }
ut_a(block->curr_n_fields + block->curr_n_bytes > 0);
table = btr_search_sys->hash_index; table = btr_search_sys->hash_index;
tree_id = ((cursor->index)->tree)->id; tree_id = cursor->index->tree->id;
fold = rec_fold(rec, block->curr_n_fields, block->curr_n_bytes, fold = rec_fold(rec, block->curr_n_fields, block->curr_n_bytes,
tree_id); tree_id);
@ -1285,7 +1346,6 @@ btr_search_update_hash_on_insert(
if (rec != page_get_infimum_rec(page)) { if (rec != page_get_infimum_rec(page)) {
fold = rec_fold(rec, n_fields, n_bytes, tree_id); fold = rec_fold(rec, n_fields, n_bytes, tree_id);
} else { } else {
if (side == BTR_SEARCH_LEFT_SIDE) { if (side == BTR_SEARCH_LEFT_SIDE) {
@ -1370,7 +1430,7 @@ btr_search_print_info(void)
rw_lock_x_lock(&btr_search_latch); rw_lock_x_lock(&btr_search_latch);
ha_print_info(btr_search_sys->hash_index); /* ha_print_info(btr_search_sys->hash_index); */
rw_lock_x_unlock(&btr_search_latch); rw_lock_x_unlock(&btr_search_latch);
} }
@ -1436,11 +1496,71 @@ btr_search_validate(void)
/*=====================*/ /*=====================*/
/* out: TRUE if ok */ /* out: TRUE if ok */
{ {
rw_lock_x_lock(&btr_search_latch); buf_block_t* block;
page_t* page;
ha_node_t* node;
ulint n_page_dumps = 0;
ibool ok = TRUE;
ulint i;
char rec_str[500];
ut_a(ha_validate(btr_search_sys->hash_index)); rw_lock_x_lock(&btr_search_latch);
for (i = 0; i < hash_get_n_cells(btr_search_sys->hash_index); i++) {
node = hash_get_nth_cell(btr_search_sys->hash_index, i)->node;
while (node != NULL) {
block = buf_block_align(node->data);
page = buf_frame_align(node->data);
if (!block->is_hashed
|| node->fold != rec_fold((rec_t*)(node->data),
block->curr_n_fields,
block->curr_n_bytes,
btr_page_get_index_id(page))) {
ok = FALSE;
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error in an adaptive hash index pointer to page %lu\n"
"ptr mem address %lu index id %lu %lu, node fold %lu, rec fold %lu\n",
buf_frame_get_page_no(page),
(ulint)(node->data),
ut_dulint_get_high(btr_page_get_index_id(page)),
ut_dulint_get_low(btr_page_get_index_id(page)),
node->fold, rec_fold((rec_t*)(node->data),
block->curr_n_fields,
block->curr_n_bytes,
btr_page_get_index_id(page)));
rec_sprintf(rec_str, 450, (rec_t*)(node->data));
fprintf(stderr,
"InnoDB: Record %s\n"
"InnoDB: on that page.", rec_str);
fprintf(stderr,
"Page mem address %lu, is hashed %lu, n fields %lu, n bytes %lu\n"
"side %lu\n",
(ulint)page, block->is_hashed, block->curr_n_fields,
block->curr_n_bytes, block->curr_side);
if (n_page_dumps < 20) {
buf_page_print(page);
n_page_dumps++;
}
}
node = node->next;
}
}
if (!ha_validate(btr_search_sys->hash_index)) {
ok = FALSE;
}
rw_lock_x_unlock(&btr_search_latch); rw_lock_x_unlock(&btr_search_latch);
return(TRUE); return(ok);
} }

View File

@ -1125,13 +1125,51 @@ buf_page_get_known_nowait(
return(TRUE); return(TRUE);
} }
/************************************************************************
Inits a page to the buffer buf_pool, for use in ibbackup --restore. */
void
buf_page_init_for_backup_restore(
/*=============================*/
ulint space, /* in: space id */
ulint offset, /* in: offset of the page within space
in units of a page */
buf_block_t* block) /* in: block to init */
{
/* Set the state of the block */
block->magic_n = BUF_BLOCK_MAGIC_N;
block->state = BUF_BLOCK_FILE_PAGE;
block->space = space;
block->offset = offset;
block->lock_hash_val = 0;
block->lock_mutex = NULL;
block->freed_page_clock = 0;
block->newest_modification = ut_dulint_zero;
block->oldest_modification = ut_dulint_zero;
block->accessed = FALSE;
block->buf_fix_count = 0;
block->io_fix = 0;
block->n_hash_helps = 0;
block->is_hashed = FALSE;
block->n_fields = 1;
block->n_bytes = 0;
block->side = BTR_SEARCH_LEFT_SIDE;
block->file_page_was_freed = FALSE;
}
/************************************************************************ /************************************************************************
Inits a page to the buffer buf_pool. */ Inits a page to the buffer buf_pool. */
static static
void void
buf_page_init( buf_page_init(
/*==========*/ /*==========*/
/* out: pointer to the block */
ulint space, /* in: space id */ ulint space, /* in: space id */
ulint offset, /* in: offset of the page within space ulint offset, /* in: offset of the page within space
in units of a page */ in units of a page */
@ -1141,6 +1179,8 @@ buf_page_init(
ut_ad(block->state == BUF_BLOCK_READY_FOR_USE); ut_ad(block->state == BUF_BLOCK_READY_FOR_USE);
/* Set the state of the block */ /* Set the state of the block */
block->magic_n = BUF_BLOCK_MAGIC_N;
block->state = BUF_BLOCK_FILE_PAGE; block->state = BUF_BLOCK_FILE_PAGE;
block->space = space; block->space = space;
block->offset = offset; block->offset = offset;
@ -1758,8 +1798,10 @@ buf_get_n_pending_ios(void)
Prints info of the buffer i/o. */ Prints info of the buffer i/o. */
void void
buf_print_io(void) buf_print_io(
/*==============*/ /*=========*/
char* buf, /* in/out: buffer where to print */
char* buf_end)/* in: buffer end */
{ {
time_t current_time; time_t current_time;
double time_elapsed; double time_elapsed;
@ -1767,19 +1809,28 @@ buf_print_io(void)
ut_ad(buf_pool); ut_ad(buf_pool);
if (buf_end - buf < 400) {
return;
}
size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE; size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE;
mutex_enter(&(buf_pool->mutex)); mutex_enter(&(buf_pool->mutex));
printf("Free list length %lu \n", UT_LIST_GET_LEN(buf_pool->free)); buf += sprintf(buf,
printf("LRU list length %lu \n", UT_LIST_GET_LEN(buf_pool->LRU)); "Free list length %lu \n", UT_LIST_GET_LEN(buf_pool->free));
printf("Flush list length %lu \n", buf += sprintf(buf,
"LRU list length %lu \n", UT_LIST_GET_LEN(buf_pool->LRU));
buf += sprintf(buf,
"Flush list length %lu \n",
UT_LIST_GET_LEN(buf_pool->flush_list)); UT_LIST_GET_LEN(buf_pool->flush_list));
printf("Buffer pool size %lu\n", size); buf += sprintf(buf, "Buffer pool size %lu\n", size);
printf("Pending reads %lu \n", buf_pool->n_pend_reads); buf += sprintf(buf, "Pending reads %lu \n", buf_pool->n_pend_reads);
printf("Pending writes: LRU %lu, flush list %lu, single page %lu\n", buf += sprintf(buf,
"Pending writes: LRU %lu, flush list %lu, single page %lu\n",
buf_pool->n_flush[BUF_FLUSH_LRU], buf_pool->n_flush[BUF_FLUSH_LRU],
buf_pool->n_flush[BUF_FLUSH_LIST], buf_pool->n_flush[BUF_FLUSH_LIST],
buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]); buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
@ -1789,10 +1840,10 @@ buf_print_io(void)
buf_pool->last_printout_time = current_time; buf_pool->last_printout_time = current_time;
printf("Pages read %lu, created %lu, written %lu\n", buf += sprintf(buf, "Pages read %lu, created %lu, written %lu\n",
buf_pool->n_pages_read, buf_pool->n_pages_created, buf_pool->n_pages_read, buf_pool->n_pages_created,
buf_pool->n_pages_written); buf_pool->n_pages_written);
printf("%.2f reads/s, %.2f creates/s, %.2f writes/s\n", buf += sprintf(buf, "%.2f reads/s, %.2f creates/s, %.2f writes/s\n",
(buf_pool->n_pages_read - buf_pool->n_pages_read_old) (buf_pool->n_pages_read - buf_pool->n_pages_read_old)
/ time_elapsed, / time_elapsed,
(buf_pool->n_pages_created - buf_pool->n_pages_created_old) (buf_pool->n_pages_created - buf_pool->n_pages_created_old)
@ -1801,13 +1852,14 @@ buf_print_io(void)
/ time_elapsed); / time_elapsed);
if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) { if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) {
printf("Buffer pool hit rate %lu / 1000\n", buf += sprintf(buf, "Buffer pool hit rate %lu / 1000\n",
1000 1000
- ((1000 * - ((1000 *
(buf_pool->n_pages_read - buf_pool->n_pages_read_old)) (buf_pool->n_pages_read - buf_pool->n_pages_read_old))
/ (buf_pool->n_page_gets - buf_pool->n_page_gets_old))); / (buf_pool->n_page_gets - buf_pool->n_page_gets_old)));
} else { } else {
printf("No buffer pool activity since the last printout\n"); buf += sprintf(buf,
"No buffer pool activity since the last printout\n");
} }
buf_pool->n_page_gets_old = buf_pool->n_page_gets; buf_pool->n_page_gets_old = buf_pool->n_page_gets;

View File

@ -100,6 +100,11 @@ buf_read_page_low(
block = buf_page_init_for_read(mode, space, offset); block = buf_page_init_for_read(mode, space, offset);
if (block != NULL) { if (block != NULL) {
if (buf_debug_prints) {
printf("Posting read request for page %lu, sync %lu\n",
offset, sync);
}
fil_io(OS_FILE_READ | wake_later, fil_io(OS_FILE_READ | wake_later,
sync, space, offset, 0, UNIV_PAGE_SIZE, sync, space, offset, 0, UNIV_PAGE_SIZE,
(void*)block->frame, (void*)block); (void*)block->frame, (void*)block);
@ -467,6 +472,12 @@ buf_read_ahead_linear(
count = 0; count = 0;
/* Since Windows XP seems to schedule the i/o handler thread
very eagerly, and consequently it does not wait for the
full read batch to be posted, we use special heuristics here */
os_aio_simulated_put_read_threads_to_sleep();
for (i = low; i < high; i++) { for (i = low; i < high; i++) {
/* It is only sensible to do read-ahead in the non-sync /* It is only sensible to do read-ahead in the non-sync
aio mode: hence FALSE as the first parameter */ aio mode: hence FALSE as the first parameter */
@ -556,16 +567,34 @@ buf_read_recv_pages(
highest page number the last in the array */ highest page number the last in the array */
ulint n_stored) /* in: number of page numbers in the array */ ulint n_stored) /* in: number of page numbers in the array */
{ {
ulint count;
ulint i; ulint i;
for (i = 0; i < n_stored; i++) { for (i = 0; i < n_stored; i++) {
count = 0;
os_aio_print_debug = FALSE;
while (buf_pool->n_pend_reads >= RECV_POOL_N_FREE_BLOCKS / 2) { while (buf_pool->n_pend_reads >= RECV_POOL_N_FREE_BLOCKS / 2) {
os_aio_simulated_wake_handler_threads(); os_aio_simulated_wake_handler_threads();
os_thread_sleep(500000); os_thread_sleep(500000);
count++;
if (count > 100) {
fprintf(stderr,
"InnoDB: Error: InnoDB has waited for 50 seconds for pending\n"
"InnoDB: reads to the buffer pool to be finished.\n"
"InnoDB: Number of pending reads %lu\n", buf_pool->n_pend_reads);
os_aio_print_debug = TRUE;
}
} }
os_aio_print_debug = FALSE;
if ((i + 1 == n_stored) && sync) { if ((i + 1 == n_stored) && sync) {
buf_read_page_low(TRUE, BUF_READ_ANY_PAGE, space, buf_read_page_low(TRUE, BUF_READ_ANY_PAGE, space,
page_nos[i]); page_nos[i]);

View File

@ -64,6 +64,35 @@ dtuple_get_nth_field_noninline(
return(dtuple_get_nth_field(tuple, n)); return(dtuple_get_nth_field(tuple, n));
} }
/*************************************************************************
Tests if dfield data length and content is equal to the given. */
ibool
dfield_data_is_binary_equal(
/*========================*/
/* out: TRUE if equal */
dfield_t* field, /* in: field */
ulint len, /* in: data length or UNIV_SQL_NULL */
byte* data) /* in: data */
{
if (len != field->len) {
return(FALSE);
}
if (len == UNIV_SQL_NULL) {
return(TRUE);
}
if (0 != ut_memcmp(field->data, data, len)) {
return(FALSE);
}
return(TRUE);
}
/**************************************************************** /****************************************************************
Returns TRUE if lengths of two dtuples are equal and respective data fields Returns TRUE if lengths of two dtuples are equal and respective data fields
in them are equal when compared with collation in char fields (not as binary in them are equal when compared with collation in char fields (not as binary
@ -153,6 +182,69 @@ dtuple_set_n_fields(
tuple->n_fields_cmp = n_fields; tuple->n_fields_cmp = n_fields;
} }
/**************************************************************
Checks that a data field is typed. */
static
ibool
dfield_check_typed_no_assert(
/*=========================*/
/* out: TRUE if ok */
dfield_t* field) /* in: data field */
{
if (dfield_get_type(field)->mtype > DATA_MYSQL
|| dfield_get_type(field)->mtype < DATA_VARCHAR) {
fprintf(stderr,
"InnoDB: Error: data field type %lu, len %lu\n",
dfield_get_type(field)->mtype, dfield_get_len(field));
return(FALSE);
}
return(TRUE);
}
/**************************************************************
Checks that a data tuple is typed. */
ibool
dtuple_check_typed_no_assert(
/*=========================*/
/* out: TRUE if ok */
dtuple_t* tuple) /* in: tuple */
{
dfield_t* field;
ulint i;
char err_buf[1000];
if (dtuple_get_n_fields(tuple) > REC_MAX_N_FIELDS) {
fprintf(stderr,
"InnoDB: Error: index entry has %lu fields\n",
dtuple_get_n_fields(tuple));
dtuple_sprintf(err_buf, 900, tuple);
fprintf(stderr,
"InnoDB: Tuple contents: %s\n", err_buf);
return(FALSE);
}
for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
field = dtuple_get_nth_field(tuple, i);
if (!dfield_check_typed_no_assert(field)) {
dtuple_sprintf(err_buf, 900, tuple);
fprintf(stderr,
"InnoDB: Tuple contents: %s\n", err_buf);
return(FALSE);
}
}
return(TRUE);
}
/************************************************************** /**************************************************************
Checks that a data field is typed. Asserts an error if not. */ Checks that a data field is typed. Asserts an error if not. */
@ -162,8 +254,15 @@ dfield_check_typed(
/* out: TRUE if ok */ /* out: TRUE if ok */
dfield_t* field) /* in: data field */ dfield_t* field) /* in: data field */
{ {
ut_a(dfield_get_type(field)->mtype <= DATA_MYSQL); if (dfield_get_type(field)->mtype > DATA_MYSQL
ut_a(dfield_get_type(field)->mtype >= DATA_VARCHAR); || dfield_get_type(field)->mtype < DATA_VARCHAR) {
fprintf(stderr,
"InnoDB: Error: data field type %lu, len %lu\n",
dfield_get_type(field)->mtype, dfield_get_len(field));
ut_a(0);
}
return(TRUE); return(TRUE);
} }
@ -460,9 +559,21 @@ dtuple_convert_big_rec(
ibool is_externally_stored; ibool is_externally_stored;
ulint i; ulint i;
ulint j; ulint j;
char err_buf[1000];
ut_a(dtuple_check_typed_no_assert(entry));
size = rec_get_converted_size(entry); size = rec_get_converted_size(entry);
if (size > 1000000000) {
fprintf(stderr,
"InnoDB: Warning: tuple size very big: %lu\n", size);
dtuple_sprintf(err_buf, 900, entry);
fprintf(stderr,
"InnoDB: Tuple contents: %s\n", err_buf);
}
heap = mem_heap_create(size + dtuple_get_n_fields(entry) heap = mem_heap_create(size + dtuple_get_n_fields(entry)
* sizeof(big_rec_field_t) + 1000); * sizeof(big_rec_field_t) + 1000);

View File

@ -153,6 +153,7 @@ dict_create_sys_tables_tuple(
if (table->type == DICT_TABLE_CLUSTER_MEMBER) { if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
dfield_set_data(dfield, table->cluster_name, dfield_set_data(dfield, table->cluster_name,
ut_strlen(table->cluster_name)); ut_strlen(table->cluster_name));
ut_a(0); /* Oracle-style clusters are not supported yet */
} else { } else {
dfield_set_data(dfield, NULL, UNIV_SQL_NULL); dfield_set_data(dfield, NULL, UNIV_SQL_NULL);
} }

View File

@ -261,7 +261,7 @@ dict_table_get_index_noninline(
{ {
return(dict_table_get_index(table, name)); return(dict_table_get_index(table, name));
} }
/************************************************************************ /************************************************************************
Initializes the autoinc counter. It is not an error to initialize an already Initializes the autoinc counter. It is not an error to initialize an already
initialized counter. */ initialized counter. */
@ -2810,6 +2810,12 @@ dict_update_statistics_low(
index = dict_table_get_first_index(table); index = dict_table_get_first_index(table);
if (index == NULL) {
/* Table definition is corrupt */
return;
}
while (index) { while (index) {
size = btr_get_size(index, BTR_TOTAL_SIZE); size = btr_get_size(index, BTR_TOTAL_SIZE);
@ -3201,6 +3207,14 @@ dict_print_info_on_foreign_keys(
buf2 += sprintf(buf2, ")"); buf2 += sprintf(buf2, ")");
if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
buf2 += sprintf(buf2, " ON DELETE CASCADE");
}
if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
buf2 += sprintf(buf2, " ON DELETE SET NULL");
}
foreign = UT_LIST_GET_NEXT(foreign_list, foreign); foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
} }

View File

@ -20,33 +20,6 @@ Created 4/24/1996 Heikki Tuuri
#include "dict0dict.h" #include "dict0dict.h"
#include "dict0boot.h" #include "dict0boot.h"
/************************************************************************
Loads definitions for table columns. */
static
void
dict_load_columns(
/*==============*/
dict_table_t* table, /* in: table */
mem_heap_t* heap); /* in: memory heap for temporary storage */
/************************************************************************
Loads definitions for table indexes. */
static
void
dict_load_indexes(
/*==============*/
dict_table_t* table, /* in: table */
mem_heap_t* heap); /* in: memory heap for temporary storage */
/************************************************************************
Loads definitions for index fields. */
static
void
dict_load_fields(
/*=============*/
dict_table_t* table, /* in: table */
dict_index_t* index, /* in: index whose fields to load */
mem_heap_t* heap); /* in: memory heap for temporary storage */
/************************************************************************ /************************************************************************
Finds the first table name in the given database. */ Finds the first table name in the given database. */
@ -194,7 +167,12 @@ loop:
fprintf(stderr, "InnoDB: Failed to load table %s\n", fprintf(stderr, "InnoDB: Failed to load table %s\n",
table_name); table_name);
} else { } else {
dict_update_statistics_low(table, TRUE); /* The table definition was corrupt if there
is no index */
if (dict_table_get_first_index(table)) {
dict_update_statistics_low(table, TRUE);
}
dict_table_print_low(table); dict_table_print_low(table);
} }
@ -207,6 +185,361 @@ loop:
goto loop; goto loop;
} }
/************************************************************************
Loads definitions for table columns. */
static
void
dict_load_columns(
/*==============*/
dict_table_t* table, /* in: table */
mem_heap_t* heap) /* in: memory heap for temporary storage */
{
dict_table_t* sys_columns;
dict_index_t* sys_index;
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
rec_t* rec;
byte* field;
ulint len;
byte* buf;
char* name_buf;
char* name;
ulint mtype;
ulint prtype;
ulint col_len;
ulint prec;
ulint i;
mtr_t mtr;
ut_ad(mutex_own(&(dict_sys->mutex)));
mtr_start(&mtr);
sys_columns = dict_table_get_low((char*) "SYS_COLUMNS");
sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
buf = mem_heap_alloc(heap, 8);
mach_write_to_8(buf, table->id);
dfield_set_data(dfield, buf, 8);
dict_index_copy_types(tuple, sys_index, 1);
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
for (i = 0; i < table->n_cols - DATA_N_SYS_COLS; i++) {
rec = btr_pcur_get_rec(&pcur);
ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
ut_a(!rec_get_deleted_flag(rec));
field = rec_get_nth_field(rec, 0, &len);
ut_ad(len == 8);
ut_a(ut_dulint_cmp(table->id, mach_read_from_8(field)) == 0);
field = rec_get_nth_field(rec, 1, &len);
ut_ad(len == 4);
ut_a(i == mach_read_from_4(field));
ut_a(0 == ut_strcmp((char*) "NAME",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_columns), 4))->name));
field = rec_get_nth_field(rec, 4, &len);
name_buf = mem_heap_alloc(heap, len + 1);
ut_memcpy(name_buf, field, len);
name_buf[len] = '\0';
name = name_buf;
field = rec_get_nth_field(rec, 5, &len);
mtype = mach_read_from_4(field);
field = rec_get_nth_field(rec, 6, &len);
prtype = mach_read_from_4(field);
field = rec_get_nth_field(rec, 7, &len);
col_len = mach_read_from_4(field);
ut_a(0 == ut_strcmp((char*) "PREC",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_columns), 8))->name));
field = rec_get_nth_field(rec, 8, &len);
prec = mach_read_from_4(field);
dict_mem_table_add_col(table, name, mtype, prtype, col_len,
prec);
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
btr_pcur_close(&pcur);
mtr_commit(&mtr);
}
/************************************************************************
Loads definitions for index fields. */
static
void
dict_load_fields(
/*=============*/
dict_table_t* table, /* in: table */
dict_index_t* index, /* in: index whose fields to load */
mem_heap_t* heap) /* in: memory heap for temporary storage */
{
dict_table_t* sys_fields;
dict_index_t* sys_index;
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
char* col_name;
rec_t* rec;
byte* field;
ulint len;
byte* buf;
ulint i;
mtr_t mtr;
ut_ad(mutex_own(&(dict_sys->mutex)));
UT_NOT_USED(table);
mtr_start(&mtr);
sys_fields = dict_table_get_low((char*) "SYS_FIELDS");
sys_index = UT_LIST_GET_FIRST(sys_fields->indexes);
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
buf = mem_heap_alloc(heap, 8);
mach_write_to_8(buf, index->id);
dfield_set_data(dfield, buf, 8);
dict_index_copy_types(tuple, sys_index, 1);
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
for (i = 0; i < index->n_fields; i++) {
rec = btr_pcur_get_rec(&pcur);
ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
if (rec_get_deleted_flag(rec)) {
fprintf(stderr,
"InnoDB: Error: data dictionary entry for table %s is corrupt!\n",
"InnoDB: An index field is delete marked.\n",
table->name);
}
field = rec_get_nth_field(rec, 0, &len);
ut_ad(len == 8);
ut_a(ut_memcmp(buf, field, len) == 0);
field = rec_get_nth_field(rec, 1, &len);
ut_ad(len == 4);
ut_a(i == mach_read_from_4(field));
ut_a(0 == ut_strcmp((char*) "COL_NAME",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_fields), 4))->name));
field = rec_get_nth_field(rec, 4, &len);
col_name = mem_heap_alloc(heap, len + 1);
ut_memcpy(col_name, field, len);
col_name[len] = '\0';
dict_mem_index_add_field(index, col_name, 0);
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
btr_pcur_close(&pcur);
mtr_commit(&mtr);
}
/************************************************************************
Loads definitions for table indexes. Adds them to the data dictionary
cache. */
static
ibool
dict_load_indexes(
/*==============*/
/* out: TRUE if ok, FALSE if corruption
of dictionary table */
dict_table_t* table, /* in: table */
mem_heap_t* heap) /* in: memory heap for temporary storage */
{
dict_table_t* sys_indexes;
dict_index_t* sys_index;
dict_index_t* index;
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
rec_t* rec;
byte* field;
ulint len;
ulint name_len;
char* name_buf;
ulint type;
ulint space;
ulint page_no;
ulint n_fields;
byte* buf;
ibool is_sys_table;
dulint id;
mtr_t mtr;
ut_ad(mutex_own(&(dict_sys->mutex)));
if ((ut_dulint_get_high(table->id) == 0)
&& (ut_dulint_get_low(table->id) < DICT_HDR_FIRST_ID)) {
is_sys_table = TRUE;
} else {
is_sys_table = FALSE;
}
mtr_start(&mtr);
sys_indexes = dict_table_get_low((char*) "SYS_INDEXES");
sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes);
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
buf = mem_heap_alloc(heap, 8);
mach_write_to_8(buf, table->id);
dfield_set_data(dfield, buf, 8);
dict_index_copy_types(tuple, sys_index, 1);
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
for (;;) {
if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
break;
}
rec = btr_pcur_get_rec(&pcur);
field = rec_get_nth_field(rec, 0, &len);
ut_ad(len == 8);
if (ut_memcmp(buf, field, len) != 0) {
break;
}
if (rec_get_deleted_flag(rec)) {
fprintf(stderr,
"InnoDB: Error: data dictionary entry for table %s is corrupt!\n"
"InnoDB: An index is delete marked.\n",
table->name);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
return(FALSE);
}
field = rec_get_nth_field(rec, 1, &len);
ut_ad(len == 8);
id = mach_read_from_8(field);
ut_a(0 == ut_strcmp("NAME",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_indexes), 4))->name));
field = rec_get_nth_field(rec, 4, &name_len);
name_buf = mem_heap_alloc(heap, name_len + 1);
ut_memcpy(name_buf, field, name_len);
name_buf[name_len] = '\0';
field = rec_get_nth_field(rec, 5, &len);
n_fields = mach_read_from_4(field);
field = rec_get_nth_field(rec, 6, &len);
type = mach_read_from_4(field);
field = rec_get_nth_field(rec, 7, &len);
space = mach_read_from_4(field);
ut_a(0 == ut_strcmp((char*) "PAGE_NO",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_indexes), 8))->name));
field = rec_get_nth_field(rec, 8, &len);
page_no = mach_read_from_4(field);
if (page_no == FIL_NULL) {
fprintf(stderr,
"InnoDB: Error: trying to load index %s for table %s\n"
"InnoDB: but the index tree has been freed!\n",
name_buf, table->name);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
return(FALSE);
}
if ((type & DICT_CLUSTERED) == 0
&& NULL == dict_table_get_first_index(table)) {
fprintf(stderr,
"InnoDB: Error: trying to load index %s for table %s\n"
"InnoDB: but the first index was not clustered!\n",
name_buf, table->name);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
return(FALSE);
}
if (is_sys_table
&& ((type & DICT_CLUSTERED)
|| ((table == dict_sys->sys_tables)
&& (name_len == ut_strlen("ID_IND"))
&& (0 == ut_memcmp(name_buf, "ID_IND",
name_len))))) {
/* The index was created in memory already in
booting */
} else {
index = dict_mem_index_create(table->name, name_buf,
space, type, n_fields);
index->page_no = page_no;
index->id = id;
dict_load_fields(table, index, heap);
dict_index_add_to_cache(table, index);
}
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
btr_pcur_close(&pcur);
mtr_commit(&mtr);
return(TRUE);
}
/************************************************************************ /************************************************************************
Loads a table definition and also all its index definitions, and also Loads a table definition and also all its index definitions, and also
the cluster definition if the table is a member in a cluster. Also loads the cluster definition if the table is a member in a cluster. Also loads
@ -338,7 +671,7 @@ dict_load_table(
dict_load_columns(table, heap); dict_load_columns(table, heap);
dict_table_add_to_cache(table); dict_table_add_to_cache(table);
dict_load_indexes(table, heap); dict_load_indexes(table, heap);
ut_a(DB_SUCCESS == dict_load_foreigns(table->name)); ut_a(DB_SUCCESS == dict_load_foreigns(table->name));
@ -436,8 +769,6 @@ dict_load_table_on_id(
/* Load the table definition to memory */ /* Load the table definition to memory */
table = dict_load_table(name); table = dict_load_table(name);
ut_a(table);
btr_pcur_close(&pcur); btr_pcur_close(&pcur);
mtr_commit(&mtr); mtr_commit(&mtr);
@ -467,324 +798,6 @@ dict_load_sys_table(
mem_heap_free(heap); mem_heap_free(heap);
} }
/************************************************************************
Loads definitions for table columns. */
static
void
dict_load_columns(
/*==============*/
dict_table_t* table, /* in: table */
mem_heap_t* heap) /* in: memory heap for temporary storage */
{
dict_table_t* sys_columns;
dict_index_t* sys_index;
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
rec_t* rec;
byte* field;
ulint len;
byte* buf;
char* name_buf;
char* name;
ulint mtype;
ulint prtype;
ulint col_len;
ulint prec;
ulint i;
mtr_t mtr;
ut_ad(mutex_own(&(dict_sys->mutex)));
mtr_start(&mtr);
sys_columns = dict_table_get_low((char *) "SYS_COLUMNS");
sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
buf = mem_heap_alloc(heap, 8);
mach_write_to_8(buf, table->id);
dfield_set_data(dfield, buf, 8);
dict_index_copy_types(tuple, sys_index, 1);
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
for (i = 0; i < table->n_cols - DATA_N_SYS_COLS; i++) {
rec = btr_pcur_get_rec(&pcur);
ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
ut_a(!rec_get_deleted_flag(rec));
field = rec_get_nth_field(rec, 0, &len);
ut_ad(len == 8);
ut_a(ut_dulint_cmp(table->id, mach_read_from_8(field)) == 0);
field = rec_get_nth_field(rec, 1, &len);
ut_ad(len == 4);
ut_a(i == mach_read_from_4(field));
ut_a(0 == ut_strcmp((char *) "NAME",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_columns), 4))->name));
field = rec_get_nth_field(rec, 4, &len);
name_buf = mem_heap_alloc(heap, len + 1);
ut_memcpy(name_buf, field, len);
name_buf[len] = '\0';
name = name_buf;
field = rec_get_nth_field(rec, 5, &len);
mtype = mach_read_from_4(field);
field = rec_get_nth_field(rec, 6, &len);
prtype = mach_read_from_4(field);
field = rec_get_nth_field(rec, 7, &len);
col_len = mach_read_from_4(field);
ut_a(0 == ut_strcmp((char *) "PREC",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_columns), 8))->name));
field = rec_get_nth_field(rec, 8, &len);
prec = mach_read_from_4(field);
dict_mem_table_add_col(table, name, mtype, prtype, col_len,
prec);
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
btr_pcur_close(&pcur);
mtr_commit(&mtr);
}
/************************************************************************
Loads definitions for table indexes. Adds them to the data dictionary cache.
*/
static
void
dict_load_indexes(
/*==============*/
dict_table_t* table, /* in: table */
mem_heap_t* heap) /* in: memory heap for temporary storage */
{
dict_table_t* sys_indexes;
dict_index_t* sys_index;
dict_index_t* index;
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
rec_t* rec;
byte* field;
ulint len;
ulint name_len;
char* name_buf;
ulint type;
ulint space;
ulint page_no;
ulint n_fields;
byte* buf;
ibool is_sys_table;
dulint id;
mtr_t mtr;
ut_ad(mutex_own(&(dict_sys->mutex)));
if ((ut_dulint_get_high(table->id) == 0)
&& (ut_dulint_get_low(table->id) < DICT_HDR_FIRST_ID)) {
is_sys_table = TRUE;
} else {
is_sys_table = FALSE;
}
mtr_start(&mtr);
sys_indexes = dict_table_get_low((char *) "SYS_INDEXES");
sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes);
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
buf = mem_heap_alloc(heap, 8);
mach_write_to_8(buf, table->id);
dfield_set_data(dfield, buf, 8);
dict_index_copy_types(tuple, sys_index, 1);
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
for (;;) {
if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
break;
}
rec = btr_pcur_get_rec(&pcur);
field = rec_get_nth_field(rec, 0, &len);
ut_ad(len == 8);
if (ut_memcmp(buf, field, len) != 0) {
break;
}
ut_a(!rec_get_deleted_flag(rec));
field = rec_get_nth_field(rec, 1, &len);
ut_ad(len == 8);
id = mach_read_from_8(field);
ut_a(0 == ut_strcmp((char *) "NAME",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_indexes), 4))->name));
field = rec_get_nth_field(rec, 4, &name_len);
name_buf = mem_heap_alloc(heap, name_len + 1);
ut_memcpy(name_buf, field, name_len);
name_buf[name_len] = '\0';
field = rec_get_nth_field(rec, 5, &len);
n_fields = mach_read_from_4(field);
field = rec_get_nth_field(rec, 6, &len);
type = mach_read_from_4(field);
field = rec_get_nth_field(rec, 7, &len);
space = mach_read_from_4(field);
ut_a(0 == ut_strcmp((char *) "PAGE_NO",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_indexes), 8))->name));
field = rec_get_nth_field(rec, 8, &len);
page_no = mach_read_from_4(field);
if (is_sys_table
&& ((type & DICT_CLUSTERED)
|| ((table == dict_sys->sys_tables)
&& (name_len == ut_strlen((char *) "ID_IND"))
&& (0 == ut_memcmp(name_buf, (char *) "ID_IND",
name_len))))) {
/* The index was created in memory already in
booting */
} else {
index = dict_mem_index_create(table->name, name_buf,
space, type, n_fields);
index->page_no = page_no;
index->id = id;
dict_load_fields(table, index, heap);
if (index->type & DICT_CLUSTERED == 0
&& NULL == dict_table_get_first_index(table)) {
fprintf(stderr,
"InnoDB: Error: trying to load index %s for table %s\n"
"InnoDB: but the first index was not clustered\n",
index->name, table->name);
} else {
dict_index_add_to_cache(table, index);
}
}
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
btr_pcur_close(&pcur);
mtr_commit(&mtr);
}
/************************************************************************
Loads definitions for index fields. */
static
void
dict_load_fields(
/*=============*/
dict_table_t* table, /* in: table */
dict_index_t* index, /* in: index whose fields to load */
mem_heap_t* heap) /* in: memory heap for temporary storage */
{
dict_table_t* sys_fields;
dict_index_t* sys_index;
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
char* col_name;
rec_t* rec;
byte* field;
ulint len;
byte* buf;
ulint i;
mtr_t mtr;
ut_ad(mutex_own(&(dict_sys->mutex)));
UT_NOT_USED(table);
mtr_start(&mtr);
sys_fields = dict_table_get_low((char *) "SYS_FIELDS");
sys_index = UT_LIST_GET_FIRST(sys_fields->indexes);
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
buf = mem_heap_alloc(heap, 8);
mach_write_to_8(buf, index->id);
dfield_set_data(dfield, buf, 8);
dict_index_copy_types(tuple, sys_index, 1);
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
for (i = 0; i < index->n_fields; i++) {
rec = btr_pcur_get_rec(&pcur);
ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
ut_a(!rec_get_deleted_flag(rec));
field = rec_get_nth_field(rec, 0, &len);
ut_ad(len == 8);
ut_a(ut_memcmp(buf, field, len) == 0);
field = rec_get_nth_field(rec, 1, &len);
ut_ad(len == 4);
ut_a(i == mach_read_from_4(field));
ut_a(0 == ut_strcmp((char *) "COL_NAME",
dict_field_get_col(
dict_index_get_nth_field(
dict_table_get_first_index(sys_fields), 4))->name));
field = rec_get_nth_field(rec, 4, &len);
col_name = mem_heap_alloc(heap, len + 1);
ut_memcpy(col_name, field, len);
col_name[len] = '\0';
dict_mem_index_add_field(index, col_name, 0);
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
btr_pcur_close(&pcur);
mtr_commit(&mtr);
}
/************************************************************************ /************************************************************************
Loads foreign key constraint col names (also for the referenced table). */ Loads foreign key constraint col names (also for the referenced table). */
static static

View File

@ -65,6 +65,9 @@ dict_mem_table_create(
table->cached = FALSE; table->cached = FALSE;
table->mix_id = ut_dulint_zero;
table->mix_len = 0;
table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS) table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS)
* sizeof(dict_col_t)); * sizeof(dict_col_t));
UT_LIST_INIT(table->indexes); UT_LIST_INIT(table->indexes);

View File

@ -573,17 +573,20 @@ fil_read_flushed_lsn_and_arch_log_no(
ulint* max_arch_log_no) /* in/out: */ ulint* max_arch_log_no) /* in/out: */
{ {
byte* buf; byte* buf;
byte* buf2;
dulint flushed_lsn; dulint flushed_lsn;
ulint arch_log_no; ulint arch_log_no;
buf = ut_malloc(UNIV_PAGE_SIZE); buf2 = ut_malloc(2 * UNIV_PAGE_SIZE);
/* Align the memory for a possibel read from a raw device */
buf = ut_align(buf2, UNIV_PAGE_SIZE);
os_file_read(data_file, buf, 0, 0, UNIV_PAGE_SIZE); os_file_read(data_file, buf, 0, 0, UNIV_PAGE_SIZE);
flushed_lsn = mach_read_from_8(buf + FIL_PAGE_FILE_FLUSH_LSN); flushed_lsn = mach_read_from_8(buf + FIL_PAGE_FILE_FLUSH_LSN);
arch_log_no = mach_read_from_4(buf + FIL_PAGE_ARCH_LOG_NO); arch_log_no = mach_read_from_4(buf + FIL_PAGE_ARCH_LOG_NO);
ut_free(buf); ut_free(buf2);
if (!one_read_already) { if (!one_read_already) {
*min_flushed_lsn = flushed_lsn; *min_flushed_lsn = flushed_lsn;

View File

@ -2608,6 +2608,7 @@ fseg_free_page_low(
ulint not_full_n_used; ulint not_full_n_used;
ulint state; ulint state;
ulint i; ulint i;
char errbuf[200];
ut_ad(seg_inode && mtr); ut_ad(seg_inode && mtr);
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) == ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) ==
@ -2621,8 +2622,25 @@ fseg_free_page_low(
descr = xdes_get_descriptor(space, page, mtr); descr = xdes_get_descriptor(space, page, mtr);
ut_a(descr); ut_a(descr);
ut_a(xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr) if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)
== FALSE); != FALSE) {
ut_sprintf_buf(errbuf, descr, 40);
fprintf(stderr,
"InnoDB: Dump of the tablespace extent descriptor: %s\n", errbuf);
fprintf(stderr,
"InnoDB: Serious error! InnoDB is trying to free page %lu\n",
"InnoDB: though it is already marked as free in the tablespace!\n"
"InnoDB: The tablespace free space info is corrupt.\n"
"InnoDB: You may need to dump your InnoDB tables and recreate the whole\n"
"InnoDB: database!\n", page);
fprintf(stderr,
"InnoDB: If the InnoDB recovery crashes here, see section 6.1\n"
"InnoDB: of http://www.innodb.com/ibman.html about forcing recovery.\n");
ut_a(0);
}
state = xdes_get_state(descr, mtr); state = xdes_get_state(descr, mtr);
if (state != XDES_FSEG) { if (state != XDES_FSEG) {

View File

@ -194,7 +194,7 @@ ha_delete(
node = ha_search_with_data(table, fold, data); node = ha_search_with_data(table, fold, data);
ut_ad(node); ut_a(node);
ha_delete_hash_node(table, node); ha_delete_hash_node(table, node);
} }
@ -232,6 +232,16 @@ ha_remove_all_nodes_to_page(
node = ha_chain_get_next(table, node); node = ha_chain_get_next(table, node);
} }
} }
/* Check that all nodes really got deleted */
node = ha_chain_get_first(table, fold);
while (node) {
ut_a(buf_frame_align(ha_node_get_data(node)) != page);
node = ha_chain_get_next(table, node);
}
} }
/***************************************************************** /*****************************************************************
@ -245,6 +255,7 @@ ha_validate(
{ {
hash_cell_t* cell; hash_cell_t* cell;
ha_node_t* node; ha_node_t* node;
ibool ok = TRUE;
ulint i; ulint i;
for (i = 0; i < hash_get_n_cells(table); i++) { for (i = 0; i < hash_get_n_cells(table); i++) {
@ -254,13 +265,21 @@ ha_validate(
node = cell->node; node = cell->node;
while (node) { while (node) {
ut_a(hash_calc_hash(node->fold, table) == i); if (hash_calc_hash(node->fold, table) != i) {
ut_print_timestamp(stderr);
fprintf(stderr,
"InnoDB: Error: hash table node fold value %lu does not\n"
"InnoDB: match with the cell number %lu.\n",
node->fold, i);
ok = FALSE;
}
node = node->next; node = node->next;
} }
} }
return(TRUE); return(ok);
} }
/***************************************************************** /*****************************************************************
@ -269,16 +288,22 @@ Prints info of a hash table. */
void void
ha_print_info( ha_print_info(
/*==========*/ /*==========*/
char* buf, /* in/out: buffer where to print */
char* buf_end,/* in: buffer end */
hash_table_t* table) /* in: hash table */ hash_table_t* table) /* in: hash table */
{ {
hash_cell_t* cell; hash_cell_t* cell;
ha_node_t* node; /* ha_node_t* node; */
ulint nodes = 0; ulint nodes = 0;
ulint cells = 0; ulint cells = 0;
ulint len = 0; ulint len = 0;
ulint max_len = 0; ulint max_len = 0;
ulint i; ulint i;
if (buf_end - buf < 200) {
return;
}
for (i = 0; i < hash_get_n_cells(table); i++) { for (i = 0; i < hash_get_n_cells(table); i++) {
cell = hash_get_nth_cell(table, i); cell = hash_get_nth_cell(table, i);
@ -286,7 +311,7 @@ ha_print_info(
if (cell->node) { if (cell->node) {
cells++; cells++;
/*
len = 0; len = 0;
node = cell->node; node = cell->node;
@ -306,12 +331,10 @@ ha_print_info(
if (len > max_len) { if (len > max_len) {
max_len = len; max_len = len;
} }
*/
} }
} }
printf("Hash table size %lu, used cells %lu, nodes %lu\n", buf += sprintf(buf, "Hash table size %lu, used cells %lu\n",
hash_get_n_cells(table), cells, nodes); hash_get_n_cells(table), cells);
printf("max chain length %lu\n", max_len);
ut_a(ha_validate(table));
} }

View File

@ -687,21 +687,21 @@ ibuf_bitmap_get_map_page(
/**************************************************************************** /****************************************************************************
Sets the free bits of the page in the ibuf bitmap. This is done in a separate Sets the free bits of the page in the ibuf bitmap. This is done in a separate
mini-transaction, hence this operation does not restrict further work to only mini-transaction, hence this operation does not restrict further work to only
ibuf bitmap operations, which would result if the latch to the bitmap pag ibuf bitmap operations, which would result if the latch to the bitmap page
were kept. */ were kept. */
UNIV_INLINE UNIV_INLINE
void void
ibuf_set_free_bits_low( ibuf_set_free_bits_low(
/*===================*/ /*===================*/
ulint type, /* in: index type */ ulint type, /* in: index type */
page_t* page, /* in: index page; free bit is reset if the index is page_t* page, /* in: index page; free bit is set if the index is
a non-clustered non-unique, and page level is 0 */ non-clustered and page level is 0 */
ulint val, /* in: value to set: < 4 */ ulint val, /* in: value to set: < 4 */
mtr_t* mtr) /* in: mtr */ mtr_t* mtr) /* in: mtr */
{ {
page_t* bitmap_page; page_t* bitmap_page;
if (type & (DICT_CLUSTERED | DICT_UNIQUE)) { if (type & DICT_CLUSTERED) {
return; return;
} }
@ -735,8 +735,8 @@ void
ibuf_set_free_bits( ibuf_set_free_bits(
/*===============*/ /*===============*/
ulint type, /* in: index type */ ulint type, /* in: index type */
page_t* page, /* in: index page; free bit is reset if the index is page_t* page, /* in: index page; free bit is set if the index is
a non-clustered non-unique, and page level is 0 */ non-clustered and page level is 0 */
ulint val, /* in: value to set: < 4 */ ulint val, /* in: value to set: < 4 */
ulint max_val)/* in: ULINT_UNDEFINED or a maximum value which ulint max_val)/* in: ULINT_UNDEFINED or a maximum value which
the bits must have before setting; this is for the bits must have before setting; this is for
@ -745,7 +745,7 @@ ibuf_set_free_bits(
mtr_t mtr; mtr_t mtr;
page_t* bitmap_page; page_t* bitmap_page;
if (type & (DICT_CLUSTERED | DICT_UNIQUE)) { if (type & DICT_CLUSTERED) {
return; return;
} }
@ -2026,7 +2026,7 @@ ibuf_insert_low(
ulint n_stored; ulint n_stored;
ulint bits; ulint bits;
ut_a(!(index->type & (DICT_UNIQUE | DICT_CLUSTERED))); ut_a(!(index->type & DICT_CLUSTERED));
ut_ad(dtuple_check_typed(entry)); ut_ad(dtuple_check_typed(entry));
do_merge = FALSE; do_merge = FALSE;
@ -2256,10 +2256,7 @@ ibuf_insert(
ut_ad(dtuple_check_typed(entry)); ut_ad(dtuple_check_typed(entry));
if (index->type & DICT_CLUSTERED || index->type & DICT_UNIQUE) { ut_a(!(index->type & DICT_CLUSTERED));
return(FALSE);
}
if (rec_get_converted_size(entry) if (rec_get_converted_size(entry)
>= page_get_free_space_of_empty() / 2) { >= page_get_free_space_of_empty() / 2) {
@ -2304,6 +2301,7 @@ ibuf_insert_to_index_page(
rec_t* rec; rec_t* rec;
page_t* bitmap_page; page_t* bitmap_page;
ulint old_bits; ulint old_bits;
char errbuf[1000];
ut_ad(ibuf_inside()); ut_ad(ibuf_inside());
ut_ad(dtuple_check_typed(entry)); ut_ad(dtuple_check_typed(entry));
@ -2326,11 +2324,24 @@ ibuf_insert_to_index_page(
/* This time the record must fit */ /* This time the record must fit */
if (!page_cur_tuple_insert(&page_cur, entry, mtr)) { if (!page_cur_tuple_insert(&page_cur, entry, mtr)) {
printf(
"Ibuf insert fails; page free %lu, dtuple size %lu\n", ut_print_timestamp(stderr);
fprintf(stderr,
"InnoDB: Error: Insert buffer insert fails; page free %lu, dtuple size %lu\n",
page_get_max_insert_size(page, 1), page_get_max_insert_size(page, 1),
rec_get_converted_size(entry)); rec_get_converted_size(entry));
dtuple_sprintf(errbuf, 900, entry);
fprintf(stderr,
"InnoDB: Cannot insert index record %s\n", errbuf);
fprintf(stderr,
"InnoDB: The table where where this index record belongs\n"
"InnoDB: is now probably corrupt. Please run CHECK TABLE on\n"
"InnoDB: that table.\n");
bitmap_page = ibuf_bitmap_get_map_page( bitmap_page = ibuf_bitmap_get_map_page(
buf_frame_get_space_id(page), buf_frame_get_space_id(page),
buf_frame_get_page_no(page), buf_frame_get_page_no(page),
@ -2341,9 +2352,11 @@ ibuf_insert_to_index_page(
buf_frame_get_page_no(page), buf_frame_get_page_no(page),
IBUF_BITMAP_FREE, mtr); IBUF_BITMAP_FREE, mtr);
printf("Bitmap bits %lu\n", old_bits); fprintf(stderr, "Bitmap bits %lu\n", old_bits);
ut_error; fprintf(stderr,
"InnoDB: Send a detailed bug report to mysql@lists.mysql.com!\n");
} }
} }
} }
@ -2692,22 +2705,30 @@ ibuf_validate_low(void)
Prints info of ibuf. */ Prints info of ibuf. */
void void
ibuf_print(void) ibuf_print(
/*============*/ /*=======*/
char* buf, /* in/out: buffer where to print */
char* buf_end)/* in: buffer end */
{ {
ibuf_data_t* data; ibuf_data_t* data;
#ifdef UNIV_IBUF_DEBUG #ifdef UNIV_IBUF_DEBUG
ulint i; ulint i;
#endif #endif
if (buf_end - buf < 500) {
return;
}
mutex_enter(&ibuf_mutex); mutex_enter(&ibuf_mutex);
data = UT_LIST_GET_FIRST(ibuf->data_list); data = UT_LIST_GET_FIRST(ibuf->data_list);
while (data) { while (data) {
printf( buf += sprintf(buf,
"Ibuf for space %lu: size %lu, free list len %lu, seg size %lu,\n", "Ibuf for space %lu: size %lu, free list len %lu, seg size %lu,\n",
data->space, data->size, data->free_list_len, data->seg_size); data->space, data->size, data->free_list_len, data->seg_size);
printf("%lu inserts, %lu merged recs, %lu merges\n",
buf += sprintf(buf,
"%lu inserts, %lu merged recs, %lu merges\n",
data->n_inserts, data->n_merged_recs, data->n_merges); data->n_inserts, data->n_merged_recs, data->n_merges);
#ifdef UNIV_IBUF_DEBUG #ifdef UNIV_IBUF_DEBUG
for (i = 0; i < IBUF_COUNT_N_PAGES; i++) { for (i = 0; i < IBUF_COUNT_N_PAGES; i++) {

View File

@ -204,16 +204,6 @@ btr_page_reorganize(
page_t* page, /* in: page to be reorganized */ page_t* page, /* in: page to be reorganized */
mtr_t* mtr); /* in: mtr */ mtr_t* mtr); /* in: mtr */
/***************************************************************** /*****************************************************************
Reorganizes an index page. */
void
btr_page_reorganize_low(
/*====================*/
ibool low, /* in: TRUE if locks should not be updated, i.e.,
there cannot exist locks on the page */
page_t* page, /* in: page to be reorganized */
mtr_t* mtr); /* in: mtr */
/*****************************************************************
Decides if the page should be split at the convergence point of Decides if the page should be split at the convergence point of
inserts converging to left. */ inserts converging to left. */

View File

@ -709,6 +709,9 @@ allowed to free an inherited external field. */
#define BTR_EXTERN_INHERITED_FLAG 64 #define BTR_EXTERN_INHERITED_FLAG 64
extern ulint btr_cur_n_non_sea; extern ulint btr_cur_n_non_sea;
extern ulint btr_cur_n_sea;
extern ulint btr_cur_n_non_sea_old;
extern ulint btr_cur_n_sea_old;
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "btr0cur.ic" #include "btr0cur.ic"

View File

@ -176,6 +176,7 @@ btr_search_validate(void);
/* The search info struct in an index */ /* The search info struct in an index */
struct btr_search_struct{ struct btr_search_struct{
ulint magic_n; /* magic number */
/* The following 4 fields are currently not used: */ /* The following 4 fields are currently not used: */
rec_t* last_search; /* pointer to the lower limit record of the rec_t* last_search; /* pointer to the lower limit record of the
previous search; NULL if not known */ previous search; NULL if not known */
@ -220,6 +221,8 @@ struct btr_search_struct{
ulint n_searches; /* number of searches */ ulint n_searches; /* number of searches */
}; };
#define BTR_SEARCH_MAGIC_N 1112765
/* The hash index system */ /* The hash index system */
typedef struct btr_search_sys_struct btr_search_sys_t; typedef struct btr_search_sys_struct btr_search_sys_t;

View File

@ -219,6 +219,16 @@ buf_page_create(
a page */ a page */
mtr_t* mtr); /* in: mini-transaction handle */ mtr_t* mtr); /* in: mini-transaction handle */
/************************************************************************ /************************************************************************
Inits a page to the buffer buf_pool, for use in ibbackup --restore. */
void
buf_page_init_for_backup_restore(
/*=============================*/
ulint space, /* in: space id */
ulint offset, /* in: offset of the page within space
in units of a page */
buf_block_t* block); /* in: block to init */
/************************************************************************
Decrements the bufferfix count of a buffer control block and releases Decrements the bufferfix count of a buffer control block and releases
a latch, if specified. */ a latch, if specified. */
UNIV_INLINE UNIV_INLINE
@ -438,7 +448,7 @@ Prints info of the buffer pool data structure. */
void void
buf_print(void); buf_print(void);
/*===========*/ /*============*/
/************************************************************************* /*************************************************************************
Returns the number of pending buf pool ios. */ Returns the number of pending buf pool ios. */
@ -449,8 +459,10 @@ buf_get_n_pending_ios(void);
Prints info of the buffer i/o. */ Prints info of the buffer i/o. */
void void
buf_print_io(void); buf_print_io(
/*==============*/ /*=========*/
char* buf, /* in/out: buffer where to print */
char* buf_end);/* in: buffer end */
/************************************************************************* /*************************************************************************
Checks that all file pages in the buffer are in a replaceable state. */ Checks that all file pages in the buffer are in a replaceable state. */
@ -605,6 +617,7 @@ struct buf_block_struct{
/* 1. General fields */ /* 1. General fields */
ulint magic_n; /* magic number to check */
ulint state; /* state of the control block: ulint state; /* state of the control block:
BUF_BLOCK_NOT_USED, ... */ BUF_BLOCK_NOT_USED, ... */
byte* frame; /* pointer to buffer frame which byte* frame; /* pointer to buffer frame which
@ -729,6 +742,8 @@ struct buf_block_struct{
frees a page in buffer pool */ frees a page in buffer pool */
}; };
#define BUF_BLOCK_MAGIC_N 41526563
/* The buffer pool structure. NOTE! The definition appears here only for /* The buffer pool structure. NOTE! The definition appears here only for
other modules of this directory (buf) to see it. Do not use from outside! */ other modules of this directory (buf) to see it. Do not use from outside! */

View File

@ -209,7 +209,7 @@ buf_block_align(
ut_ad((ulint)ptr >= (ulint)frame_zero); ut_ad((ulint)ptr >= (ulint)frame_zero);
block = buf_pool_get_nth_block(buf_pool, (ptr - frame_zero) block = buf_pool_get_nth_block(buf_pool, ((ulint)(ptr - frame_zero))
>> UNIV_PAGE_SIZE_SHIFT); >> UNIV_PAGE_SIZE_SHIFT);
ut_a(block >= buf_pool->blocks); ut_a(block >= buf_pool->blocks);
ut_a(block < buf_pool->blocks + buf_pool->max_size); ut_a(block < buf_pool->blocks + buf_pool->max_size);
@ -236,7 +236,7 @@ buf_block_align_low(
ut_ad((ulint)ptr >= (ulint)frame_zero); ut_ad((ulint)ptr >= (ulint)frame_zero);
block = buf_pool_get_nth_block(buf_pool, (ptr - frame_zero) block = buf_pool_get_nth_block(buf_pool, ((ulint)(ptr - frame_zero))
>> UNIV_PAGE_SIZE_SHIFT); >> UNIV_PAGE_SIZE_SHIFT);
ut_a(block >= buf_pool->blocks); ut_a(block >= buf_pool->blocks);
ut_a(block < buf_pool->blocks + buf_pool->max_size); ut_a(block < buf_pool->blocks + buf_pool->max_size);

View File

@ -89,7 +89,7 @@ buf_read_recv_pages(
/* The size in pages of the area which the read-ahead algorithms read if /* The size in pages of the area which the read-ahead algorithms read if
invoked */ invoked */
#define BUF_READ_AHEAD_AREA ut_min(32, buf_pool->curr_size / 16) #define BUF_READ_AHEAD_AREA ut_min(64, ut_2_power_up(buf_pool->curr_size / 32))
/* Modes used in read-ahead */ /* Modes used in read-ahead */
#define BUF_READ_IBUF_PAGES_ONLY 131 #define BUF_READ_IBUF_PAGES_ONLY 131

View File

@ -123,7 +123,7 @@ dfield_datas_are_binary_equal(
dfield_t* field2);/* in: field */ dfield_t* field2);/* in: field */
/************************************************************************* /*************************************************************************
Tests if dfield data length and content is equal to the given. */ Tests if dfield data length and content is equal to the given. */
UNIV_INLINE
ibool ibool
dfield_data_is_binary_equal( dfield_data_is_binary_equal(
/*========================*/ /*========================*/
@ -279,6 +279,14 @@ dtuple_check_typed(
/* out: TRUE if ok */ /* out: TRUE if ok */
dtuple_t* tuple); /* in: tuple */ dtuple_t* tuple); /* in: tuple */
/************************************************************** /**************************************************************
Checks that a data tuple is typed. */
ibool
dtuple_check_typed_no_assert(
/*=========================*/
/* out: TRUE if ok */
dtuple_t* tuple); /* in: tuple */
/**************************************************************
Validates the consistency of a tuple which must be complete, i.e, Validates the consistency of a tuple which must be complete, i.e,
all fields must have been set. */ all fields must have been set. */

View File

@ -153,30 +153,6 @@ dfield_datas_are_binary_equal(
return(TRUE); return(TRUE);
} }
/*************************************************************************
Tests if dfield data length and content is equal to the given. */
UNIV_INLINE
ibool
dfield_data_is_binary_equal(
/*========================*/
/* out: TRUE if equal */
dfield_t* field, /* in: field */
ulint len, /* in: data length or UNIV_SQL_NULL */
byte* data) /* in: data */
{
if (len != field->len) {
return(FALSE);
}
if (len != UNIV_SQL_NULL && 0 != ut_memcmp(field->data, data, len)) {
return(FALSE);
}
return(TRUE);
}
/************************************************************************* /*************************************************************************
Gets info bits in a data tuple. */ Gets info bits in a data tuple. */
UNIV_INLINE UNIV_INLINE

View File

@ -127,6 +127,8 @@ Prints info of a hash table. */
void void
ha_print_info( ha_print_info(
/*==========*/ /*==========*/
char* buf, /* in/out: buffer where to print */
char* buf_end,/* in: buffer end */
hash_table_t* table); /* in: hash table */ hash_table_t* table); /* in: hash table */

View File

@ -269,8 +269,10 @@ ibuf_count_get(
Prints info of ibuf. */ Prints info of ibuf. */
void void
ibuf_print(void); ibuf_print(
/*============*/ /*=======*/
char* buf, /* in/out: buffer where to print */
char* buf_end);/* in: buffer end */
#define IBUF_HEADER_PAGE_NO FSP_IBUF_HEADER_PAGE_NO #define IBUF_HEADER_PAGE_NO FSP_IBUF_HEADER_PAGE_NO
#define IBUF_TREE_ROOT_PAGE_NO FSP_IBUF_TREE_ROOT_PAGE_NO #define IBUF_TREE_ROOT_PAGE_NO FSP_IBUF_TREE_ROOT_PAGE_NO

View File

@ -460,6 +460,8 @@ Prints info of a table lock. */
void void
lock_table_print( lock_table_print(
/*=============*/ /*=============*/
char* buf, /* in/out: buffer where to print, must be at least
500 bytes */
lock_t* lock); /* in: table type lock */ lock_t* lock); /* in: table type lock */
/************************************************************************* /*************************************************************************
Prints info of a record lock. */ Prints info of a record lock. */
@ -467,13 +469,17 @@ Prints info of a record lock. */
void void
lock_rec_print( lock_rec_print(
/*===========*/ /*===========*/
char* buf, /* in/out: buffer where to print, must be at least
500 bytes */
lock_t* lock); /* in: record type lock */ lock_t* lock); /* in: record type lock */
/************************************************************************* /*************************************************************************
Prints info of locks for all transactions. */ Prints info of locks for all transactions. */
void void
lock_print_info(void); lock_print_info(
/*=================*/ /*============*/
char* buf, /* in/out: buffer where to print */
char* buf_end);/* in: buffer end */
/************************************************************************* /*************************************************************************
Validates the lock queue on a table. */ Validates the lock queue on a table. */

View File

@ -157,6 +157,14 @@ log_io_complete(
/*============*/ /*============*/
log_group_t* group); /* in: log group */ log_group_t* group); /* in: log group */
/********************************************************** /**********************************************************
Flushes the log files to the disk, using, for example, the Unix fsync.
This function does the flush even if the user has set
srv_flush_log_at_trx_commit = FALSE. */
void
log_flush_to_disk(void);
/*===================*/
/**********************************************************
This function is called, e.g., when a transaction wants to commit. It checks This function is called, e.g., when a transaction wants to commit. It checks
that the log has been flushed to disk up to the last log entry written by the that the log has been flushed to disk up to the last log entry written by the
transaction. If there is a flush running, it waits and checks if the flush transaction. If there is a flush running, it waits and checks if the flush
@ -260,7 +268,9 @@ log_reset_first_header_and_checkpoint(
/*==================================*/ /*==================================*/
byte* hdr_buf,/* in: buffer which will be written to the start byte* hdr_buf,/* in: buffer which will be written to the start
of the first log file */ of the first log file */
dulint lsn); /* in: lsn of the start of the first log file */ dulint start); /* in: lsn of the start of the first log file;
we pretend that there is a checkpoint at
start + LOG_BLOCK_HDR_SIZE */
/************************************************************************ /************************************************************************
Starts an archiving operation. */ Starts an archiving operation. */
@ -463,6 +473,15 @@ log_block_init(
byte* log_block, /* in: pointer to the log buffer */ byte* log_block, /* in: pointer to the log buffer */
dulint lsn); /* in: lsn within the log block */ dulint lsn); /* in: lsn within the log block */
/**************************************************************** /****************************************************************
Initializes a log block in the log buffer in the old, < 3.23.52 format, where
there was no checksum yet. */
UNIV_INLINE
void
log_block_init_in_old_format(
/*=========================*/
byte* log_block, /* in: pointer to the log buffer */
dulint lsn); /* in: lsn within the log block */
/****************************************************************
Converts a lsn to a log block number. */ Converts a lsn to a log block number. */
UNIV_INLINE UNIV_INLINE
ulint ulint
@ -474,8 +493,10 @@ log_block_convert_lsn_to_no(
Prints info of the log. */ Prints info of the log. */
void void
log_print(void); log_print(
/*===========*/ /*======*/
char* buf, /* in/out: buffer where to print */
char* buf_end);/* in: buffer end */
extern log_t* log_sys; extern log_t* log_sys;
@ -523,7 +544,10 @@ extern log_t* log_sys;
bytes */ bytes */
/* Offsets of a log block trailer from the end of the block */ /* Offsets of a log block trailer from the end of the block */
#define LOG_BLOCK_TRL_NO 4 /* log block number */ #define LOG_BLOCK_TRL_CHECKSUM 4 /* 1 byte checksum of the log block
contents */
#define LOG_BLOCK_TRL_NO 3 /* 3 lowest bytes of the log block
number */
#define LOG_BLOCK_TRL_SIZE 4 /* trailer size in bytes */ #define LOG_BLOCK_TRL_SIZE 4 /* trailer size in bytes */
/* Offsets for a checkpoint field */ /* Offsets for a checkpoint field */
@ -558,11 +582,22 @@ extern log_t* log_sys;
#define LOG_GROUP_ID 0 /* log group number */ #define LOG_GROUP_ID 0 /* log group number */
#define LOG_FILE_START_LSN 4 /* lsn of the start of data in this #define LOG_FILE_START_LSN 4 /* lsn of the start of data in this
log file */ log file */
#define LOG_FILE_NO 12 /* 4-byte archived log file number */ #define LOG_FILE_NO 12 /* 4-byte archived log file number;
this field is only defined in an
archived log file */
#define LOG_FILE_WAS_CREATED_BY_HOT_BACKUP 16
/* a 32-byte field which contains
the string 'ibbackup' and the
creation time if the log file was
created by ibbackup --restore;
when mysqld is first time started
on the restored database, it can
print helpful info for the user */
#define LOG_FILE_ARCH_COMPLETED OS_FILE_LOG_BLOCK_SIZE #define LOG_FILE_ARCH_COMPLETED OS_FILE_LOG_BLOCK_SIZE
/* this 4-byte field is TRUE when /* this 4-byte field is TRUE when
the writing of an archived log file the writing of an archived log file
has been completed */ has been completed; this field is
only defined in an archived log file */
#define LOG_FILE_END_LSN (OS_FILE_LOG_BLOCK_SIZE + 4) #define LOG_FILE_END_LSN (OS_FILE_LOG_BLOCK_SIZE + 4)
/* lsn where the archived log file /* lsn where the archived log file
at least extends: actually the at least extends: actually the
@ -572,7 +607,14 @@ extern log_t* log_sys;
is defined only when an archived log is defined only when an archived log
file has been completely written */ file has been completely written */
#define LOG_CHECKPOINT_1 OS_FILE_LOG_BLOCK_SIZE #define LOG_CHECKPOINT_1 OS_FILE_LOG_BLOCK_SIZE
/* first checkpoint field in the log
header; we write alternately to the
checkpoint fields when we make new
checkpoints; this field is only defined
in the first log file of a log group */
#define LOG_CHECKPOINT_2 (3 * OS_FILE_LOG_BLOCK_SIZE) #define LOG_CHECKPOINT_2 (3 * OS_FILE_LOG_BLOCK_SIZE)
/* second checkpoint field in the log
header */
#define LOG_FILE_HDR_SIZE (4 * OS_FILE_LOG_BLOCK_SIZE) #define LOG_FILE_HDR_SIZE (4 * OS_FILE_LOG_BLOCK_SIZE)
#define LOG_GROUP_OK 301 #define LOG_GROUP_OK 301
@ -678,7 +720,7 @@ struct log_struct{
write i/o has been completed for all write i/o has been completed for all
log groups */ log groups */
dulint flush_lsn; /* end lsn for the current flush */ dulint flush_lsn; /* end lsn for the current flush */
ulint flush_end_offset;/* the data in buffer ha been flushed ulint flush_end_offset;/* the data in buffer has been flushed
up to this offset when the current up to this offset when the current
flush ends: this field will then flush ends: this field will then
be copied to buf_next_to_write */ be copied to buf_next_to_write */

View File

@ -179,7 +179,7 @@ log_block_get_trl_no(
trailer */ trailer */
byte* log_block) /* in: log block */ byte* log_block) /* in: log block */
{ {
return(mach_read_from_4(log_block + OS_FILE_LOG_BLOCK_SIZE return(mach_read_from_3(log_block + OS_FILE_LOG_BLOCK_SIZE
- LOG_BLOCK_TRL_NO)); - LOG_BLOCK_TRL_NO));
} }
@ -192,8 +192,8 @@ log_block_set_trl_no(
byte* log_block, /* in: log block */ byte* log_block, /* in: log block */
ulint n) /* in: log block number */ ulint n) /* in: log block number */
{ {
mach_write_to_4(log_block + OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_NO, mach_write_to_3(log_block + OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_NO,
n); n & 0xFFFFFF);
} }
/**************************************************************** /****************************************************************
@ -237,6 +237,29 @@ log_block_init(
log_block_set_data_len(log_block, LOG_BLOCK_HDR_SIZE); log_block_set_data_len(log_block, LOG_BLOCK_HDR_SIZE);
log_block_set_first_rec_group(log_block, 0); log_block_set_first_rec_group(log_block, 0);
} }
/****************************************************************
Initializes a log block in the log buffer in the old format, where there
was no checksum yet. */
UNIV_INLINE
void
log_block_init_in_old_format(
/*=========================*/
byte* log_block, /* in: pointer to the log buffer */
dulint lsn) /* in: lsn within the log block */
{
ulint no;
ut_ad(mutex_own(&(log_sys->mutex)));
no = log_block_convert_lsn_to_no(lsn);
log_block_set_hdr_no(log_block, no);
mach_write_to_4(log_block + OS_FILE_LOG_BLOCK_SIZE
- LOG_BLOCK_TRL_NO - 1, no);
log_block_set_data_len(log_block, LOG_BLOCK_HDR_SIZE);
log_block_set_first_rec_group(log_block, 0);
}
/**************************************************************** /****************************************************************
Writes to the log the string given. The log must be released with Writes to the log the string given. The log must be released with

View File

@ -16,6 +16,7 @@ Created 10/21/1995 Heikki Tuuri
os_file_write */ os_file_write */
extern ibool os_do_not_call_flush_at_each_write; extern ibool os_do_not_call_flush_at_each_write;
extern ibool os_has_said_disk_full; extern ibool os_has_said_disk_full;
extern ibool os_aio_print_debug;
#ifdef __WIN__ #ifdef __WIN__
@ -33,6 +34,8 @@ extern ibool os_has_said_disk_full;
typedef int os_file_t; typedef int os_file_t;
#endif #endif
extern ulint os_innodb_umask;
/* If this flag is TRUE, then we will use the native aio of the /* If this flag is TRUE, then we will use the native aio of the
OS (provided we compiled Innobase with it in), otherwise we will OS (provided we compiled Innobase with it in), otherwise we will
use simulated aio we build below with threads */ use simulated aio we build below with threads */
@ -309,6 +312,15 @@ Wakes up simulated aio i/o-handler threads if they have something to do. */
void void
os_aio_simulated_wake_handler_threads(void); os_aio_simulated_wake_handler_threads(void);
/*=======================================*/ /*=======================================*/
/**************************************************************************
This function can be called if one wants to post a batch of reads and
prefers an i/o-handler thread to handle them all at once later. You must
call os_aio_simulated_wake_handler_threads later to ensure the threads
are not left sleeping! */
void
os_aio_simulated_put_read_threads_to_sleep(void);
/*============================================*/
#ifdef WIN_ASYNC_IO #ifdef WIN_ASYNC_IO
/************************************************************************** /**************************************************************************
@ -391,8 +403,10 @@ os_aio_validate(void);
Prints info of the aio arrays. */ Prints info of the aio arrays. */
void void
os_aio_print(void); os_aio_print(
/*==============*/ /*=========*/
char* buf, /* in/out: buffer where to print */
char* buf_end);/* in: buffer end */
/************************************************************************** /**************************************************************************
Checks that all slots in the system have been freed, that is, there are Checks that all slots in the system have been freed, that is, there are
no pending io operations. */ no pending io operations. */

View File

@ -12,8 +12,10 @@ Created 9/8/1995 Heikki Tuuri
#include "univ.i" #include "univ.i"
/* Maximum number of threads which can be created in the program */ /* Maximum number of threads which can be created in the program;
#define OS_THREAD_MAX_N 1000 this is also the size of the wait slot array for MySQL threads which
can wait inside InnoDB */
#define OS_THREAD_MAX_N 10000
/* Possible fixed priorities for threads */ /* Possible fixed priorities for threads */
#define OS_THREAD_PRIORITY_NONE 100 #define OS_THREAD_PRIORITY_NONE 100

View File

@ -328,7 +328,7 @@ page_dir_calc_reserved_space(
ulint n_recs); /* in: number of records */ ulint n_recs); /* in: number of records */
/******************************************************************* /*******************************************************************
Looks for the directory slot which owns the given record. */ Looks for the directory slot which owns the given record. */
UNIV_INLINE
ulint ulint
page_dir_find_owner_slot( page_dir_find_owner_slot(
/*=====================*/ /*=====================*/

View File

@ -479,6 +479,8 @@ page_rec_get_next(
offs = rec_get_next_offs(rec); offs = rec_get_next_offs(rec);
ut_a(offs < UNIV_PAGE_SIZE);
if (offs == 0) { if (offs == 0) {
return(NULL); return(NULL);
@ -487,40 +489,6 @@ page_rec_get_next(
return(page + offs); return(page + offs);
} }
/*******************************************************************
Looks for the directory slot which owns the given record. */
UNIV_INLINE
ulint
page_dir_find_owner_slot(
/*=====================*/
/* out: the directory slot number */
rec_t* rec) /* in: the physical record */
{
ulint i;
page_t* page;
page_dir_slot_t* slot;
ut_ad(page_rec_check(rec));
while (rec_get_n_owned(rec) == 0) {
rec = page_rec_get_next(rec);
}
page = buf_frame_align(rec);
i = page_dir_get_n_slots(page) - 1;
slot = page_dir_get_nth_slot(page, i);
while (page_dir_slot_get_rec(slot) != rec) {
ut_a(i > 0);
i--;
slot = page_dir_get_nth_slot(page, i);
}
return(i);
}
/**************************************************************** /****************************************************************
Sets the pointer to the next record on the page. */ Sets the pointer to the next record on the page. */
UNIV_INLINE UNIV_INLINE
@ -534,7 +502,7 @@ page_rec_set_next(
page_t* page; page_t* page;
ut_ad(page_rec_check(rec)); ut_ad(page_rec_check(rec));
ut_ad((next == NULL) ut_a((next == NULL)
|| (buf_frame_align(rec) == buf_frame_align(next))); || (buf_frame_align(rec) == buf_frame_align(next)));
page = buf_frame_align(rec); page = buf_frame_align(rec);
@ -573,7 +541,7 @@ page_rec_get_prev(
slot_no = page_dir_find_owner_slot(rec); slot_no = page_dir_find_owner_slot(rec);
ut_ad(slot_no != 0); ut_a(slot_no != 0);
slot = page_dir_get_nth_slot(page, slot_no - 1); slot = page_dir_get_nth_slot(page, slot_no - 1);
@ -584,7 +552,7 @@ page_rec_get_prev(
rec2 = page_rec_get_next(rec2); rec2 = page_rec_get_next(rec2);
} }
ut_ad(prev_rec); ut_a(prev_rec);
return(prev_rec); return(prev_rec);
} }

View File

@ -970,8 +970,6 @@ rec_fold(
ut_ad(n_fields <= rec_get_n_fields(rec)); ut_ad(n_fields <= rec_get_n_fields(rec));
ut_ad((n_fields < rec_get_n_fields(rec)) || (n_bytes == 0)); ut_ad((n_fields < rec_get_n_fields(rec)) || (n_bytes == 0));
ut_ad(n_fields + n_bytes > 0); ut_ad(n_fields + n_bytes > 0);
/* Only the page supremum and infimum records have 1 field: */
ut_ad(rec_get_n_fields(rec) > 1);
n_fields_rec = rec_get_n_fields(rec); n_fields_rec = rec_get_n_fields(rec);

View File

@ -230,6 +230,19 @@ row_update_cascade_for_mysql(
or set null operation */ or set null operation */
dict_table_t* table); /* in: table where we do the operation */ dict_table_t* table); /* in: table where we do the operation */
/************************************************************************* /*************************************************************************
Locks the data dictionary exclusively for performing a table create
operation. */
void
row_mysql_lock_data_dictionary(void);
/*================================*/
/*************************************************************************
Unlocks the data dictionary exclusively lock. */
void
row_mysql_unlock_data_dictionary(void);
/*==================================*/
/*************************************************************************
Does a table creation operation for MySQL. If the name of the created Does a table creation operation for MySQL. If the name of the created
table ends to characters INNODB_MONITOR, then this also starts table ends to characters INNODB_MONITOR, then this also starts
printing of monitor output by the master thread. */ printing of monitor output by the master thread. */

View File

@ -357,6 +357,14 @@ srv_error_monitor_thread(
/* out: a dummy parameter */ /* out: a dummy parameter */
void* arg); /* in: a dummy parameter required by void* arg); /* in: a dummy parameter required by
os_thread_create */ os_thread_create */
/**********************************************************************
Sprintfs to a buffer the output of the InnoDB Monitor. */
void
srv_sprintf_innodb_monitor(
/*=======================*/
char* buf, /* in/out: buffer which must be at least 4 kB */
ulint len); /* in: length of the buffer */
/* Types for the threads existing in the system. Threads of types 4 - 9 /* Types for the threads existing in the system. Threads of types 4 - 9

View File

@ -114,6 +114,8 @@ Prints info of the wait array. */
void void
sync_array_print_info( sync_array_print_info(
/*==================*/ /*==================*/
char* buf, /* in/out: buffer where to print */
char* buf_end,/* in: buffer end */
sync_array_t* arr); /* in: wait array */ sync_array_t* arr); /* in: wait array */

View File

@ -117,14 +117,18 @@ FUNCTION PROTOTYPES FOR DEBUGGING */
Prints wait info of the sync system. */ Prints wait info of the sync system. */
void void
sync_print_wait_info(void); sync_print_wait_info(
/*======================*/ /*=================*/
char* buf, /* in/out: buffer where to print */
char* buf_end); /* in: buffer end */
/*********************************************************************** /***********************************************************************
Prints info of the sync system. */ Prints info of the sync system. */
void void
sync_print(void); sync_print(
/*============*/ /*=======*/
char* buf, /* in/out: buffer where to print */
char* buf_end); /* in: buffer end */
/********************************************************************** /**********************************************************************
Checks that the mutex has been initialized. */ Checks that the mutex has been initialized. */

View File

@ -102,11 +102,13 @@ trx_rollback(
calling function can start running calling function can start running
a new query thread */ a new query thread */
/*********************************************************************** /***********************************************************************
Rollback uncommitted transactions which have no user session. */ Rollback or clean up transactions which have no user session. If the
transaction already was committed, then we clean up a possible insert
undo log. If the transaction was not yet committed, then we roll it back. */
void void
trx_rollback_all_without_sess(void); trx_rollback_or_clean_all_without_sess(void);
/*===============================*/ /*========================================*/
/******************************************************************** /********************************************************************
Finishes a transaction rollback. */ Finishes a transaction rollback. */

View File

@ -24,6 +24,14 @@ Created 3/26/1996 Heikki Tuuri
#include "fsp0fsp.h" #include "fsp0fsp.h"
#include "read0types.h" #include "read0types.h"
/* In a MySQL replication slave, in crash recovery we store the master log
file name and position here. We have successfully got the updates to InnoDB
up to this position. If .._pos is -1, it means no crash recovery was needed,
or there was no master log position info inside InnoDB. */
extern char trx_sys_mysql_master_log_name[];
extern ib_longlong trx_sys_mysql_master_log_pos;
/* The transaction system */ /* The transaction system */
extern trx_sys_t* trx_sys; extern trx_sys_t* trx_sys;
@ -229,13 +237,18 @@ trx_in_trx_list(
trx_t* in_trx);/* in: trx */ trx_t* in_trx);/* in: trx */
/********************************************************************* /*********************************************************************
Updates the offset information about the end of the MySQL binlog entry Updates the offset information about the end of the MySQL binlog entry
which corresponds to the transaction just being committed. */ which corresponds to the transaction just being committed. In a MySQL
replication slave updates the latest master binlog position up to which
replication has proceeded. */
void void
trx_sys_update_mysql_binlog_offset( trx_sys_update_mysql_binlog_offset(
/*===============================*/ /*===============================*/
trx_t* trx, /* in: transaction being committed */ char* file_name,/* in: MySQL log file name */
mtr_t* mtr); /* in: mtr */ ib_longlong offset, /* in: position in that log file */
ulint field, /* in: offset of the MySQL log info field in
the trx sys header */
mtr_t* mtr); /* in: mtr */
/********************************************************************* /*********************************************************************
Prints to stderr the MySQL binlog offset info in the trx system header if Prints to stderr the MySQL binlog offset info in the trx system header if
the magic number shows it valid. */ the magic number shows it valid. */
@ -243,15 +256,17 @@ the magic number shows it valid. */
void void
trx_sys_print_mysql_binlog_offset(void); trx_sys_print_mysql_binlog_offset(void);
/*===================================*/ /*===================================*/
/*********************************************************************
Prints to stderr the MySQL master log offset info in the trx system header if
the magic number shows it valid. */
void
trx_sys_print_mysql_master_log_pos(void);
/*====================================*/
/* The automatically created system rollback segment has this id */ /* The automatically created system rollback segment has this id */
#define TRX_SYS_SYSTEM_RSEG_ID 0 #define TRX_SYS_SYSTEM_RSEG_ID 0
/* Max number of rollback segments: the number of segment specification slots
in the transaction system array; rollback segment id must fit in one byte,
therefore 256 */
#define TRX_SYS_N_RSEGS 256
/* Space id and page no where the trx system file copy resides */ /* Space id and page no where the trx system file copy resides */
#define TRX_SYS_SPACE 0 /* the SYSTEM tablespace */ #define TRX_SYS_SPACE 0 /* the SYSTEM tablespace */
#define TRX_SYS_PAGE_NO FSP_TRX_SYS_PAGE_NO #define TRX_SYS_PAGE_NO FSP_TRX_SYS_PAGE_NO
@ -277,22 +292,29 @@ therefore 256 */
segment specification slots */ segment specification slots */
/*-------------------------------------------------------------*/ /*-------------------------------------------------------------*/
#define TRX_SYS_MYSQL_LOG_NAME_LEN 32 /* Max number of rollback segments: the number of segment specification slots
in the transaction system array; rollback segment id must fit in one byte,
therefore 256; each slot is currently 8 bytes in size */
#define TRX_SYS_N_RSEGS 256
#define TRX_SYS_MYSQL_LOG_NAME_LEN 512
#define TRX_SYS_MYSQL_LOG_MAGIC_N 873422344 #define TRX_SYS_MYSQL_LOG_MAGIC_N 873422344
/* The offset of the MySQL replication info on the trx system header page;
this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */
#define TRX_SYS_MYSQL_MASTER_LOG_INFO (UNIV_PAGE_SIZE - 2000)
/* The offset of the MySQL binlog offset info on the trx system header page */ /* The offset of the MySQL binlog offset info on the trx system header page */
#define TRX_SYS_MYSQL_LOG_INFO (UNIV_PAGE_SIZE - 300) #define TRX_SYS_MYSQL_LOG_INFO (UNIV_PAGE_SIZE - 1000)
#define TRX_SYS_MYSQL_LOG_MAGIC_N_FLD 0 /* magic number which shows #define TRX_SYS_MYSQL_LOG_MAGIC_N_FLD 0 /* magic number which shows
if we have valid data in the if we have valid data in the
MySQL binlog info; the value MySQL binlog info; the value
is ..._MAGIC_N if yes */ is ..._MAGIC_N if yes */
#define TRX_SYS_MYSQL_LOG_NAME 4 /* MySQL log file name */ #define TRX_SYS_MYSQL_LOG_OFFSET_HIGH 4 /* high 4 bytes of the offset
#define TRX_SYS_MYSQL_LOG_OFFSET_HIGH (4 + TRX_SYS_MYSQL_LOG_NAME_LEN)
/* high 4 bytes of the offset
within that file */ within that file */
#define TRX_SYS_MYSQL_LOG_OFFSET_LOW (8 + TRX_SYS_MYSQL_LOG_NAME_LEN) #define TRX_SYS_MYSQL_LOG_OFFSET_LOW 8 /* low 4 bytes of the offset
/* low 4 bytes of the offset
within that file */ within that file */
#define TRX_SYS_MYSQL_LOG_NAME 12 /* MySQL log file name */
/* The offset of the doublewrite buffer header on the trx system header page */ /* The offset of the doublewrite buffer header on the trx system header page */
#define TRX_SYS_DOUBLEWRITE (UNIV_PAGE_SIZE - 200) #define TRX_SYS_DOUBLEWRITE (UNIV_PAGE_SIZE - 200)

View File

@ -124,6 +124,15 @@ void
trx_commit_off_kernel( trx_commit_off_kernel(
/*==================*/ /*==================*/
trx_t* trx); /* in: transaction */ trx_t* trx); /* in: transaction */
/********************************************************************
Cleans up a transaction at database startup. The cleanup is needed if
the transaction already got to the middle of a commit when the database
crashed, andf we cannot roll it back. */
void
trx_cleanup_at_db_startup(
/*======================*/
trx_t* trx); /* in: transaction */
/************************************************************************** /**************************************************************************
Does the transaction commit for MySQL. */ Does the transaction commit for MySQL. */
@ -252,7 +261,9 @@ own the kernel mutex. */
void void
trx_print( trx_print(
/*======*/ /*======*/
trx_t* trx); /* in: transaction */ char* buf, /* in/out: buffer where to print, must be at least
500 bytes */
trx_t* trx); /* in: transaction */
/* Signal to a transaction */ /* Signal to a transaction */
@ -322,13 +333,24 @@ struct trx_struct{
void* mysql_thd; /* MySQL thread handle corresponding void* mysql_thd; /* MySQL thread handle corresponding
to this trx, or NULL */ to this trx, or NULL */
char* mysql_log_file_name; char* mysql_log_file_name;
/* If MySQL binlog is used, this field /* if MySQL binlog is used, this field
contains a pointer to the latest file contains a pointer to the latest file
name; this is NULL if binlog is not name; this is NULL if binlog is not
used */ used */
ib_longlong mysql_log_offset;/* If MySQL binlog is used, this field ib_longlong mysql_log_offset;/* if MySQL binlog is used, this field
contains the end offset of the binlog contains the end offset of the binlog
entry */ entry */
char* mysql_master_log_file_name;
/* if the database server is a MySQL
replication slave, we have here the
master binlog name up to which
replication has processed; otherwise
this is a pointer to a null character */
ib_longlong mysql_master_log_pos;
/* if the database server is a MySQL
replication slave, this is the
position in the log file up to which
replication has processed */
os_thread_id_t mysql_thread_id;/* id of the MySQL thread associated os_thread_id_t mysql_thread_id;/* id of the MySQL thread associated
with this transaction object */ with this transaction object */
/*------------------------------*/ /*------------------------------*/

View File

@ -9,41 +9,26 @@ Created 1/20/1994 Heikki Tuuri
#ifndef univ_i #ifndef univ_i
#define univ_i #define univ_i
#if (defined(_WIN32) || defined(_WIN64)) && !defined(MYSQL_SERVER) #if (defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)) && !defined(MYSQL_SERVER)
#define __WIN__ #define __WIN__
#include <windows.h> #include <windows.h>
/* When compiling for Itanium IA64, undefine the flag below to prevent use #if !defined(WIN64) && !defined(_WIN64)
of 32-bit assembler */
#ifndef WIN64
#define UNIV_CAN_USE_X86_ASSEMBLER #define UNIV_CAN_USE_X86_ASSEMBLER
#endif #endif
/* If you want to check for errors with compiler level -W4,
comment out the above include of windows.h and let the following defines
be defined:
#define HANDLE void*
#define CRITICAL_SECTION ulint
*/
#ifdef _NT_ #ifdef _NT_
#define __NT__ #define __NT__
#endif #endif
#else #else
/* The Unix version */ /* The defines used with MySQL */
/* Most C compilers other than gcc do not know 'extern inline' */
#if !defined(__GNUC__) && !defined(__WIN__)
#undef UNIV_MUST_NOT_INLINE
#define UNIV_MUST_NOT_INLINE
#endif
/* Include two header files from MySQL to make the Unix flavor used /* Include two header files from MySQL to make the Unix flavor used
in compiling more Posix-compatible. We assume that 'innobase' is a in compiling more Posix-compatible. These headers also define __WIN__
subdirectory of 'mysql'. */ if we are compiling on Windows. */
#include <my_global.h> #include <my_global.h>
#include <my_pthread.h> #include <my_pthread.h>
@ -60,6 +45,20 @@ subdirectory of 'mysql'. */
#include <sched.h> #include <sched.h>
#endif #endif
/* When compiling for Itanium IA64, undefine the flag below to prevent use
of the 32-bit x86 assembler in mutex operations. */
#if defined(__WIN__) && !defined(WIN64) && !defined(_WIN64)
#define UNIV_CAN_USE_X86_ASSEMBLER
#endif
/* We only try to do explicit inlining of functions with gcc and
Microsoft Visual C++ */
#if !defined(__GNUC__) && !defined(__WIN__)
#define UNIV_MUST_NOT_INLINE
#endif
#ifdef HAVE_PREAD #ifdef HAVE_PREAD
#define HAVE_PWRITE #define HAVE_PWRITE
#endif #endif

View File

@ -114,7 +114,7 @@ ut_2_exp(
ulint n); /* in: number */ ulint n); /* in: number */
/***************************************************************** /*****************************************************************
Calculates fast the number rounded up to the nearest power of 2. */ Calculates fast the number rounded up to the nearest power of 2. */
UNIV_INLINE
ulint ulint
ut_2_power_up( ut_2_power_up(
/*==========*/ /*==========*/
@ -155,6 +155,13 @@ ut_print_timestamp(
/*===============*/ /*===============*/
FILE* file); /* in: file where to print */ FILE* file); /* in: file where to print */
/************************************************************** /**************************************************************
Sprintfs a timestamp to a buffer. */
void
ut_sprintf_timestamp(
/*=================*/
char* buf); /* in: buffer where to sprintf */
/**************************************************************
Returns current year, month, day. */ Returns current year, month, day. */
void void

View File

@ -172,25 +172,3 @@ ut_2_exp(
{ {
return(1 << n); return(1 << n);
} }
/*****************************************************************
Calculates fast the number rounded up to the nearest power of 2. */
UNIV_INLINE
ulint
ut_2_power_up(
/*==========*/
/* out: first power of 2 which is >= n */
ulint n) /* in: number != 0 */
{
ulint res;
res = 1;
ut_ad(n > 0);
while (res < n) {
res = res * 2;
}
return(res);
}

View File

@ -1542,6 +1542,15 @@ lock_rec_enqueue_waiting(
trx = thr_get_trx(thr); trx = thr_get_trx(thr);
if (trx->dict_operation) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: a record lock wait happens in a dictionary operation!\n"
"InnoDB: Table name %s. Send a bug report to mysql@lists.mysql.com\n",
index->table_name);
}
/* Enqueue the lock request that will wait to be granted */ /* Enqueue the lock request that will wait to be granted */
lock = lock_rec_create(type_mode | LOCK_WAIT, rec, index, trx); lock = lock_rec_create(type_mode | LOCK_WAIT, rec, index, trx);
@ -2915,7 +2924,7 @@ lock_table_enqueue_waiting(
trx_t* trx; trx_t* trx;
ut_ad(mutex_own(&kernel_mutex)); ut_ad(mutex_own(&kernel_mutex));
/* Test if there already is some other reason to suspend thread: /* Test if there already is some other reason to suspend thread:
we do not enqueue a lock request if the query thread should be we do not enqueue a lock request if the query thread should be
stopped anyway */ stopped anyway */
@ -2927,6 +2936,15 @@ lock_table_enqueue_waiting(
} }
trx = thr_get_trx(thr); trx = thr_get_trx(thr);
if (trx->dict_operation) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: a table lock wait happens in a dictionary operation!\n"
"InnoDB: Table name %s. Send a bug report to mysql@lists.mysql.com\n",
table->name);
}
/* Enqueue the lock request that will wait to be granted */ /* Enqueue the lock request that will wait to be granted */
@ -3309,34 +3327,37 @@ Prints info of a table lock. */
void void
lock_table_print( lock_table_print(
/*=============*/ /*=============*/
char* buf, /* in/out: buffer where to print, must be at least
500 bytes */
lock_t* lock) /* in: table type lock */ lock_t* lock) /* in: table type lock */
{ {
ut_ad(mutex_own(&kernel_mutex)); ut_ad(mutex_own(&kernel_mutex));
ut_a(lock_get_type(lock) == LOCK_TABLE); ut_a(lock_get_type(lock) == LOCK_TABLE);
printf("TABLE LOCK table %s trx id %lu %lu", buf += sprintf(buf, "TABLE LOCK table %s trx id %lu %lu",
lock->un_member.tab_lock.table->name, lock->un_member.tab_lock.table->name,
(lock->trx)->id.high, (lock->trx)->id.low); (lock->trx)->id.high, (lock->trx)->id.low);
if (lock_get_mode(lock) == LOCK_S) { if (lock_get_mode(lock) == LOCK_S) {
printf(" lock mode S"); buf += sprintf(buf, " lock mode S");
} else if (lock_get_mode(lock) == LOCK_X) { } else if (lock_get_mode(lock) == LOCK_X) {
printf(" lock_mode X"); buf += sprintf(buf, " lock_mode X");
} else if (lock_get_mode(lock) == LOCK_IS) { } else if (lock_get_mode(lock) == LOCK_IS) {
printf(" lock_mode IS"); buf += sprintf(buf, " lock_mode IS");
} else if (lock_get_mode(lock) == LOCK_IX) { } else if (lock_get_mode(lock) == LOCK_IX) {
printf(" lock_mode IX"); buf += sprintf(buf, " lock_mode IX");
} else if (lock_get_mode(lock) == LOCK_AUTO_INC) { } else if (lock_get_mode(lock) == LOCK_AUTO_INC) {
printf(" lock_mode AUTO-INC"); buf += sprintf(buf, " lock_mode AUTO-INC");
} else { } else {
printf(" unknown lock_mode %lu", lock_get_mode(lock)); buf += sprintf(buf,
" unknown lock_mode %lu", lock_get_mode(lock));
} }
if (lock_get_wait(lock)) { if (lock_get_wait(lock)) {
printf(" waiting"); buf += sprintf(buf, " waiting");
} }
printf("\n"); buf += sprintf(buf, "\n");
} }
/************************************************************************* /*************************************************************************
@ -3345,6 +3366,8 @@ Prints info of a record lock. */
void void
lock_rec_print( lock_rec_print(
/*===========*/ /*===========*/
char* buf, /* in/out: buffer where to print, must be at least
500 bytes */
lock_t* lock) /* in: record type lock */ lock_t* lock) /* in: record type lock */
{ {
page_t* page; page_t* page;
@ -3352,8 +3375,7 @@ lock_rec_print(
ulint page_no; ulint page_no;
ulint i; ulint i;
ulint count = 0; ulint count = 0;
ulint len; char* buf_start = buf;
char buf[200];
mtr_t mtr; mtr_t mtr;
ut_ad(mutex_own(&kernel_mutex)); ut_ad(mutex_own(&kernel_mutex));
@ -3362,32 +3384,32 @@ lock_rec_print(
space = lock->un_member.rec_lock.space; space = lock->un_member.rec_lock.space;
page_no = lock->un_member.rec_lock.page_no; page_no = lock->un_member.rec_lock.page_no;
printf("RECORD LOCKS space id %lu page no %lu n bits %lu", buf += sprintf(buf, "RECORD LOCKS space id %lu page no %lu n bits %lu",
space, page_no, lock_rec_get_n_bits(lock)); space, page_no, lock_rec_get_n_bits(lock));
printf(" table %s index %s trx id %lu %lu", buf += sprintf(buf, " table %s index %s trx id %lu %lu",
lock->index->table->name, lock->index->name, lock->index->table->name, lock->index->name,
(lock->trx)->id.high, (lock->trx)->id.low); (lock->trx)->id.high, (lock->trx)->id.low);
if (lock_get_mode(lock) == LOCK_S) { if (lock_get_mode(lock) == LOCK_S) {
printf(" lock mode S"); buf += sprintf(buf, " lock mode S");
} else if (lock_get_mode(lock) == LOCK_X) { } else if (lock_get_mode(lock) == LOCK_X) {
printf(" lock_mode X"); buf += sprintf(buf, " lock_mode X");
} else { } else {
ut_error; ut_error;
} }
if (lock_rec_get_gap(lock)) { if (lock_rec_get_gap(lock)) {
printf(" gap type lock"); buf += sprintf(buf, " gap type lock");
} }
if (lock_get_wait(lock)) { if (lock_get_wait(lock)) {
printf(" waiting"); buf += sprintf(buf, " waiting");
} }
mtr_start(&mtr); mtr_start(&mtr);
printf("\n"); buf += sprintf(buf, "\n");
/* If the page is not in the buffer pool, we cannot load it /* If the page is not in the buffer pool, we cannot load it
because we have the kernel mutex and ibuf operations would because we have the kernel mutex and ibuf operations would
@ -3406,28 +3428,28 @@ lock_rec_print(
for (i = 0; i < lock_rec_get_n_bits(lock); i++) { for (i = 0; i < lock_rec_get_n_bits(lock); i++) {
if (buf - buf_start > 300) {
buf += sprintf(buf,
"Suppressing further record lock prints for this page\n");
return;
}
if (lock_rec_get_nth_bit(lock, i)) { if (lock_rec_get_nth_bit(lock, i)) {
printf("Record lock, heap no %lu ", i); buf += sprintf(buf, "Record lock, heap no %lu ", i);
if (page) { if (page) {
len = rec_sprintf(buf, 190, buf += rec_sprintf(buf, 120,
page_find_rec_with_heap_no(page, i)); page_find_rec_with_heap_no(page, i));
buf[len] = '\0'; *buf = '\0';
printf("%s", buf);
} }
printf("\n"); buf += sprintf(buf, "\n");
count++; count++;
} }
if (count >= 3) {
printf(
"3 LOCKS PRINTED FOR THIS TRX AND PAGE: SUPPRESSING FURTHER PRINTS\n");
goto end_prints;
}
} }
end_prints:
mtr_commit(&mtr); mtr_commit(&mtr);
} }
@ -3462,8 +3484,10 @@ lock_get_n_rec_locks(void)
Prints info of locks for all transactions. */ Prints info of locks for all transactions. */
void void
lock_print_info(void) lock_print_info(
/*=================*/ /*============*/
char* buf, /* in/out: buffer where to print */
char* buf_end)/* in: buffer end */
{ {
lock_t* lock; lock_t* lock;
trx_t* trx; trx_t* trx;
@ -3476,11 +3500,15 @@ lock_print_info(void)
ulint i; ulint i;
mtr_t mtr; mtr_t mtr;
printf("Trx id counter %lu %lu\n", if (buf_end - buf < 600) {
return;
}
buf += sprintf(buf, "Trx id counter %lu %lu\n",
ut_dulint_get_high(trx_sys->max_trx_id), ut_dulint_get_high(trx_sys->max_trx_id),
ut_dulint_get_low(trx_sys->max_trx_id)); ut_dulint_get_low(trx_sys->max_trx_id));
printf( buf += sprintf(buf,
"Purge done for trx's n:o < %lu %lu undo n:o < %lu %lu\n", "Purge done for trx's n:o < %lu %lu undo n:o < %lu %lu\n",
ut_dulint_get_high(purge_sys->purge_trx_no), ut_dulint_get_high(purge_sys->purge_trx_no),
ut_dulint_get_low(purge_sys->purge_trx_no), ut_dulint_get_low(purge_sys->purge_trx_no),
@ -3489,7 +3517,8 @@ lock_print_info(void)
lock_mutex_enter_kernel(); lock_mutex_enter_kernel();
printf("Total number of lock structs in row lock hash table %lu\n", buf += sprintf(buf,
"Total number of lock structs in row lock hash table %lu\n",
lock_get_n_rec_locks()); lock_get_n_rec_locks());
/* First print info on non-active transactions */ /* First print info on non-active transactions */
@ -3497,9 +3526,15 @@ lock_print_info(void)
trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list); trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list);
while (trx) { while (trx) {
if (buf_end - buf < 600) {
return;
}
if (trx->conc_state == TRX_NOT_STARTED) { if (trx->conc_state == TRX_NOT_STARTED) {
printf("---"); buf += sprintf(buf, "---");
trx_print(trx); trx_print(buf, trx);
buf += strlen(buf);
} }
trx = UT_LIST_GET_NEXT(mysql_trx_list, trx); trx = UT_LIST_GET_NEXT(mysql_trx_list, trx);
@ -3528,12 +3563,22 @@ loop:
return; return;
} }
if (nth_lock == 0) { if (buf_end - buf < 600) {
printf("---"); return;
trx_print(trx); }
if (nth_lock == 0) {
buf += sprintf(buf, "---");
trx_print(buf, trx);
buf += strlen(buf);
if (buf_end - buf < 500) {
return;
}
if (trx->read_view) { if (trx->read_view) {
printf( buf += sprintf(buf,
"Trx read view will not see trx with id >= %lu %lu, sees < %lu %lu\n", "Trx read view will not see trx with id >= %lu %lu, sees < %lu %lu\n",
ut_dulint_get_high(trx->read_view->low_limit_id), ut_dulint_get_high(trx->read_view->low_limit_id),
ut_dulint_get_low(trx->read_view->low_limit_id), ut_dulint_get_low(trx->read_view->low_limit_id),
@ -3542,16 +3587,17 @@ loop:
} }
if (trx->que_state == TRX_QUE_LOCK_WAIT) { if (trx->que_state == TRX_QUE_LOCK_WAIT) {
printf( buf += sprintf(buf,
"------------------TRX IS WAITING FOR THE LOCK:\n"); "------------------TRX IS WAITING FOR THE LOCK:\n");
if (lock_get_type(trx->wait_lock) == LOCK_REC) { if (lock_get_type(trx->wait_lock) == LOCK_REC) {
lock_rec_print(trx->wait_lock); lock_rec_print(buf, trx->wait_lock);
} else { } else {
lock_table_print(trx->wait_lock); lock_table_print(buf, trx->wait_lock);
} }
printf( buf += strlen(buf);
buf += sprintf(buf,
"------------------\n"); "------------------\n");
} }
} }
@ -3580,6 +3626,10 @@ loop:
goto loop; goto loop;
} }
if (buf_end - buf < 500) {
return;
}
if (lock_get_type(lock) == LOCK_REC) { if (lock_get_type(lock) == LOCK_REC) {
space = lock->un_member.rec_lock.space; space = lock->un_member.rec_lock.space;
page_no = lock->un_member.rec_lock.page_no; page_no = lock->un_member.rec_lock.page_no;
@ -3600,19 +3650,21 @@ loop:
goto loop; goto loop;
} }
lock_rec_print(lock); lock_rec_print(buf, lock);
} else { } else {
ut_ad(lock_get_type(lock) == LOCK_TABLE); ut_ad(lock_get_type(lock) == LOCK_TABLE);
lock_table_print(lock); lock_table_print(buf, lock);
} }
buf += strlen(buf);
load_page_first = TRUE; load_page_first = TRUE;
nth_lock++; nth_lock++;
if (nth_lock >= 10) { if (nth_lock >= 10) {
printf( buf += sprintf(buf,
"10 LOCKS PRINTED FOR THIS TRX: SUPPRESSING FURTHER PRINTS\n"); "10 LOCKS PRINTED FOR THIS TRX: SUPPRESSING FURTHER PRINTS\n");
nth_trx++; nth_trx++;

View File

@ -162,6 +162,8 @@ log_reserve_and_open(
ulint archived_lsn_age; ulint archived_lsn_age;
ulint count = 0; ulint count = 0;
ulint dummy; ulint dummy;
ut_a(len < log->buf_size / 2);
loop: loop:
mutex_enter(&(log->mutex)); mutex_enter(&(log->mutex));
@ -663,6 +665,8 @@ log_init(void)
log_sys->buf_next_to_write = 0; log_sys->buf_next_to_write = 0;
log_sys->flush_lsn = ut_dulint_zero;
log_sys->written_to_some_lsn = log_sys->lsn; log_sys->written_to_some_lsn = log_sys->lsn;
log_sys->written_to_all_lsn = log_sys->lsn; log_sys->written_to_all_lsn = log_sys->lsn;
@ -777,9 +781,15 @@ log_group_init(
*(group->file_header_bufs + i) = ut_align( *(group->file_header_bufs + i) = ut_align(
mem_alloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE), mem_alloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE),
OS_FILE_LOG_BLOCK_SIZE); OS_FILE_LOG_BLOCK_SIZE);
memset(*(group->file_header_bufs + i), '\0',
LOG_FILE_HDR_SIZE);
*(group->archive_file_header_bufs + i) = ut_align( *(group->archive_file_header_bufs + i) = ut_align(
mem_alloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE), mem_alloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE),
OS_FILE_LOG_BLOCK_SIZE); OS_FILE_LOG_BLOCK_SIZE);
memset(*(group->archive_file_header_bufs + i), '\0',
LOG_FILE_HDR_SIZE);
} }
group->archive_space_id = archive_space_id; group->archive_space_id = archive_space_id;
@ -791,6 +801,8 @@ log_group_init(
mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE), mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE),
OS_FILE_LOG_BLOCK_SIZE); OS_FILE_LOG_BLOCK_SIZE);
memset(group->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE);
UT_LIST_ADD_LAST(log_groups, log_sys->log_groups, group); UT_LIST_ADD_LAST(log_groups, log_sys->log_groups, group);
ut_a(log_calc_max_ages()); ut_a(log_calc_max_ages());
@ -839,7 +851,7 @@ log_group_check_flush_completion(
{ {
ut_ad(mutex_own(&(log_sys->mutex))); ut_ad(mutex_own(&(log_sys->mutex)));
if (!log_sys->one_flushed && (group->n_pending_writes == 0)) { if (!log_sys->one_flushed && group->n_pending_writes == 0) {
if (log_debug_writes) { if (log_debug_writes) {
printf("Log flushed first to group %lu\n", group->id); printf("Log flushed first to group %lu\n", group->id);
@ -933,16 +945,20 @@ log_io_complete(
return; return;
} }
ut_a(0); /* We currently use synchronous writing of the
logs and cannot end up here! */
if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC
&& srv_unix_file_flush_method != SRV_UNIX_NOSYNC) { && srv_unix_file_flush_method != SRV_UNIX_NOSYNC
&& srv_flush_log_at_trx_commit != 2) {
fil_flush(group->space_id); fil_flush(group->space_id);
} }
mutex_enter(&(log_sys->mutex)); mutex_enter(&(log_sys->mutex));
ut_ad(group->n_pending_writes > 0); ut_a(group->n_pending_writes > 0);
ut_ad(log_sys->n_pending_writes > 0); ut_a(log_sys->n_pending_writes > 0);
group->n_pending_writes--; group->n_pending_writes--;
log_sys->n_pending_writes--; log_sys->n_pending_writes--;
@ -955,6 +971,57 @@ log_io_complete(
mutex_exit(&(log_sys->mutex)); mutex_exit(&(log_sys->mutex));
} }
/**********************************************************
Flushes the log files to the disk, using, for example, the Unix fsync.
This function does the flush even if the user has set
srv_flush_log_at_trx_commit = FALSE. */
void
log_flush_to_disk(void)
/*===================*/
{
log_group_t* group;
loop:
mutex_enter(&(log_sys->mutex));
if (log_sys->n_pending_writes > 0) {
/* A log file write is running */
mutex_exit(&(log_sys->mutex));
/* Wait for the log file write to complete and try again */
os_event_wait(log_sys->no_flush_event);
goto loop;
}
group = UT_LIST_GET_FIRST(log_sys->log_groups);
log_sys->n_pending_writes++;
group->n_pending_writes++;
os_event_reset(log_sys->no_flush_event);
os_event_reset(log_sys->one_flushed_event);
mutex_exit(&(log_sys->mutex));
fil_flush(group->space_id);
mutex_enter(&(log_sys->mutex));
ut_a(group->n_pending_writes == 1);
ut_a(log_sys->n_pending_writes == 1);
group->n_pending_writes--;
log_sys->n_pending_writes--;
os_event_set(log_sys->no_flush_event);
os_event_set(log_sys->one_flushed_event);
mutex_exit(&(log_sys->mutex));
}
/********************************************************** /**********************************************************
Writes a log file header to a log file space. */ Writes a log file header to a log file space. */
static static
@ -970,7 +1037,6 @@ log_group_file_header_flush(
{ {
byte* buf; byte* buf;
ulint dest_offset; ulint dest_offset;
ibool sync;
ut_ad(mutex_own(&(log_sys->mutex))); ut_ad(mutex_own(&(log_sys->mutex)));
@ -981,15 +1047,11 @@ log_group_file_header_flush(
mach_write_to_4(buf + LOG_GROUP_ID, group->id); mach_write_to_4(buf + LOG_GROUP_ID, group->id);
mach_write_to_8(buf + LOG_FILE_START_LSN, start_lsn); mach_write_to_8(buf + LOG_FILE_START_LSN, start_lsn);
/* Wipe over possible label of ibbackup --restore */
memcpy(buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, " ", 4);
dest_offset = nth_file * group->file_size; dest_offset = nth_file * group->file_size;
sync = FALSE;
if (type == LOG_RECOVER) {
sync = TRUE;
}
if (log_debug_writes) { if (log_debug_writes) {
printf( printf(
"Writing log file header to group %lu file %lu\n", group->id, "Writing log file header to group %lu file %lu\n", group->id,
@ -997,14 +1059,9 @@ log_group_file_header_flush(
} }
if (log_do_write) { if (log_do_write) {
if (type == LOG_FLUSH) {
log_sys->n_pending_writes++;
group->n_pending_writes++;
}
log_sys->n_log_ios++; log_sys->n_log_ios++;
fil_io(OS_FILE_WRITE | OS_FILE_LOG, sync, group->space_id, fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->space_id,
dest_offset / UNIV_PAGE_SIZE, dest_offset / UNIV_PAGE_SIZE,
dest_offset % UNIV_PAGE_SIZE, dest_offset % UNIV_PAGE_SIZE,
OS_FILE_LOG_BLOCK_SIZE, OS_FILE_LOG_BLOCK_SIZE,
@ -1012,6 +1069,31 @@ log_group_file_header_flush(
} }
} }
/**********************************************************
Stores a 1-byte checksum to the trailer checksum field of a log block
before writing it to a log file. This checksum is used in recovery to
check the consistency of a log block. The checksum is simply the 8 low
bits of 1 + the sum of the bytes in the log block except the trailer bytes. */
static
void
log_block_store_checksum(
/*=====================*/
byte* block) /* in/out: pointer to a log block */
{
ulint i;
ulint sum;
sum = 1;
for (i = 0; i < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE; i++) {
sum += (ulint)(*(block + i));
}
mach_write_to_1(block + OS_FILE_LOG_BLOCK_SIZE
- LOG_BLOCK_TRL_CHECKSUM,
0xFF & sum);
}
/********************************************************** /**********************************************************
Writes a buffer to a log file group. */ Writes a buffer to a log file group. */
@ -1032,20 +1114,13 @@ log_group_write_buf(
header */ header */
{ {
ulint write_len; ulint write_len;
ibool sync;
ibool write_header; ibool write_header;
ulint next_offset; ulint next_offset;
ulint i;
ut_ad(mutex_own(&(log_sys->mutex))); ut_ad(mutex_own(&(log_sys->mutex)));
ut_ad(len % OS_FILE_LOG_BLOCK_SIZE == 0); ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_ad(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); ut_a(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0);
sync = FALSE;
if (type == LOG_RECOVER) {
sync = TRUE;
}
if (new_data_offset == 0) { if (new_data_offset == 0) {
write_header = TRUE; write_header = TRUE;
@ -1076,7 +1151,6 @@ loop:
} }
if (log_debug_writes) { if (log_debug_writes) {
ulint i;
printf( printf(
"Writing log file segment to group %lu offset %lu len %lu\n" "Writing log file segment to group %lu offset %lu len %lu\n"
@ -1100,15 +1174,17 @@ loop:
} }
} }
if (log_do_write) { /* Calculate the checksums for each log block and write them to
if (type == LOG_FLUSH) { the trailer fields of the log blocks */
log_sys->n_pending_writes++;
group->n_pending_writes++;
}
for (i = 0; i < write_len / OS_FILE_LOG_BLOCK_SIZE; i++) {
log_block_store_checksum(buf + i * OS_FILE_LOG_BLOCK_SIZE);
}
if (log_do_write) {
log_sys->n_log_ios++; log_sys->n_log_ios++;
fil_io(OS_FILE_WRITE | OS_FILE_LOG, sync, group->space_id, fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->space_id,
next_offset / UNIV_PAGE_SIZE, next_offset / UNIV_PAGE_SIZE,
next_offset % UNIV_PAGE_SIZE, write_len, buf, group); next_offset % UNIV_PAGE_SIZE, write_len, buf, group);
} }
@ -1126,15 +1202,15 @@ loop:
/********************************************************** /**********************************************************
This function is called, e.g., when a transaction wants to commit. It checks This function is called, e.g., when a transaction wants to commit. It checks
that the log has been flushed to disk up to the last log entry written by the that the log has been written to the log file up to the last log entry written
transaction. If there is a flush running, it waits and checks if the flush by the transaction. If there is a flush running, it waits and checks if the
flushed enough. If not, starts a new flush. */ flush flushed enough. If not, starts a new flush. */
void void
log_flush_up_to( log_flush_up_to(
/*============*/ /*============*/
dulint lsn, /* in: log sequence number up to which the log should dulint lsn, /* in: log sequence number up to which the log should
be flushed, ut_dulint_max if not specified */ be written, ut_dulint_max if not specified */
ulint wait) /* in: LOG_NO_WAIT, LOG_WAIT_ONE_GROUP, ulint wait) /* in: LOG_NO_WAIT, LOG_WAIT_ONE_GROUP,
or LOG_WAIT_ALL_GROUPS */ or LOG_WAIT_ALL_GROUPS */
{ {
@ -1144,6 +1220,7 @@ log_flush_up_to(
ulint area_start; ulint area_start;
ulint area_end; ulint area_end;
ulint loop_count; ulint loop_count;
ulint unlock;
if (recv_no_ibuf_operations) { if (recv_no_ibuf_operations) {
/* Recovery is running and no operations on the log files are /* Recovery is running and no operations on the log files are
@ -1209,6 +1286,12 @@ loop:
ut_dulint_get_low(log_sys->lsn)); ut_dulint_get_low(log_sys->lsn));
} }
log_sys->n_pending_writes++;
group = UT_LIST_GET_FIRST(log_sys->log_groups);
group->n_pending_writes++; /* We assume here that we have only
one log group! */
os_event_reset(log_sys->no_flush_event); os_event_reset(log_sys->no_flush_event);
os_event_reset(log_sys->one_flushed_event); os_event_reset(log_sys->one_flushed_event);
@ -1254,6 +1337,36 @@ loop:
group = UT_LIST_GET_NEXT(log_groups, group); group = UT_LIST_GET_NEXT(log_groups, group);
} }
mutex_exit(&(log_sys->mutex));
if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC
&& srv_unix_file_flush_method != SRV_UNIX_NOSYNC
&& srv_flush_log_at_trx_commit != 2) {
group = UT_LIST_GET_FIRST(log_sys->log_groups);
fil_flush(group->space_id);
}
mutex_enter(&(log_sys->mutex));
group = UT_LIST_GET_FIRST(log_sys->log_groups);
ut_a(group->n_pending_writes == 1);
ut_a(log_sys->n_pending_writes == 1);
group->n_pending_writes--;
log_sys->n_pending_writes--;
unlock = log_group_check_flush_completion(group);
unlock = unlock | log_sys_check_flush_completion();
log_flush_do_unlocks(unlock);
mutex_exit(&(log_sys->mutex));
return;
do_waits: do_waits:
mutex_exit(&(log_sys->mutex)); mutex_exit(&(log_sys->mutex));
@ -1539,15 +1652,23 @@ log_reset_first_header_and_checkpoint(
/*==================================*/ /*==================================*/
byte* hdr_buf,/* in: buffer which will be written to the start byte* hdr_buf,/* in: buffer which will be written to the start
of the first log file */ of the first log file */
dulint lsn) /* in: lsn of the start of the first log file dulint start) /* in: lsn of the start of the first log file;
+ LOG_BLOCK_HDR_SIZE */ we pretend that there is a checkpoint at
start + LOG_BLOCK_HDR_SIZE */
{ {
ulint fold; ulint fold;
byte* buf; byte* buf;
dulint lsn;
mach_write_to_4(hdr_buf + LOG_GROUP_ID, 0); mach_write_to_4(hdr_buf + LOG_GROUP_ID, 0);
mach_write_to_8(hdr_buf + LOG_FILE_START_LSN, lsn); mach_write_to_8(hdr_buf + LOG_FILE_START_LSN, start);
lsn = ut_dulint_add(start, LOG_BLOCK_HDR_SIZE);
/* Write the label of ibbackup --restore */
sprintf(hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, "ibbackup ");
ut_sprintf_timestamp(hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP
+ strlen("ibbackup "));
buf = hdr_buf + LOG_CHECKPOINT_1; buf = hdr_buf + LOG_CHECKPOINT_1;
mach_write_to_8(buf + LOG_CHECKPOINT_NO, ut_dulint_zero); mach_write_to_8(buf + LOG_CHECKPOINT_NO, ut_dulint_zero);
@ -2965,15 +3086,22 @@ log_check_log_recs(
Prints info of the log. */ Prints info of the log. */
void void
log_print(void) log_print(
/*===========*/ /*======*/
char* buf, /* in/out: buffer where to print */
char* buf_end)/* in: buffer end */
{ {
double time_elapsed; double time_elapsed;
time_t current_time; time_t current_time;
if (buf_end - buf < 300) {
return;
}
mutex_enter(&(log_sys->mutex)); mutex_enter(&(log_sys->mutex));
printf("Log sequence number %lu %lu\n" buf += sprintf(buf, "Log sequence number %lu %lu\n"
"Log flushed up to %lu %lu\n" "Log flushed up to %lu %lu\n"
"Last checkpoint at %lu %lu\n", "Last checkpoint at %lu %lu\n",
ut_dulint_get_high(log_sys->lsn), ut_dulint_get_high(log_sys->lsn),
@ -2987,7 +3115,7 @@ log_print(void)
time_elapsed = difftime(current_time, log_sys->last_printout_time); time_elapsed = difftime(current_time, log_sys->last_printout_time);
printf( buf += sprintf(buf,
"%lu pending log writes, %lu pending chkp writes\n" "%lu pending log writes, %lu pending chkp writes\n"
"%lu log i/o's done, %.2f log i/o's/second\n", "%lu log i/o's done, %.2f log i/o's/second\n",
log_sys->n_pending_writes, log_sys->n_pending_writes,

View File

@ -568,6 +568,55 @@ recv_read_cp_info_for_backup(
return(TRUE); return(TRUE);
} }
/**********************************************************
Checks the 1-byte checksum to the trailer checksum field of a log block.
We also accept a log block in the old format where the checksum field
contained the highest byte of the log block number. */
static
ibool
log_block_checksum_is_ok_or_old_format(
/*===================================*/
/* out: TRUE if ok, or if the log block may be in the
format of InnoDB version < 3.23.52 */
byte* block) /* in: pointer to a log block */
{
ulint i;
ulint sum;
sum = 1;
for (i = 0; i < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE; i++) {
sum += (ulint)(*(block + i));
}
/* printf("Checksum %lu, byte %lu\n", 0xFF & sum,
mach_read_from_1(block + OS_FILE_LOG_BLOCK_SIZE
- LOG_BLOCK_TRL_CHECKSUM));
*/
if (mach_read_from_1(block + OS_FILE_LOG_BLOCK_SIZE
- LOG_BLOCK_TRL_CHECKSUM)
== (0xFF & sum)) {
return(TRUE);
}
if (((0xFF000000 & log_block_get_hdr_no(block)) >> 24)
== mach_read_from_1(block + OS_FILE_LOG_BLOCK_SIZE
- LOG_BLOCK_TRL_CHECKSUM)) {
/* We assume the log block is in the format of
InnoDB version < 3.23.52 and the block is ok */
/*
fprintf(stderr,
"InnoDB: Scanned old format < InnoDB-3.23.52 log block number %lu\n",
log_block_get_hdr_no(block));
*/
return(TRUE);
}
return(FALSE);
}
/*********************************************************************** /***********************************************************************
Scans the log segment and n_bytes_scanned is set to the length of valid Scans the log segment and n_bytes_scanned is set to the length of valid
log scanned. */ log scanned. */
@ -598,12 +647,13 @@ recv_scan_log_seg_for_backup(
no = log_block_get_hdr_no(log_block); no = log_block_get_hdr_no(log_block);
/* fprintf(stderr, "Log block header no %lu\n", no); */ /* fprintf(stderr, "Log block header no %lu\n", no); */
if (no != log_block_get_trl_no(log_block) if ((no & 0xFFFFFF) != log_block_get_trl_no(log_block)
|| no != log_block_convert_lsn_to_no(*scanned_lsn)) { || no != log_block_convert_lsn_to_no(*scanned_lsn)
|| !log_block_checksum_is_ok_or_old_format(log_block)) {
/* printf( /*
printf(
"Log block n:o %lu, trailer n:o %lu, scanned lsn n:o %lu\n", "Log block n:o %lu, trailer n:o %lu, scanned lsn n:o %lu\n",
no, log_block_get_trl_no(log_block), no, log_block_get_trl_no(log_block),
log_block_convert_lsn_to_no(*scanned_lsn)); log_block_convert_lsn_to_no(*scanned_lsn));
@ -611,8 +661,8 @@ recv_scan_log_seg_for_backup(
/* Garbage or an incompletely written log block */ /* Garbage or an incompletely written log block */
log_block += OS_FILE_LOG_BLOCK_SIZE; log_block += OS_FILE_LOG_BLOCK_SIZE;
/*
/* printf( printf(
"Next log block n:o %lu, trailer n:o %lu\n", "Next log block n:o %lu, trailer n:o %lu\n",
log_block_get_hdr_no(log_block), log_block_get_hdr_no(log_block),
log_block_get_trl_no(log_block)); log_block_get_trl_no(log_block));
@ -629,11 +679,11 @@ recv_scan_log_seg_for_backup(
/* Garbage from a log buffer flush which was made /* Garbage from a log buffer flush which was made
before the most recent database recovery */ before the most recent database recovery */
/*
printf("Scanned cp n:o %lu, block cp n:o %lu\n", printf("Scanned cp n:o %lu, block cp n:o %lu\n",
*scanned_checkpoint_no, *scanned_checkpoint_no,
log_block_get_checkpoint_no(log_block)); log_block_get_checkpoint_no(log_block));
*/
break; break;
} }
@ -1011,7 +1061,7 @@ recv_recover_page(
page_lsn = page_newest_lsn; page_lsn = page_newest_lsn;
} }
} else { } else {
/* In recovery from a backup we do not use the buffer /* In recovery from a backup we do not really use the buffer
pool */ pool */
page_newest_lsn = ut_dulint_zero; page_newest_lsn = ut_dulint_zero;
@ -1361,6 +1411,14 @@ recv_apply_log_recs_for_backup(
nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT), nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT),
UNIV_PAGE_SIZE); UNIV_PAGE_SIZE);
/* We simulate a page read made by the buffer pool,
to make sure recovery works ok. We must init the
block corresponding to buf_pool->frame_zero
(== page) */
buf_page_init_for_backup_restore(0, i,
buf_block_align(page));
recv_recover_page(TRUE, FALSE, page, 0, i); recv_recover_page(TRUE, FALSE, page, 0, i);
buf_flush_init_for_writing(page, buf_flush_init_for_writing(page,
@ -2037,8 +2095,33 @@ recv_scan_log_recs(
/* fprintf(stderr, "Log block header no %lu\n", no); */ /* fprintf(stderr, "Log block header no %lu\n", no); */
if (no != log_block_get_trl_no(log_block) if ((no & 0xFFFFFF) != log_block_get_trl_no(log_block)
|| no != log_block_convert_lsn_to_no(scanned_lsn)) { || no != log_block_convert_lsn_to_no(scanned_lsn)
|| !log_block_checksum_is_ok_or_old_format(log_block)) {
if ((no & 0xFFFFFF) == log_block_get_trl_no(log_block)
&& no == log_block_convert_lsn_to_no(scanned_lsn)
&& !log_block_checksum_is_ok_or_old_format(
log_block)) {
fprintf(stderr,
"InnoDB: Log block no %lu at lsn %lu %lu has\n"
"InnoDB: ok header and trailer, but checksum field contains %lu\n",
no, ut_dulint_get_high(scanned_lsn),
ut_dulint_get_low(scanned_lsn),
mach_read_from_1(log_block
+ OS_FILE_LOG_BLOCK_SIZE
- LOG_BLOCK_TRL_CHECKSUM));
}
if ((no & 0xFFFFFF)
!= log_block_get_trl_no(log_block)) {
fprintf(stderr,
"InnoDB: Log block with header no %lu at lsn %lu %lu has\n"
"InnoDB: trailer no %lu\n",
no, ut_dulint_get_high(scanned_lsn),
ut_dulint_get_low(scanned_lsn),
log_block_get_trl_no(log_block));
}
/* Garbage or an incompletely written log block */ /* Garbage or an incompletely written log block */
@ -2241,6 +2324,7 @@ recv_recovery_from_checkpoint_start(
dulint archived_lsn; dulint archived_lsn;
ulint capacity; ulint capacity;
byte* buf; byte* buf;
byte log_hdr_buf[LOG_FILE_HDR_SIZE];
ulint err; ulint err;
ut_ad((type != LOG_CHECKPOINT) ut_ad((type != LOG_CHECKPOINT)
@ -2288,6 +2372,33 @@ recv_recovery_from_checkpoint_start(
checkpoint_no = mach_read_from_8(buf + LOG_CHECKPOINT_NO); checkpoint_no = mach_read_from_8(buf + LOG_CHECKPOINT_NO);
archived_lsn = mach_read_from_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN); archived_lsn = mach_read_from_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN);
/* Read the first log file header to print a note if this is
a recovery from a restored InnoDB Hot Backup */
fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE, max_cp_group->space_id,
0, 0, LOG_FILE_HDR_SIZE,
log_hdr_buf, max_cp_group);
if (0 == ut_memcmp(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
"ibbackup", ut_strlen("ibbackup"))) {
/* This log file was created by ibbackup --restore: print
a note to the user about it */
fprintf(stderr,
"InnoDB: The log file was created by ibbackup --restore at\n"
"InnoDB: %s\n", log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP);
/* Wipe over the label now */
ut_memcpy(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
" ", 4);
/* Write to the log file to wipe over the label */
fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE,
max_cp_group->space_id,
0, 0, OS_FILE_LOG_BLOCK_SIZE,
log_hdr_buf, max_cp_group);
}
group = UT_LIST_GET_FIRST(log_sys->log_groups); group = UT_LIST_GET_FIRST(log_sys->log_groups);
while (group) { while (group) {
@ -2471,7 +2582,7 @@ recv_recovery_from_checkpoint_finish(void)
/* Rollback the uncommitted transactions which have no user session */ /* Rollback the uncommitted transactions which have no user session */
if (srv_force_recovery < SRV_FORCE_NO_TRX_UNDO) { if (srv_force_recovery < SRV_FORCE_NO_TRX_UNDO) {
trx_rollback_all_without_sess(); trx_rollback_or_clean_all_without_sess();
} }
/* Apply the hashed log records to the respective file pages */ /* Apply the hashed log records to the respective file pages */
@ -2487,6 +2598,7 @@ recv_recovery_from_checkpoint_finish(void)
} }
if (recv_needed_recovery) { if (recv_needed_recovery) {
trx_sys_print_mysql_master_log_pos();
trx_sys_print_mysql_binlog_offset(); trx_sys_print_mysql_binlog_offset();
} }
@ -2614,10 +2726,9 @@ recv_reset_log_files_for_backup(
/* We pretend there is a checkpoint at lsn + LOG_BLOCK_HDR_SIZE */ /* We pretend there is a checkpoint at lsn + LOG_BLOCK_HDR_SIZE */
log_reset_first_header_and_checkpoint(buf, log_reset_first_header_and_checkpoint(buf, lsn);
ut_dulint_add(lsn, LOG_BLOCK_HDR_SIZE));
log_block_init(buf + LOG_FILE_HDR_SIZE, lsn); log_block_init_in_old_format(buf + LOG_FILE_HDR_SIZE, lsn);
log_block_set_first_rec_group(buf + LOG_FILE_HDR_SIZE, log_block_set_first_rec_group(buf + LOG_FILE_HDR_SIZE,
LOG_BLOCK_HDR_SIZE); LOG_BLOCK_HDR_SIZE);
sprintf(name, "%sib_logfile%lu", log_dir, 0); sprintf(name, "%sib_logfile%lu", log_dir, 0);
@ -2754,7 +2865,7 @@ ask_again:
if (ut_dulint_cmp(recv_sys->parse_start_lsn, start_lsn) < 0) { if (ut_dulint_cmp(recv_sys->parse_start_lsn, start_lsn) < 0) {
fprintf(stderr, fprintf(stderr,
"InnoDB: Archive log file %s starts from too big a lsn\n", "InnoDB: Archive log file %s starts from too big a lsn\n",
name); name);
return(TRUE); return(TRUE);
} }
@ -2765,7 +2876,7 @@ ask_again:
fprintf(stderr, fprintf(stderr,
"InnoDB: Archive log file %s starts from a wrong lsn\n", "InnoDB: Archive log file %s starts from a wrong lsn\n",
name); name);
return(TRUE); return(TRUE);
} }

View File

@ -290,7 +290,7 @@ mlog_write_string(
ut_a(0); ut_a(0);
} }
ut_ad(ptr && mtr); ut_ad(ptr && mtr);
ut_ad(len < UNIV_PAGE_SIZE); ut_a(len < UNIV_PAGE_SIZE);
ut_memcpy(ptr, str, len); ut_memcpy(ptr, str, len);
@ -338,9 +338,13 @@ mlog_parse_string(
offset = mach_read_from_2(ptr); offset = mach_read_from_2(ptr);
ptr += 2; ptr += 2;
ut_a(offset < UNIV_PAGE_SIZE);
len = mach_read_from_2(ptr); len = mach_read_from_2(ptr);
ptr += 2; ptr += 2;
ut_a(len + offset < UNIV_PAGE_SIZE);
if (end_ptr < ptr + len) { if (end_ptr < ptr + len) {
return(NULL); return(NULL);

View File

@ -315,7 +315,7 @@ mtr_log_reserve_and_write(
} }
data_size = dyn_array_get_data_size(mlog); data_size = dyn_array_get_data_size(mlog);
/* Open the database log for log_write_low */ /* Open the database log for log_write_low */
mtr->start_lsn = log_reserve_and_open(data_size); mtr->start_lsn = log_reserve_and_open(data_size);

View File

@ -22,6 +22,16 @@ Created 10/21/1995 Heikki Tuuri
#endif #endif
/* This specifies the file permissions InnoDB uses when it craetes files in
Unix; the value of os_innodb_umask is initialized in ha_innodb.cc to
my_umask */
#ifndef __WIN__
ulint os_innodb_umask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
#else
ulint os_innodb_umask = 0;
#endif
/* If the following is set to TRUE, we do not call os_file_flush in every /* If the following is set to TRUE, we do not call os_file_flush in every
os_file_write. We can set this TRUE if the doublewrite buffer is used. */ os_file_write. We can set this TRUE if the doublewrite buffer is used. */
ibool os_do_not_call_flush_at_each_write = FALSE; ibool os_do_not_call_flush_at_each_write = FALSE;
@ -32,7 +42,7 @@ OS does not provide an atomic pread or pwrite, or similar */
os_mutex_t os_file_seek_mutexes[OS_FILE_N_SEEK_MUTEXES]; os_mutex_t os_file_seek_mutexes[OS_FILE_N_SEEK_MUTEXES];
/* In simulated aio, merge at most this many consecutive i/os */ /* In simulated aio, merge at most this many consecutive i/os */
#define OS_AIO_MERGE_N_CONSECUTIVE 32 #define OS_AIO_MERGE_N_CONSECUTIVE 64
/* If this flag is TRUE, then we will use the native aio of the /* If this flag is TRUE, then we will use the native aio of the
OS (provided we compiled Innobase with it in), otherwise we will OS (provided we compiled Innobase with it in), otherwise we will
@ -40,6 +50,8 @@ use simulated aio we build below with threads */
ibool os_aio_use_native_aio = FALSE; ibool os_aio_use_native_aio = FALSE;
ibool os_aio_print_debug = FALSE;
/* The aio array slot structure */ /* The aio array slot structure */
typedef struct os_aio_slot_struct os_aio_slot_t; typedef struct os_aio_slot_struct os_aio_slot_t;
@ -115,7 +127,12 @@ os_aio_array_t* os_aio_sync_array = NULL;
ulint os_aio_n_segments = ULINT_UNDEFINED; ulint os_aio_n_segments = ULINT_UNDEFINED;
/* If the following is TRUE, read i/o handler threads try to
wait until a batch of new read requests have been posted */
ibool os_aio_recommend_sleep_for_read_threads = FALSE;
ulint os_n_file_reads = 0; ulint os_n_file_reads = 0;
ulint os_bytes_read_since_printout = 0;
ulint os_n_file_writes = 0; ulint os_n_file_writes = 0;
ulint os_n_fsyncs = 0; ulint os_n_fsyncs = 0;
ulint os_n_file_reads_old = 0; ulint os_n_file_reads_old = 0;
@ -412,8 +429,8 @@ try_again:
} }
if (create_mode == OS_FILE_CREATE) { if (create_mode == OS_FILE_CREATE) {
file = open(name, create_flag, S_IRUSR | S_IWUSR | S_IRGRP file = open(name, create_flag, S_IRUSR | S_IWUSR
| S_IWGRP | S_IROTH | S_IWOTH); | S_IRGRP | S_IWGRP);
} else { } else {
file = open(name, create_flag); file = open(name, create_flag);
} }
@ -548,8 +565,7 @@ try_again:
} }
#endif #endif
if (create_mode == OS_FILE_CREATE) { if (create_mode == OS_FILE_CREATE) {
file = open(name, create_flag, S_IRUSR | S_IWUSR | S_IRGRP file = open(name, create_flag, os_innodb_umask);
| S_IWGRP | S_IROTH | S_IWOTH);
} else { } else {
file = open(name, create_flag); file = open(name, create_flag);
} }
@ -673,6 +689,7 @@ os_file_set_size(
ulint n_bytes; ulint n_bytes;
ibool ret; ibool ret;
byte* buf; byte* buf;
byte* buf2;
ulint i; ulint i;
ut_a(size == (size & 0xFFFFFFFF)); ut_a(size == (size & 0xFFFFFFFF));
@ -680,7 +697,10 @@ os_file_set_size(
/* We use a very big 8 MB buffer in writing because Linux may be /* We use a very big 8 MB buffer in writing because Linux may be
extremely slow in fsync on 1 MB writes */ extremely slow in fsync on 1 MB writes */
buf = ut_malloc(UNIV_PAGE_SIZE * 512); buf2 = ut_malloc(UNIV_PAGE_SIZE * 513);
/* Align the buffer for possible raw i/o */
buf = ut_align(buf2, UNIV_PAGE_SIZE);
/* Write buffer full of zeros */ /* Write buffer full of zeros */
for (i = 0; i < UNIV_PAGE_SIZE * 512; i++) { for (i = 0; i < UNIV_PAGE_SIZE * 512; i++) {
@ -702,13 +722,13 @@ os_file_set_size(
(ulint)(offset >> 32), (ulint)(offset >> 32),
n_bytes); n_bytes);
if (!ret) { if (!ret) {
ut_free(buf); ut_free(buf2);
goto error_handling; goto error_handling;
} }
offset += n_bytes; offset += n_bytes;
} }
ut_free(buf); ut_free(buf2);
ret = os_file_flush(file); ret = os_file_flush(file);
@ -734,6 +754,8 @@ os_file_flush(
ut_a(file); ut_a(file);
os_n_fsyncs++;
ret = FlushFileBuffers(file); ret = FlushFileBuffers(file);
if (ret) { if (ret) {
@ -742,6 +764,10 @@ os_file_flush(
os_file_handle_error(file, NULL); os_file_handle_error(file, NULL);
/* It is a fatal error if a file flush does not succeed, because then
the database can get corrupt on disk */
ut_a(0);
return(FALSE); return(FALSE);
#else #else
int ret; int ret;
@ -764,11 +790,17 @@ os_file_flush(
return(TRUE); return(TRUE);
} }
ut_print_timestamp(stderr);
fprintf(stderr, fprintf(stderr,
"InnoDB: Error: the OS said file flush did not succeed\n"); " InnoDB: Error: the OS said file flush did not succeed\n");
os_file_handle_error(file, NULL); os_file_handle_error(file, NULL);
/* It is a fatal error if a file flush does not succeed, because then
the database can get corrupt on disk */
ut_a(0);
return(FALSE); return(FALSE);
#endif #endif
} }
@ -954,6 +986,7 @@ os_file_read(
ut_a((offset & 0xFFFFFFFF) == offset); ut_a((offset & 0xFFFFFFFF) == offset);
os_n_file_reads++; os_n_file_reads++;
os_bytes_read_since_printout += n;
try_again: try_again:
ut_ad(file); ut_ad(file);
@ -1062,7 +1095,9 @@ os_file_write(
fprintf(stderr, fprintf(stderr,
" InnoDB: Error: File pointer positioning to file %s failed at\n" " InnoDB: Error: File pointer positioning to file %s failed at\n"
"InnoDB: offset %lu %lu. Operating system error number %lu.\n", "InnoDB: offset %lu %lu. Operating system error number %lu.\n"
"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n"
"InnoDB: what the error number means.\n",
name, offset_high, offset, name, offset_high, offset,
(ulint)GetLastError()); (ulint)GetLastError());
@ -1093,8 +1128,10 @@ os_file_write(
" InnoDB: Error: Write to file %s failed at offset %lu %lu.\n" " InnoDB: Error: Write to file %s failed at offset %lu %lu.\n"
"InnoDB: %lu bytes should have been written, only %lu were written.\n" "InnoDB: %lu bytes should have been written, only %lu were written.\n"
"InnoDB: Operating system error number %lu.\n" "InnoDB: Operating system error number %lu.\n"
"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n"
"InnoDB: what the error number means.\n"
"InnoDB: Check that your OS and file system support files of this size.\n" "InnoDB: Check that your OS and file system support files of this size.\n"
"InnoDB: Check also the disk is not full or a disk quota exceeded.\n", "InnoDB: Check also that the disk is not full or a disk quota exceeded.\n",
name, offset_high, offset, n, len, name, offset_high, offset, n, len,
(ulint)GetLastError()); (ulint)GetLastError());
@ -1120,10 +1157,12 @@ os_file_write(
" InnoDB: Error: Write to file %s failed at offset %lu %lu.\n" " InnoDB: Error: Write to file %s failed at offset %lu %lu.\n"
"InnoDB: %lu bytes should have been written, only %lu were written.\n" "InnoDB: %lu bytes should have been written, only %lu were written.\n"
"InnoDB: Operating system error number %lu.\n" "InnoDB: Operating system error number %lu.\n"
"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n"
"InnoDB: what the error number means or use the perror program of MySQL.\n"
"InnoDB: Check that your OS and file system support files of this size.\n" "InnoDB: Check that your OS and file system support files of this size.\n"
"InnoDB: Check also the disk is not full or a disk quota exceeded.\n", "InnoDB: Check also that the disk is not full or a disk quota exceeded.\n",
name, offset_high, offset, n, ret, (ulint)errno); name, offset_high, offset, n, (ulint)ret,
(ulint)errno);
os_has_said_disk_full = TRUE; os_has_said_disk_full = TRUE;
} }
@ -1623,13 +1662,40 @@ os_aio_simulated_wake_handler_threads(void)
/* We do not use simulated aio: do nothing */ /* We do not use simulated aio: do nothing */
return; return;
} }
os_aio_recommend_sleep_for_read_threads = FALSE;
for (i = 0; i < os_aio_n_segments; i++) { for (i = 0; i < os_aio_n_segments; i++) {
os_aio_simulated_wake_handler_thread(i); os_aio_simulated_wake_handler_thread(i);
} }
} }
/**************************************************************************
This function can be called if one wants to post a batch of reads and
prefers an i/o-handler thread to handle them all at once later. You must
call os_aio_simulated_wake_handler_threads later to ensure the threads
are not left sleeping! */
void
os_aio_simulated_put_read_threads_to_sleep(void)
/*============================================*/
{
os_aio_array_t* array;
ulint g;
os_aio_recommend_sleep_for_read_threads = TRUE;
for (g = 0; g < os_aio_n_segments; g++) {
os_aio_get_array_and_local_segment(&array, g);
if (array == os_aio_read_array) {
os_event_reset(os_aio_segment_wait_events[g]);
}
}
}
/*********************************************************************** /***********************************************************************
Requests an asynchronous i/o operation. */ Requests an asynchronous i/o operation. */
@ -1685,7 +1751,6 @@ os_aio(
ut_ad(buf); ut_ad(buf);
ut_ad(n > 0); ut_ad(n > 0);
ut_ad(n % OS_FILE_LOG_BLOCK_SIZE == 0); ut_ad(n % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_ad((ulint)buf % OS_FILE_LOG_BLOCK_SIZE == 0)
ut_ad(offset % OS_FILE_LOG_BLOCK_SIZE == 0); ut_ad(offset % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_ad(os_aio_validate()); ut_ad(os_aio_validate());
@ -2036,18 +2101,14 @@ os_aio_simulated_handle(
ulint offs; ulint offs;
ulint lowest_offset; ulint lowest_offset;
byte* combined_buf; byte* combined_buf;
byte* combined_buf2;
ibool ret; ibool ret;
ulint n; ulint n;
ulint i; ulint i;
segment = os_aio_get_array_and_local_segment(&array, global_segment); segment = os_aio_get_array_and_local_segment(&array, global_segment);
restart: restart:
/* Give other threads chance to add several i/os to the array
at once */
os_thread_yield();
/* NOTE! We only access constant fields in os_aio_array. Therefore /* NOTE! We only access constant fields in os_aio_array. Therefore
we do not have to acquire the protecting mutex yet */ we do not have to acquire the protecting mutex yet */
@ -2058,6 +2119,15 @@ restart:
/* Look through n slots after the segment * n'th slot */ /* Look through n slots after the segment * n'th slot */
if (array == os_aio_read_array
&& os_aio_recommend_sleep_for_read_threads) {
/* Give other threads chance to add several i/os to the array
at once. */
goto recommended_sleep;
}
os_mutex_enter(array->mutex); os_mutex_enter(array->mutex);
/* Check if there is a slot for which the i/o has already been /* Check if there is a slot for which the i/o has already been
@ -2068,6 +2138,11 @@ restart:
if (slot->reserved && slot->io_already_done) { if (slot->reserved && slot->io_already_done) {
if (os_aio_print_debug) {
fprintf(stderr,
"InnoDB: i/o for slot %lu already done, returning\n", i);
}
ret = TRUE; ret = TRUE;
goto slot_io_done; goto slot_io_done;
@ -2149,9 +2224,11 @@ consecutive_loop:
/* We can use the buffer of the i/o request */ /* We can use the buffer of the i/o request */
combined_buf = slot->buf; combined_buf = slot->buf;
} else { } else {
combined_buf = ut_malloc(total_len); combined_buf2 = ut_malloc(total_len + UNIV_PAGE_SIZE);
ut_a(combined_buf); ut_a(combined_buf2);
combined_buf = ut_align(combined_buf2, UNIV_PAGE_SIZE);
} }
/* We release the array mutex for the time of the i/o: NOTE that /* We release the array mutex for the time of the i/o: NOTE that
@ -2174,6 +2251,13 @@ consecutive_loop:
srv_io_thread_op_info[global_segment] = (char*) "doing file i/o"; srv_io_thread_op_info[global_segment] = (char*) "doing file i/o";
if (os_aio_print_debug) {
fprintf(stderr,
"InnoDB: doing i/o of type %lu at offset %lu %lu, length %lu\n",
slot->type, slot->offset_high, slot->offset,
total_len);
}
/* Do the i/o with ordinary, synchronous i/o functions: */ /* Do the i/o with ordinary, synchronous i/o functions: */
if (slot->type == OS_FILE_WRITE) { if (slot->type == OS_FILE_WRITE) {
ret = os_file_write(slot->name, slot->file, combined_buf, ret = os_file_write(slot->name, slot->file, combined_buf,
@ -2203,7 +2287,7 @@ consecutive_loop:
} }
if (n_consecutive > 1) { if (n_consecutive > 1) {
ut_free(combined_buf); ut_free(combined_buf2);
} }
os_mutex_enter(array->mutex); os_mutex_enter(array->mutex);
@ -2241,10 +2325,18 @@ wait_for_io:
os_mutex_exit(array->mutex); os_mutex_exit(array->mutex);
srv_io_thread_op_info[global_segment] = (char*) "waiting for i/o request"; recommended_sleep:
srv_io_thread_op_info[global_segment] =
(char*)"waiting for i/o request";
os_event_wait(os_aio_segment_wait_events[global_segment]); os_event_wait(os_aio_segment_wait_events[global_segment]);
if (os_aio_print_debug) {
fprintf(stderr,
"InnoDB: i/o handler thread for i/o segment %lu wakes up\n",
global_segment);
}
goto restart; goto restart;
} }
@ -2305,22 +2397,30 @@ os_aio_validate(void)
Prints info of the aio arrays. */ Prints info of the aio arrays. */
void void
os_aio_print(void) os_aio_print(
/*==============*/ /*=========*/
char* buf, /* in/out: buffer where to print */
char* buf_end)/* in: buffer end */
{ {
os_aio_array_t* array; os_aio_array_t* array;
os_aio_slot_t* slot; os_aio_slot_t* slot;
ulint n_reserved; ulint n_reserved;
time_t current_time; time_t current_time;
double time_elapsed; double time_elapsed;
double avg_bytes_read;
ulint i; ulint i;
if (buf_end - buf < 1000) {
return;
}
for (i = 0; i < srv_n_file_io_threads; i++) { for (i = 0; i < srv_n_file_io_threads; i++) {
printf("I/O thread %lu state: %s\n", i, buf += sprintf(buf, "I/O thread %lu state: %s\n", i,
srv_io_thread_op_info[i]); srv_io_thread_op_info[i]);
} }
printf("Pending normal aio reads:"); buf += sprintf(buf, "Pending normal aio reads:");
array = os_aio_read_array; array = os_aio_read_array;
loop: loop:
@ -2347,12 +2447,12 @@ loop:
ut_a(array->n_reserved == n_reserved); ut_a(array->n_reserved == n_reserved);
printf(" %lu", n_reserved); buf += sprintf(buf, " %lu", n_reserved);
os_mutex_exit(array->mutex); os_mutex_exit(array->mutex);
if (array == os_aio_read_array) { if (array == os_aio_read_array) {
printf(", aio writes:"); buf += sprintf(buf, ", aio writes:");
array = os_aio_write_array; array = os_aio_write_array;
@ -2360,38 +2460,50 @@ loop:
} }
if (array == os_aio_write_array) { if (array == os_aio_write_array) {
printf(",\n ibuf aio reads:"); buf += sprintf(buf, ",\n ibuf aio reads:");
array = os_aio_ibuf_array; array = os_aio_ibuf_array;
goto loop; goto loop;
} }
if (array == os_aio_ibuf_array) { if (array == os_aio_ibuf_array) {
printf(", log i/o's:"); buf += sprintf(buf, ", log i/o's:");
array = os_aio_log_array; array = os_aio_log_array;
goto loop; goto loop;
} }
if (array == os_aio_log_array) { if (array == os_aio_log_array) {
printf(", sync i/o's:"); buf += sprintf(buf, ", sync i/o's:");
array = os_aio_sync_array; array = os_aio_sync_array;
goto loop; goto loop;
} }
printf("\n"); buf += sprintf(buf, "\n");
current_time = time(NULL); current_time = time(NULL);
time_elapsed = difftime(current_time, os_last_printout); time_elapsed = difftime(current_time, os_last_printout);
printf("Pending flushes (fsync) log: %lu; buffer pool: %lu\n", buf += sprintf(buf,
"Pending flushes (fsync) log: %lu; buffer pool: %lu\n",
fil_n_pending_log_flushes, fil_n_pending_tablespace_flushes); fil_n_pending_log_flushes, fil_n_pending_tablespace_flushes);
printf("%lu OS file reads, %lu OS file writes, %lu OS fsyncs\n", buf += sprintf(buf,
"%lu OS file reads, %lu OS file writes, %lu OS fsyncs\n",
os_n_file_reads, os_n_file_writes, os_n_fsyncs); os_n_file_reads, os_n_file_writes, os_n_fsyncs);
printf("%.2f reads/s, %.2f writes/s, %.2f fsyncs/s\n",
if (os_n_file_reads == os_n_file_reads_old) {
avg_bytes_read = 0.0;
} else {
avg_bytes_read = os_bytes_read_since_printout /
(os_n_file_reads - os_n_file_reads_old);
}
buf += sprintf(buf,
"%.2f reads/s, %lu avg bytes/read, %.2f writes/s, %.2f fsyncs/s\n",
(os_n_file_reads - os_n_file_reads_old) (os_n_file_reads - os_n_file_reads_old)
/ time_elapsed, / time_elapsed,
(ulint)avg_bytes_read,
(os_n_file_writes - os_n_file_writes_old) (os_n_file_writes - os_n_file_writes_old)
/ time_elapsed, / time_elapsed,
(os_n_fsyncs - os_n_fsyncs_old) (os_n_fsyncs - os_n_fsyncs_old)
@ -2400,6 +2512,7 @@ loop:
os_n_file_reads_old = os_n_file_reads; os_n_file_reads_old = os_n_file_reads;
os_n_file_writes_old = os_n_file_writes; os_n_file_writes_old = os_n_file_writes;
os_n_fsyncs_old = os_n_fsyncs; os_n_fsyncs_old = os_n_fsyncs;
os_bytes_read_since_printout = 0;
os_last_printout = current_time; os_last_printout = current_time;
} }

View File

@ -435,7 +435,7 @@ os_fast_mutex_init(
InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex); InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex);
#else #else
pthread_mutex_init(fast_mutex, NULL); pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST);
#endif #endif
} }

View File

@ -403,6 +403,8 @@ page_cur_insert_rec_write_log(
byte* log_ptr; byte* log_ptr;
ulint i; ulint i;
ut_a(rec_size < UNIV_PAGE_SIZE);
log_ptr = mlog_open(mtr, 30 + MLOG_BUF_MARGIN); log_ptr = mlog_open(mtr, 30 + MLOG_BUF_MARGIN);
if (log_ptr == NULL) { if (log_ptr == NULL) {
@ -491,6 +493,8 @@ page_cur_insert_rec_write_log(
mlog_close(mtr, log_ptr); mlog_close(mtr, log_ptr);
ut_a(rec_size - i < UNIV_PAGE_SIZE);
if (rec_size - i >= MLOG_BUF_MARGIN) { if (rec_size - i >= MLOG_BUF_MARGIN) {
mlog_catenate_string(mtr, ins_ptr, rec_size - i); mlog_catenate_string(mtr, ins_ptr, rec_size - i);
} }
@ -602,6 +606,9 @@ page_cur_parse_insert_rec(
/* Build the inserted record to buf */ /* Build the inserted record to buf */
ut_a(mismatch_index < UNIV_PAGE_SIZE);
ut_a(end_seg_len < UNIV_PAGE_SIZE);
ut_memcpy(buf, rec_get_start(cursor_rec), mismatch_index); ut_memcpy(buf, rec_get_start(cursor_rec), mismatch_index);
ut_memcpy(buf + mismatch_index, ptr, end_seg_len); ut_memcpy(buf + mismatch_index, ptr, end_seg_len);
@ -938,6 +945,8 @@ page_copy_rec_list_end_to_created_page(
log_data_len = dyn_array_get_data_size(&(mtr->log)) - log_data_len; log_data_len = dyn_array_get_data_size(&(mtr->log)) - log_data_len;
ut_a(log_data_len < 100 * UNIV_PAGE_SIZE);
mach_write_to_4(log_ptr, log_data_len); mach_write_to_4(log_ptr, log_data_len);
rec_set_next_offs(insert_rec, PAGE_SUPREMUM); rec_set_next_offs(insert_rec, PAGE_SUPREMUM);

View File

@ -17,6 +17,7 @@ Created 2/2/1994 Heikki Tuuri
#include "lock0lock.h" #include "lock0lock.h"
#include "fut0lst.h" #include "fut0lst.h"
#include "btr0sea.h" #include "btr0sea.h"
#include "buf0buf.h"
/* A cached template page used in page_create */ /* A cached template page used in page_create */
page_t* page_template = NULL; page_t* page_template = NULL;
@ -63,6 +64,65 @@ Assuming a page size of 8 kB, a typical index page of a secondary
index contains 300 index entries, and the size of the page directory index contains 300 index entries, and the size of the page directory
is 50 x 4 bytes = 200 bytes. */ is 50 x 4 bytes = 200 bytes. */
/*******************************************************************
Looks for the directory slot which owns the given record. */
ulint
page_dir_find_owner_slot(
/*=====================*/
/* out: the directory slot number */
rec_t* rec) /* in: the physical record */
{
ulint i;
ulint steps = 0;
page_t* page;
page_dir_slot_t* slot;
rec_t* original_rec = rec;
char err_buf[1000];
ut_ad(page_rec_check(rec));
while (rec_get_n_owned(rec) == 0) {
steps++;
rec = page_rec_get_next(rec);
}
page = buf_frame_align(rec);
i = page_dir_get_n_slots(page) - 1;
slot = page_dir_get_nth_slot(page, i);
while (page_dir_slot_get_rec(slot) != rec) {
if (i == 0) {
fprintf(stderr,
"InnoDB: Probable data corruption on page %lu\n",
buf_frame_get_page_no(page));
rec_sprintf(err_buf, 900, original_rec);
fprintf(stderr,
"InnoDB: Original record %s\n"
"InnoDB: on that page. Steps %lu.\n", err_buf, steps);
rec_sprintf(err_buf, 900, rec);
fprintf(stderr,
"InnoDB: Cannot find the dir slot for record %s\n"
"InnoDB: on that page!\n", err_buf);
buf_page_print(page);
ut_a(0);
}
i--;
slot = page_dir_get_nth_slot(page, i);
}
return(i);
}
/****************************************************************** /******************************************************************
Used to check the consistency of a directory slot. */ Used to check the consistency of a directory slot. */
static static

View File

@ -104,7 +104,9 @@ cmp_types_are_equal(
if ((type1->mtype == DATA_VARCHAR && type2->mtype == DATA_CHAR) if ((type1->mtype == DATA_VARCHAR && type2->mtype == DATA_CHAR)
|| (type1->mtype == DATA_CHAR && type2->mtype == DATA_VARCHAR) || (type1->mtype == DATA_CHAR && type2->mtype == DATA_VARCHAR)
|| (type1->mtype == DATA_FIXBINARY && type2->mtype == DATA_BINARY) || (type1->mtype == DATA_FIXBINARY && type2->mtype == DATA_BINARY)
|| (type1->mtype == DATA_BINARY && type2->mtype == DATA_FIXBINARY)) { || (type1->mtype == DATA_BINARY && type2->mtype == DATA_FIXBINARY)
|| (type1->mtype == DATA_MYSQL && type2->mtype == DATA_VARMYSQL)
|| (type1->mtype == DATA_VARMYSQL && type2->mtype == DATA_MYSQL)) {
return(TRUE); return(TRUE);
} }
@ -124,14 +126,9 @@ cmp_types_are_equal(
return(FALSE); return(FALSE);
} }
if (type1->mtype == DATA_MYSQL if (type1->mtype == DATA_INT && type1->len != type2->len) {
|| type1->mtype == DATA_VARMYSQL) {
if ((type1->prtype & ~DATA_NOT_NULL) return(FALSE);
!= (type2->prtype & ~DATA_NOT_NULL)) {
return(FALSE);
}
} }
return(TRUE); return(TRUE);

View File

@ -392,6 +392,19 @@ row_ins_foreign_delete_or_set_null(
node = thr->run_node; node = thr->run_node;
ut_a(que_node_get_type(node) == QUE_NODE_UPDATE);
if (!node->is_delete) {
/* According to SQL-92 an UPDATE with respect to FOREIGN
KEY constraints is not semantically equivalent to a
DELETE + INSERT. Therefore we do not perform any action
here and consequently the child rows would be left
orphaned if we would let the UPDATE happen. Thus we return
an error. */
return(DB_ROW_IS_REFERENCED);
}
if (node->cascade_node == NULL) { if (node->cascade_node == NULL) {
/* Extend our query graph by creating a child to current /* Extend our query graph by creating a child to current
update node. The child is used in the cascade or set null update node. The child is used in the cascade or set null
@ -609,7 +622,7 @@ the caller must have a shared latch on dict_foreign_key_check_lock. */
ulint ulint
row_ins_check_foreign_constraint( row_ins_check_foreign_constraint(
/*=============================*/ /*=============================*/
/* out: DB_SUCCESS, DB_LOCK_WAIT, /* out: DB_SUCCESS,
DB_NO_REFERENCED_ROW, DB_NO_REFERENCED_ROW,
or DB_ROW_IS_REFERENCED */ or DB_ROW_IS_REFERENCED */
ibool check_ref,/* in: TRUE if we want to check that ibool check_ref,/* in: TRUE if we want to check that
@ -627,6 +640,7 @@ row_ins_check_foreign_constraint(
dict_table_t* check_table; dict_table_t* check_table;
dict_index_t* check_index; dict_index_t* check_index;
ulint n_fields_cmp; ulint n_fields_cmp;
ibool timeout_expired;
rec_t* rec; rec_t* rec;
btr_pcur_t pcur; btr_pcur_t pcur;
ibool moved; ibool moved;
@ -635,6 +649,7 @@ row_ins_check_foreign_constraint(
ulint i; ulint i;
mtr_t mtr; mtr_t mtr;
run_again:
ut_ad(rw_lock_own(&dict_foreign_key_check_lock, RW_LOCK_SHARED)); ut_ad(rw_lock_own(&dict_foreign_key_check_lock, RW_LOCK_SHARED));
if (thr_get_trx(thr)->check_foreigns == FALSE) { if (thr_get_trx(thr)->check_foreigns == FALSE) {
@ -682,7 +697,7 @@ row_ins_check_foreign_constraint(
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
return(err); goto do_possible_lock_wait;
} }
} }
@ -727,6 +742,11 @@ row_ins_check_foreign_constraint(
if (!rec_get_deleted_flag(rec)) { if (!rec_get_deleted_flag(rec)) {
/* Found a matching record */ /* Found a matching record */
/* printf(
"FOREIGN: Found matching record from %s %s\n",
check_index->table_name, check_index->name);
rec_print(rec);
*/
if (check_ref) { if (check_ref) {
err = DB_SUCCESS; err = DB_SUCCESS;
@ -779,6 +799,22 @@ next_rec:
/* Restore old value */ /* Restore old value */
dtuple_set_n_fields_cmp(entry, n_fields_cmp); dtuple_set_n_fields_cmp(entry, n_fields_cmp);
do_possible_lock_wait:
if (err == DB_LOCK_WAIT) {
thr_get_trx(thr)->error_state = err;
que_thr_stop_for_mysql(thr);
timeout_expired = srv_suspend_mysql_thread(thr);
if (!timeout_expired) {
goto run_again;
}
err = DB_LOCK_WAIT_TIMEOUT;
}
return(err); return(err);
} }
@ -792,8 +828,7 @@ static
ulint ulint
row_ins_check_foreign_constraints( row_ins_check_foreign_constraints(
/*==============================*/ /*==============================*/
/* out: DB_SUCCESS, DB_LOCK_WAIT, or error /* out: DB_SUCCESS or error code */
code */
dict_table_t* table, /* in: table */ dict_table_t* table, /* in: table */
dict_index_t* index, /* in: index */ dict_index_t* index, /* in: index */
dtuple_t* entry, /* in: index entry for index */ dtuple_t* entry, /* in: index entry for index */

View File

@ -934,6 +934,7 @@ row_update_for_mysql(
ut_ad(!prebuilt->sql_stat_start); ut_ad(!prebuilt->sql_stat_start);
que_thr_move_to_run_state_for_mysql(thr, trx); que_thr_move_to_run_state_for_mysql(thr, trx);
run_again: run_again:
thr->run_node = node; thr->run_node = node;
thr->prev_node = node; thr->prev_node = node;
@ -998,7 +999,6 @@ row_update_cascade_for_mysql(
trx_t* trx; trx_t* trx;
trx = thr_get_trx(thr); trx = thr_get_trx(thr);
run_again: run_again:
thr->run_node = node; thr->run_node = node;
thr->prev_node = node; thr->prev_node = node;
@ -1130,6 +1130,35 @@ row_mysql_recover_tmp_table(
return(row_rename_table_for_mysql(old_name, table->name, trx)); return(row_rename_table_for_mysql(old_name, table->name, trx));
} }
/*************************************************************************
Locks the data dictionary exclusively for performing a table create
operation. */
void
row_mysql_lock_data_dictionary(void)
/*================================*/
{
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks or lock waits can occur then in these operations */
rw_lock_x_lock(&(dict_foreign_key_check_lock));
mutex_enter(&(dict_sys->mutex));
}
/*************************************************************************
Unlocks the data dictionary exclusively lock. */
void
row_mysql_unlock_data_dictionary(void)
/*==================================*/
{
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
mutex_exit(&(dict_sys->mutex));
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
}
/************************************************************************* /*************************************************************************
Does a table creation operation for MySQL. If the name of the created Does a table creation operation for MySQL. If the name of the created
table ends to characters INNODB_MONITOR, then this also starts table ends to characters INNODB_MONITOR, then this also starts
@ -1150,6 +1179,7 @@ row_create_table_for_mysql(
ulint err; ulint err;
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_ad(mutex_own(&(dict_sys->mutex)));
if (srv_created_new_raw || srv_force_recovery) { if (srv_created_new_raw || srv_force_recovery) {
fprintf(stderr, fprintf(stderr,
@ -1265,19 +1295,13 @@ row_create_table_for_mysql(
"to use this feature you must compile InnoDB with\n" "to use this feature you must compile InnoDB with\n"
"UNIV_MEM_DEBUG defined in univ.i and the server must be\n" "UNIV_MEM_DEBUG defined in univ.i and the server must be\n"
"quiet because allocation from a mem heap is not protected\n" "quiet because allocation from a mem heap is not protected\n"
"by any semaphore.\n"); "by any semaphore.\n");
ut_a(mem_validate()); ut_a(mem_validate());
printf("Memory validated\n"); printf("Memory validated\n");
} }
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
rw_lock_x_lock(&(dict_foreign_key_check_lock));
mutex_enter(&(dict_sys->mutex));
heap = mem_heap_create(512); heap = mem_heap_create(512);
trx->dict_operation = TRUE; trx->dict_operation = TRUE;
@ -1327,9 +1351,6 @@ row_create_table_for_mysql(
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
} }
mutex_exit(&(dict_sys->mutex));
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
que_graph_free((que_t*) que_node_get_parent(thr)); que_graph_free((que_t*) que_node_get_parent(thr));
trx->op_info = (char *) ""; trx->op_info = (char *) "";
@ -1356,6 +1377,7 @@ row_create_index_for_mysql(
ulint keywordlen; ulint keywordlen;
ulint err; ulint err;
ut_ad(mutex_own(&(dict_sys->mutex)));
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
trx->op_info = (char *) "creating index"; trx->op_info = (char *) "creating index";
@ -1374,12 +1396,6 @@ row_create_index_for_mysql(
return(DB_SUCCESS); return(DB_SUCCESS);
} }
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
rw_lock_x_lock(&(dict_foreign_key_check_lock));
mutex_enter(&(dict_sys->mutex));
heap = mem_heap_create(512); heap = mem_heap_create(512);
trx->dict_operation = TRUE; trx->dict_operation = TRUE;
@ -1407,9 +1423,6 @@ row_create_index_for_mysql(
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
} }
mutex_exit(&(dict_sys->mutex));
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
que_graph_free((que_t*) que_node_get_parent(thr)); que_graph_free((que_t*) que_node_get_parent(thr));
trx->op_info = (char *) ""; trx->op_info = (char *) "";
@ -1443,6 +1456,7 @@ row_table_add_foreign_constraints(
ulint keywordlen; ulint keywordlen;
ulint err; ulint err;
ut_ad(mutex_own(&(dict_sys->mutex)));
ut_a(sql_string); ut_a(sql_string);
trx->op_info = (char *) "adding foreign keys"; trx->op_info = (char *) "adding foreign keys";
@ -1461,12 +1475,6 @@ row_table_add_foreign_constraints(
return(DB_SUCCESS); return(DB_SUCCESS);
} }
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
rw_lock_x_lock(&(dict_foreign_key_check_lock));
mutex_enter(&(dict_sys->mutex));
trx->dict_operation = TRUE; trx->dict_operation = TRUE;
err = dict_create_foreign_constraints(trx, sql_string, name); err = dict_create_foreign_constraints(trx, sql_string, name);
@ -1488,9 +1496,6 @@ row_table_add_foreign_constraints(
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
} }
mutex_exit(&(dict_sys->mutex));
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
return((int) err); return((int) err);
} }
@ -1922,6 +1927,13 @@ row_drop_table_for_mysql(
ut_a(0); ut_a(0);
} else { } else {
dict_table_remove_from_cache(table); dict_table_remove_from_cache(table);
if (dict_load_table(name) != NULL) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: dropping of table %s failed!\n", name);
}
} }
funct_exit: funct_exit:
rw_lock_s_unlock(&(purge_sys->purge_is_running)); rw_lock_s_unlock(&(purge_sys->purge_is_running));
@ -1979,6 +1991,7 @@ loop:
if (table->n_mysql_handles_opened > 0) { if (table->n_mysql_handles_opened > 0) {
mutex_exit(&(dict_sys->mutex)); mutex_exit(&(dict_sys->mutex));
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, fprintf(stderr,
@ -2409,6 +2422,14 @@ row_check_table_for_mysql(
index = dict_table_get_next_index(index); index = dict_table_get_next_index(index);
} }
/* We validate also the whole adaptive hash index for all tables
at every CHECK TABLE */
if (!btr_search_validate()) {
ret = DB_ERROR;
}
prebuilt->trx->op_info = (char *) ""; prebuilt->trx->op_info = (char *) "";
return(ret); return(ret);

View File

@ -511,6 +511,14 @@ row_purge_parse_undo_rec(
clust_index = dict_table_get_first_index(node->table); clust_index = dict_table_get_first_index(node->table);
if (clust_index == NULL) {
/* The table was corrupt in the data dictionary */
rw_lock_x_unlock(&(purge_sys->purge_is_running));
return(FALSE);
}
ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref), ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
node->heap); node->heap);

View File

@ -437,11 +437,12 @@ row_undo_mod_del_unmark_sec(
rec_sprintf(err_buf, 900, btr_pcur_get_rec(&pcur)); rec_sprintf(err_buf, 900, btr_pcur_get_rec(&pcur));
fprintf(stderr, "InnoDB: record %s\n", err_buf); fprintf(stderr, "InnoDB: record %s\n", err_buf);
trx_print(err_buf, thr_get_trx(thr));
fprintf(stderr, fprintf(stderr,
"InnoDB: Make a detailed bug report and send it\n"); "%s\nInnoDB: Make a detailed bug report and send it\n",
err_buf);
fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n");
trx_print(thr_get_trx(thr));
} else { } else {
btr_cur = btr_pcur_get_btr_cur(&pcur); btr_cur = btr_pcur_get_btr_cur(&pcur);

View File

@ -129,8 +129,7 @@ static
ulint ulint
row_upd_check_references_constraints( row_upd_check_references_constraints(
/*=================================*/ /*=================================*/
/* out: DB_SUCCESS, DB_LOCK_WAIT, or an error /* out: DB_SUCCESS or an error code */
code */
btr_pcur_t* pcur, /* in: cursor positioned on a record; NOTE: the btr_pcur_t* pcur, /* in: cursor positioned on a record; NOTE: the
cursor position is lost in this function! */ cursor position is lost in this function! */
dict_table_t* table, /* in: table in question */ dict_table_t* table, /* in: table in question */
@ -626,7 +625,7 @@ row_upd_index_parse(
/******************************************************************* /*******************************************************************
Returns TRUE if ext_vec contains i. */ Returns TRUE if ext_vec contains i. */
UNIV_INLINE static
ibool ibool
upd_ext_vec_contains( upd_ext_vec_contains(
/*=================*/ /*=================*/
@ -738,6 +737,7 @@ row_upd_build_difference_binary(
ulint n_diff; ulint n_diff;
ulint roll_ptr_pos; ulint roll_ptr_pos;
ulint trx_id_pos; ulint trx_id_pos;
ibool extern_bit;
ulint i; ulint i;
/* This function is used only for a clustered index */ /* This function is used only for a clustered index */
@ -763,9 +763,10 @@ row_upd_build_difference_binary(
goto skip_compare; goto skip_compare;
} }
extern_bit = rec_get_nth_field_extern_bit(rec, i);
if (rec_get_nth_field_extern_bit(rec, i) if (extern_bit != upd_ext_vec_contains(ext_vec, n_ext_vec, i)
!= upd_ext_vec_contains(ext_vec, n_ext_vec, i)
|| !dfield_data_is_binary_equal(dfield, len, data)) { || !dfield_data_is_binary_equal(dfield, len, data)) {
upd_field = upd_get_nth_field(update, n_diff); upd_field = upd_get_nth_field(update, n_diff);
@ -1094,11 +1095,12 @@ row_upd_sec_index_entry(
rec_sprintf(err_buf, 900, rec); rec_sprintf(err_buf, 900, rec);
fprintf(stderr, "InnoDB: record %s\n", err_buf); fprintf(stderr, "InnoDB: record %s\n", err_buf);
fprintf(stderr, trx_print(err_buf, thr_get_trx(thr));
"InnoDB: Make a detailed bug report and send it\n");
fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n");
trx_print(thr_get_trx(thr)); fprintf(stderr,
"%s\nInnoDB: Make a detailed bug report and send it\n",
err_buf);
fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n");
} else { } else {
/* Delete mark the old index record; it can already be /* Delete mark the old index record; it can already be
delete marked if we return after a lock wait in delete marked if we return after a lock wait in
@ -1362,7 +1364,7 @@ ulint
row_upd_del_mark_clust_rec( row_upd_del_mark_clust_rec(
/*=======================*/ /*=======================*/
/* out: DB_SUCCESS if operation successfully /* out: DB_SUCCESS if operation successfully
completed, else error code or DB_LOCK_WAIT */ completed, else error code */
upd_node_t* node, /* in: row update node */ upd_node_t* node, /* in: row update node */
dict_index_t* index, /* in: clustered index */ dict_index_t* index, /* in: clustered index */
que_thr_t* thr, /* in: query thread */ que_thr_t* thr, /* in: query thread */
@ -1381,8 +1383,6 @@ row_upd_del_mark_clust_rec(
pcur = node->pcur; pcur = node->pcur;
btr_cur = btr_pcur_get_btr_cur(pcur); btr_cur = btr_pcur_get_btr_cur(pcur);
ut_ad(FALSE == rec_get_deleted_flag(btr_pcur_get_rec(pcur)));
/* Store row because we have to build also the secondary index /* Store row because we have to build also the secondary index
entries */ entries */
@ -1391,11 +1391,11 @@ row_upd_del_mark_clust_rec(
/* Mark the clustered index record deleted; we do not have to check /* Mark the clustered index record deleted; we do not have to check
locks, because we assume that we have an x-lock on the record */ locks, because we assume that we have an x-lock on the record */
err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG, btr_cur, err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
TRUE, thr, mtr); btr_cur, TRUE, thr, mtr);
if (err == DB_SUCCESS && check_ref) { if (err == DB_SUCCESS && check_ref) {
/* NOTE that the following call loses /* NOTE that the following call loses the position of pcur ! */
the position of pcur ! */
err = row_upd_check_references_constraints(pcur, index->table, err = row_upd_check_references_constraints(pcur, index->table,
index, thr, mtr); index, thr, mtr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {

View File

@ -61,7 +61,7 @@ ulint srv_activity_count = 0;
ibool srv_lock_timeout_and_monitor_active = FALSE; ibool srv_lock_timeout_and_monitor_active = FALSE;
ibool srv_error_monitor_active = FALSE; ibool srv_error_monitor_active = FALSE;
char* srv_main_thread_op_info = (char *) ""; char* srv_main_thread_op_info = (char*) "";
/* Server parameters which are read from the initfile */ /* Server parameters which are read from the initfile */
@ -238,15 +238,14 @@ ulint srv_n_rows_updated_old = 0;
ulint srv_n_rows_deleted_old = 0; ulint srv_n_rows_deleted_old = 0;
ulint srv_n_rows_read_old = 0; ulint srv_n_rows_read_old = 0;
ibool srv_print_innodb_monitor = FALSE;
ibool srv_print_innodb_lock_monitor = FALSE;
ibool srv_print_innodb_tablespace_monitor = FALSE;
/* /*
Set the following to 0 if you want InnoDB to write messages on Set the following to 0 if you want InnoDB to write messages on
stderr on startup/shutdown stderr on startup/shutdown
*/ */
ibool srv_print_verbose_log = TRUE; ibool srv_print_verbose_log = TRUE;
ibool srv_print_innodb_monitor = FALSE;
ibool srv_print_innodb_lock_monitor = FALSE;
ibool srv_print_innodb_tablespace_monitor = FALSE;
ibool srv_print_innodb_table_monitor = FALSE; ibool srv_print_innodb_table_monitor = FALSE;
/* The parameters below are obsolete: */ /* The parameters below are obsolete: */
@ -278,6 +277,10 @@ i/o handler thread */
char* srv_io_thread_op_info[SRV_MAX_N_IO_THREADS]; char* srv_io_thread_op_info[SRV_MAX_N_IO_THREADS];
time_t srv_last_monitor_time;
mutex_t srv_innodb_monitor_mutex;
/* /*
IMPLEMENTATION OF THE SERVER MAIN PROGRAM IMPLEMENTATION OF THE SERVER MAIN PROGRAM
========================================= =========================================
@ -645,7 +648,7 @@ srv_release_threads(
slot = srv_table_get_nth_slot(i); slot = srv_table_get_nth_slot(i);
if ((slot->type == type) && slot->suspended) { if (slot->in_use && slot->type == type && slot->suspended) {
slot->suspended = FALSE; slot->suspended = FALSE;
@ -987,7 +990,6 @@ srv_communication_init(
/************************************************************************* /*************************************************************************
Implements the recovery utility. */ Implements the recovery utility. */
#ifdef NOT_USED
static static
ulint ulint
srv_recovery_thread( srv_recovery_thread(
@ -1025,7 +1027,7 @@ srv_recovery_thread(
return(0); return(0);
} }
#endif
/************************************************************************* /*************************************************************************
Implements the purge utility. */ Implements the purge utility. */
@ -1077,7 +1079,6 @@ srv_create_utility_threads(void)
/************************************************************************* /*************************************************************************
Implements the communication threads. */ Implements the communication threads. */
#ifdef NOT_USED
static static
ulint ulint
srv_com_thread( srv_com_thread(
@ -1125,7 +1126,7 @@ srv_com_thread(
return(0); return(0);
} }
#endif
/************************************************************************* /*************************************************************************
Creates the communication threads. */ Creates the communication threads. */
@ -1147,7 +1148,6 @@ srv_create_com_threads(void)
/************************************************************************* /*************************************************************************
Implements the worker threads. */ Implements the worker threads. */
#ifdef NOT_USED
static static
ulint ulint
srv_worker_thread( srv_worker_thread(
@ -1190,7 +1190,7 @@ srv_worker_thread(
return(0); return(0);
} }
#endif
/************************************************************************* /*************************************************************************
Creates the worker threads. */ Creates the worker threads. */
@ -1625,13 +1625,16 @@ srv_init(void)
kernel_mutex_temp = mem_alloc(sizeof(mutex_t)); kernel_mutex_temp = mem_alloc(sizeof(mutex_t));
mutex_create(&kernel_mutex); mutex_create(&kernel_mutex);
mutex_set_level(&kernel_mutex, SYNC_KERNEL); mutex_set_level(&kernel_mutex, SYNC_KERNEL);
mutex_create(&srv_innodb_monitor_mutex);
mutex_set_level(&srv_innodb_monitor_mutex, SYNC_NO_ORDER_CHECK);
srv_sys->threads = mem_alloc(OS_THREAD_MAX_N * sizeof(srv_slot_t)); srv_sys->threads = mem_alloc(OS_THREAD_MAX_N * sizeof(srv_slot_t));
for (i = 0; i < OS_THREAD_MAX_N; i++) { for (i = 0; i < OS_THREAD_MAX_N; i++) {
slot = srv_table_get_nth_slot(i); slot = srv_table_get_nth_slot(i);
slot->in_use = FALSE; slot->in_use = FALSE;
slot->type=0; /* Avoid purify errors */ slot->type=0; /* Avoid purify errors */
slot->event = os_event_create(NULL); slot->event = os_event_create(NULL);
ut_a(slot->event); ut_a(slot->event);
} }
@ -1641,6 +1644,7 @@ srv_init(void)
for (i = 0; i < OS_THREAD_MAX_N; i++) { for (i = 0; i < OS_THREAD_MAX_N; i++) {
slot = srv_mysql_table + i; slot = srv_mysql_table + i;
slot->in_use = FALSE; slot->in_use = FALSE;
slot->type = 0;
slot->event = os_event_create(NULL); slot->event = os_event_create(NULL);
ut_a(slot->event); ut_a(slot->event);
} }
@ -1900,7 +1904,6 @@ srv_conc_exit_innodb(
trx_t* trx) /* in: transaction object associated with the trx_t* trx) /* in: transaction object associated with the
thread */ thread */
{ {
if (srv_thread_concurrency >= 500) { if (srv_thread_concurrency >= 500) {
return; return;
@ -2004,7 +2007,31 @@ srv_table_reserve_slot_for_mysql(void)
while (slot->in_use) { while (slot->in_use) {
i++; i++;
ut_a(i < OS_THREAD_MAX_N);
if (i >= OS_THREAD_MAX_N) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: There appear to be %lu MySQL threads currently waiting\n"
"InnoDB: inside InnoDB, which is the upper limit. Cannot continue operation.\n"
"InnoDB: We intentionally generate a seg fault to print a stack trace\n"
"InnoDB: on Linux. But first we print a list of waiting threads.\n", i);
for (i = 0; i < OS_THREAD_MAX_N; i++) {
slot = srv_mysql_table + i;
fprintf(stderr,
"Slot %lu: thread id %lu, type %lu, in use %lu, susp %lu, time %lu\n",
i, (ulint)(slot->id),
slot->type, slot->in_use,
slot->suspended,
(ulint)difftime(ut_time(), slot->suspend_time));
}
ut_a(0);
}
slot = srv_mysql_table + i; slot = srv_mysql_table + i;
} }
@ -2141,6 +2168,134 @@ srv_release_mysql_thread_if_suspended(
/* not found */ /* not found */
} }
/**********************************************************************
Sprintfs to a buffer the output of the InnoDB Monitor. */
void
srv_sprintf_innodb_monitor(
/*=======================*/
char* buf, /* in/out: buffer which must be at least 4 kB */
ulint len) /* in: length of the buffer */
{
char* buf_end = buf + len - 2000;
double time_elapsed;
time_t current_time;
mutex_enter(&srv_innodb_monitor_mutex);
current_time = time(NULL);
/* We add 0.001 seconds to time_elapsed to prevent division
by zero if two users happen to call SHOW INNODB STATUS at the same
time */
time_elapsed = difftime(current_time, srv_last_monitor_time)
+ 0.001;
srv_last_monitor_time = time(NULL);
ut_a(len >= 4096);
buf += sprintf(buf, "\n=====================================\n");
ut_sprintf_timestamp(buf);
buf = buf + strlen(buf);
buf += sprintf(buf, " INNODB MONITOR OUTPUT\n"
"=====================================\n");
buf += sprintf(buf,
"Per second values calculated from the last %lu seconds\n",
(ulint)time_elapsed);
buf += sprintf(buf, "----------\n"
"SEMAPHORES\n"
"----------\n");
sync_print(buf, buf_end);
buf = buf + strlen(buf);
buf += sprintf(buf, "------------\n"
"TRANSACTIONS\n"
"------------\n");
lock_print_info(buf, buf_end);
buf = buf + strlen(buf);
buf += sprintf(buf, "--------\n"
"FILE I/O\n"
"--------\n");
os_aio_print(buf, buf_end);
buf = buf + strlen(buf);
buf += sprintf(buf, "-------------------------------------\n"
"INSERT BUFFER AND ADAPTIVE HASH INDEX\n"
"-------------------------------------\n");
ibuf_print(buf, buf_end);
buf = buf + strlen(buf);
ha_print_info(buf, buf_end, btr_search_sys->hash_index);
buf = buf + strlen(buf);
buf += sprintf(buf,
"%.2f hash searches/s, %.2f non-hash searches/s\n",
(btr_cur_n_sea - btr_cur_n_sea_old)
/ time_elapsed,
(btr_cur_n_non_sea - btr_cur_n_non_sea_old)
/ time_elapsed);
btr_cur_n_sea_old = btr_cur_n_sea;
btr_cur_n_non_sea_old = btr_cur_n_non_sea;
buf += sprintf(buf,"---\n"
"LOG\n"
"---\n");
log_print(buf, buf_end);
buf = buf + strlen(buf);
buf += sprintf(buf, "----------------------\n"
"BUFFER POOL AND MEMORY\n"
"----------------------\n");
buf += sprintf(buf,
"Total memory allocated %lu; in additional pool allocated %lu\n",
ut_total_allocated_memory,
mem_pool_get_reserved(mem_comm_pool));
buf_print_io(buf, buf_end);
buf = buf + strlen(buf);
buf += sprintf(buf, "--------------\n"
"ROW OPERATIONS\n"
"--------------\n");
buf += sprintf(buf,
"%ld queries inside InnoDB, %ld queries in queue; main thread: %s\n",
srv_conc_n_threads, srv_conc_n_waiting_threads,
srv_main_thread_op_info);
buf += sprintf(buf,
"Number of rows inserted %lu, updated %lu, deleted %lu, read %lu\n",
srv_n_rows_inserted,
srv_n_rows_updated,
srv_n_rows_deleted,
srv_n_rows_read);
buf += sprintf(buf,
"%.2f inserts/s, %.2f updates/s, %.2f deletes/s, %.2f reads/s\n",
(srv_n_rows_inserted - srv_n_rows_inserted_old)
/ time_elapsed,
(srv_n_rows_updated - srv_n_rows_updated_old)
/ time_elapsed,
(srv_n_rows_deleted - srv_n_rows_deleted_old)
/ time_elapsed,
(srv_n_rows_read - srv_n_rows_read_old)
/ time_elapsed);
srv_n_rows_inserted_old = srv_n_rows_inserted;
srv_n_rows_updated_old = srv_n_rows_updated;
srv_n_rows_deleted_old = srv_n_rows_deleted;
srv_n_rows_read_old = srv_n_rows_read;
buf += sprintf(buf, "----------------------------\n"
"END OF INNODB MONITOR OUTPUT\n"
"============================\n");
mutex_exit(&srv_innodb_monitor_mutex);
}
/************************************************************************* /*************************************************************************
A thread which wakes up threads whose lock wait may have lasted too long. A thread which wakes up threads whose lock wait may have lasted too long.
This also prints the info output by various InnoDB monitors. */ This also prints the info output by various InnoDB monitors. */
@ -2159,15 +2314,17 @@ srv_lock_timeout_and_monitor_thread(
srv_slot_t* slot; srv_slot_t* slot;
double time_elapsed; double time_elapsed;
time_t current_time; time_t current_time;
time_t last_monitor_time; time_t last_table_monitor_time;
time_t last_table_monitor_time; time_t last_monitor_time;
ibool some_waits; ibool some_waits;
double wait_time; double wait_time;
char* buf;
ulint i; ulint i;
UT_NOT_USED(arg); UT_NOT_USED(arg);
last_monitor_time = time(NULL); srv_last_monitor_time = time(NULL);
last_table_monitor_time = time(NULL); last_table_monitor_time = time(NULL);
last_monitor_time = time(NULL);
loop: loop:
srv_lock_timeout_and_monitor_active = TRUE; srv_lock_timeout_and_monitor_active = TRUE;
@ -2187,76 +2344,17 @@ loop:
time_elapsed = difftime(current_time, last_monitor_time); time_elapsed = difftime(current_time, last_monitor_time);
if (time_elapsed > 15) { if (time_elapsed > 15) {
last_monitor_time = time(NULL);
if (srv_print_innodb_monitor) { if (srv_print_innodb_monitor) {
last_monitor_time = time(NULL); buf = mem_alloc(100000);
printf("=====================================\n");
ut_print_timestamp(stdout);
printf(" INNODB MONITOR OUTPUT\n"
"=====================================\n");
printf("----------\n"
"SEMAPHORES\n"
"----------\n");
sync_print();
printf("------------\n"
"TRANSACTIONS\n"
"------------\n");
lock_print_info();
printf("--------\n"
"FILE I/O\n"
"--------\n");
os_aio_print();
printf("-------------\n"
"INSERT BUFFER\n"
"-------------\n");
ibuf_print();
printf("---\n"
"LOG\n"
"---\n");
log_print();
printf("----------------------\n"
"BUFFER POOL AND MEMORY\n"
"----------------------\n");
printf(
"Total memory allocated %lu; in additional pool allocated %lu\n",
ut_total_allocated_memory,
mem_pool_get_reserved(mem_comm_pool));
buf_print_io();
printf("--------------\n"
"ROW OPERATIONS\n"
"--------------\n");
printf(
"%ld queries inside InnoDB, %ld queries in queue; main thread: %s\n",
srv_conc_n_threads, srv_conc_n_waiting_threads,
srv_main_thread_op_info);
printf(
"Number of rows inserted %lu, updated %lu, deleted %lu, read %lu\n",
srv_n_rows_inserted,
srv_n_rows_updated,
srv_n_rows_deleted,
srv_n_rows_read);
printf(
"%.2f inserts/s, %.2f updates/s, %.2f deletes/s, %.2f reads/s\n",
(srv_n_rows_inserted - srv_n_rows_inserted_old)
/ time_elapsed,
(srv_n_rows_updated - srv_n_rows_updated_old)
/ time_elapsed,
(srv_n_rows_deleted - srv_n_rows_deleted_old)
/ time_elapsed,
(srv_n_rows_read - srv_n_rows_read_old)
/ time_elapsed);
srv_n_rows_inserted_old = srv_n_rows_inserted; srv_sprintf_innodb_monitor(buf, 100000);
srv_n_rows_updated_old = srv_n_rows_updated;
srv_n_rows_deleted_old = srv_n_rows_deleted;
srv_n_rows_read_old = srv_n_rows_read;
printf("----------------------------\n" printf("%s", buf);
"END OF INNODB MONITOR OUTPUT\n"
"============================\n"); mem_free(buf);
} }
if (srv_print_innodb_tablespace_monitor if (srv_print_innodb_tablespace_monitor
@ -2491,7 +2589,7 @@ srv_master_thread(
os_event_set(srv_sys->operational); os_event_set(srv_sys->operational);
loop: loop:
srv_main_thread_op_info = (char *) "reserving kernel mutex"; srv_main_thread_op_info = (char*) "reserving kernel mutex";
n_ios_very_old = log_sys->n_log_ios + buf_pool->n_pages_read n_ios_very_old = log_sys->n_log_ios + buf_pool->n_pages_read
+ buf_pool->n_pages_written; + buf_pool->n_pages_written;
@ -2507,18 +2605,19 @@ loop:
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
n_ios_old = log_sys->n_log_ios + buf_pool->n_pages_read n_ios_old = log_sys->n_log_ios + buf_pool->n_pages_read
+ buf_pool->n_pages_written; + buf_pool->n_pages_written;
srv_main_thread_op_info = (char *) "sleeping"; srv_main_thread_op_info = (char*)"sleeping";
os_thread_sleep(1000000); os_thread_sleep(1000000);
/* ALTER TABLE in MySQL requires on Unix that the table handler /* ALTER TABLE in MySQL requires on Unix that the table handler
can drop tables lazily after there no longer are SELECT can drop tables lazily after there no longer are SELECT
queries to them. */ queries to them. */
srv_main_thread_op_info = (char*) "doing background drop tables"; srv_main_thread_op_info =
(char*)"doing background drop tables";
row_drop_tables_for_mysql_in_background(); row_drop_tables_for_mysql_in_background();
srv_main_thread_op_info = (char*) ""; srv_main_thread_op_info = (char*)"";
if (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND) { if (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND) {
@ -2529,8 +2628,9 @@ loop:
is issued or the we have specified in my.cnf no flush is issued or the we have specified in my.cnf no flush
at transaction commit */ at transaction commit */
srv_main_thread_op_info = (char *) "flushing log"; srv_main_thread_op_info = (char*)"flushing log";
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
log_flush_to_disk();
/* If there were less than 10 i/os during the /* If there were less than 10 i/os during the
one second sleep, we assume that there is free one second sleep, we assume that there is free
@ -2543,11 +2643,13 @@ loop:
+ buf_pool->n_pages_written; + buf_pool->n_pages_written;
if (n_pend_ios < 3 && (n_ios - n_ios_old < 10)) { if (n_pend_ios < 3 && (n_ios - n_ios_old < 10)) {
srv_main_thread_op_info = srv_main_thread_op_info =
(char *) "doing insert buffer merge"; (char*)"doing insert buffer merge";
ibuf_contract_for_n_pages(TRUE, 5); ibuf_contract_for_n_pages(TRUE, 5);
srv_main_thread_op_info = (char *) "flushing log"; srv_main_thread_op_info =
(char*)"flushing log";
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
log_flush_to_disk();
} }
if (srv_fast_shutdown && srv_shutdown_state > 0) { if (srv_fast_shutdown && srv_shutdown_state > 0) {
@ -2583,21 +2685,23 @@ loop:
+ buf_pool->n_pages_written; + buf_pool->n_pages_written;
if (n_pend_ios < 3 && (n_ios - n_ios_very_old < 200)) { if (n_pend_ios < 3 && (n_ios - n_ios_very_old < 200)) {
srv_main_thread_op_info =(char *) "flushing buffer pool pages"; srv_main_thread_op_info = (char*) "flushing buffer pool pages";
buf_flush_batch(BUF_FLUSH_LIST, 50, ut_dulint_max); buf_flush_batch(BUF_FLUSH_LIST, 50, ut_dulint_max);
srv_main_thread_op_info = (char *) "flushing log"; srv_main_thread_op_info = (char*) "flushing log";
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
log_flush_to_disk();
} }
/* We run a batch of insert buffer merge every 10 seconds, /* We run a batch of insert buffer merge every 10 seconds,
even if the server were active */ even if the server were active */
srv_main_thread_op_info = (char *) "doing insert buffer merge"; srv_main_thread_op_info = (char*)"doing insert buffer merge";
ibuf_contract_for_n_pages(TRUE, 5); ibuf_contract_for_n_pages(TRUE, 5);
srv_main_thread_op_info = (char *) "flushing log"; srv_main_thread_op_info = (char*)"flushing log";
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
log_flush_to_disk();
/* We run a full purge every 10 seconds, even if the server /* We run a full purge every 10 seconds, even if the server
were active */ were active */
@ -2613,15 +2717,16 @@ loop:
goto background_loop; goto background_loop;
} }
srv_main_thread_op_info = (char *) "purging"; srv_main_thread_op_info = (char*)"purging";
n_pages_purged = trx_purge(); n_pages_purged = trx_purge();
current_time = time(NULL); current_time = time(NULL);
if (difftime(current_time, last_flush_time) > 1) { if (difftime(current_time, last_flush_time) > 1) {
srv_main_thread_op_info = (char *) "flushing log"; srv_main_thread_op_info = (char*) "flushing log";
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
log_flush_to_disk();
last_flush_time = current_time; last_flush_time = current_time;
} }
} }
@ -2630,25 +2735,25 @@ background_loop:
/* In this loop we run background operations when the server /* In this loop we run background operations when the server
is quiet and we also come here about once in 10 seconds */ is quiet and we also come here about once in 10 seconds */
srv_main_thread_op_info = (char*) "doing background drop tables"; srv_main_thread_op_info = (char*)"doing background drop tables";
n_tables_to_drop = row_drop_tables_for_mysql_in_background(); n_tables_to_drop = row_drop_tables_for_mysql_in_background();
srv_main_thread_op_info = (char*) ""; srv_main_thread_op_info = (char*)"";
srv_main_thread_op_info = (char*) "flushing buffer pool pages"; srv_main_thread_op_info = (char*)"flushing buffer pool pages";
/* Flush a few oldest pages to make the checkpoint younger */ /* Flush a few oldest pages to make the checkpoint younger */
n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 10, ut_dulint_max); n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 10, ut_dulint_max);
srv_main_thread_op_info = (char*) "making checkpoint"; srv_main_thread_op_info = (char*)"making checkpoint";
/* Make a new checkpoint about once in 10 seconds */ /* Make a new checkpoint about once in 10 seconds */
log_checkpoint(TRUE, FALSE); log_checkpoint(TRUE, FALSE);
srv_main_thread_op_info = (char *) "reserving kernel mutex"; srv_main_thread_op_info = (char*)"reserving kernel mutex";
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) { if (srv_activity_count != old_activity_count) {
@ -2661,11 +2766,11 @@ background_loop:
/* The server has been quiet for a while: start running background /* The server has been quiet for a while: start running background
operations */ operations */
srv_main_thread_op_info = (char *) "purging"; srv_main_thread_op_info = (char*)"purging";
n_pages_purged = trx_purge(); n_pages_purged = trx_purge();
srv_main_thread_op_info = (char *) "reserving kernel mutex"; srv_main_thread_op_info = (char*)"reserving kernel mutex";
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) { if (srv_activity_count != old_activity_count) {
@ -2674,10 +2779,10 @@ background_loop:
} }
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
srv_main_thread_op_info = (char *) "doing insert buffer merge"; srv_main_thread_op_info = (char*)"doing insert buffer merge";
n_bytes_merged = ibuf_contract_for_n_pages(TRUE, 20); n_bytes_merged = ibuf_contract_for_n_pages(TRUE, 20);
srv_main_thread_op_info = (char *) "reserving kernel mutex"; srv_main_thread_op_info = (char*)"reserving kernel mutex";
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) { if (srv_activity_count != old_activity_count) {
@ -2686,10 +2791,10 @@ background_loop:
} }
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
srv_main_thread_op_info = (char *) "flushing buffer pool pages"; srv_main_thread_op_info = (char*)"flushing buffer pool pages";
n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max); n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max);
srv_main_thread_op_info = (char *) "reserving kernel mutex"; srv_main_thread_op_info = (char*)"reserving kernel mutex";
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) { if (srv_activity_count != old_activity_count) {
@ -2698,15 +2803,14 @@ background_loop:
} }
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
srv_main_thread_op_info = srv_main_thread_op_info = (char*) "waiting for buffer pool flush to end";
(char *) "waiting for buffer pool flush to end";
buf_flush_wait_batch_end(BUF_FLUSH_LIST); buf_flush_wait_batch_end(BUF_FLUSH_LIST);
srv_main_thread_op_info = (char *) "making checkpoint"; srv_main_thread_op_info = (char*)"making checkpoint";
log_checkpoint(TRUE, FALSE); log_checkpoint(TRUE, FALSE);
srv_main_thread_op_info = (char *) "reserving kernel mutex"; srv_main_thread_op_info = (char*)"reserving kernel mutex";
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) { if (srv_activity_count != old_activity_count) {
@ -2716,7 +2820,7 @@ background_loop:
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
srv_main_thread_op_info = srv_main_thread_op_info =
(char *) "archiving log (if log archive is on)"; (char*)"archiving log (if log archive is on)";
log_archive_do(FALSE, &n_bytes_archived); log_archive_do(FALSE, &n_bytes_archived);
@ -2742,7 +2846,7 @@ background_loop:
master thread to wait for more server activity */ master thread to wait for more server activity */
suspend_thread: suspend_thread:
srv_main_thread_op_info = (char *) "suspending"; srv_main_thread_op_info = (char*)"suspending";
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
@ -2756,7 +2860,7 @@ suspend_thread:
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
srv_main_thread_op_info = (char *) "waiting for server activity"; srv_main_thread_op_info = (char*)"waiting for server activity";
os_event_wait(event); os_event_wait(event);

View File

@ -433,8 +433,7 @@ Normalizes a directory path for Windows: converts slashes to backslashes. */
void void
srv_normalize_path_for_win( srv_normalize_path_for_win(
/*=======================*/ /*=======================*/
char* str __attribute__((unused))) char* str __attribute__((unused))) /* in/out: null-terminated character string */
/* in/out: null-terminated character string */
{ {
#ifdef __WIN__ #ifdef __WIN__
ulint i; ulint i;
@ -619,8 +618,7 @@ open_or_create_log_file(
if (k == 0 && i == 0) { if (k == 0 && i == 0) {
arch_space_id = 2 * k + 1 + SRV_LOG_SPACE_FIRST_ID; arch_space_id = 2 * k + 1 + SRV_LOG_SPACE_FIRST_ID;
fil_space_create((char *) "arch_log_space", arch_space_id, fil_space_create((char*) "arch_log_space", arch_space_id, FIL_LOG);
FIL_LOG);
} else { } else {
arch_space_id = ULINT_UNDEFINED; arch_space_id = ULINT_UNDEFINED;
} }
@ -839,7 +837,6 @@ open_or_create_data_files(
/********************************************************************* /*********************************************************************
This thread is used to measure contention of latches. */ This thread is used to measure contention of latches. */
#ifdef NOT_USED
static static
ulint ulint
test_measure_cont( test_measure_cont(
@ -899,7 +896,7 @@ test_measure_cont(
"Mutex res. l %lu, p %lu, k %lu s x %lu s s %lu s mut %lu of %lu\n", "Mutex res. l %lu, p %lu, k %lu s x %lu s s %lu s mut %lu of %lu\n",
lcount, pcount, kcount, s_xcount, s_scount, s_mcount, j); lcount, pcount, kcount, s_xcount, s_scount, s_mcount, j);
sync_print_wait_info(); /* sync_print_wait_info(); */
fprintf(stderr, fprintf(stderr,
"log i/o %lu n non sea %lu n succ %lu n h fail %lu\n", "log i/o %lu n non sea %lu n succ %lu n h fail %lu\n",
@ -909,7 +906,7 @@ test_measure_cont(
return(0); return(0);
} }
#endif
/******************************************************************** /********************************************************************
Starts InnoDB and creates a new database if database files Starts InnoDB and creates a new database if database files
are not found and the user wants. Server parameters are are not found and the user wants. Server parameters are
@ -935,27 +932,44 @@ innobase_start_or_create_for_mysql(void)
ulint k; ulint k;
mtr_t mtr; mtr_t mtr;
#ifdef UNIV_DEBUG
fprintf(stderr,
"InnoDB: !!!!!!!!!!!!!! UNIV_DEBUG switched on !!!!!!!!!!!!!!!\n");
#endif
#ifdef UNIV_SYNC_DEBUG
fprintf(stderr,
"InnoDB: !!!!!!!!!!!!!! UNIV_SYNC_DEBUG switched on !!!!!!!!!!!!!!!\n");
#endif
#ifdef UNIV_SEARCH_DEBUG
fprintf(stderr,
"InnoDB: !!!!!!!!!!!!!! UNIV_SEARCH_DEBUG switched on !!!!!!!!!!!!!!!\n");
#endif
#ifdef UNIV_MEM_DEBUG
fprintf(stderr,
"InnoDB: !!!!!!!!!!!!!! UNIV_MEM_DEBUG switched on !!!!!!!!!!!!!!!\n");
#endif
log_do_write = TRUE; log_do_write = TRUE;
/* yydebug = TRUE; */ /* yydebug = TRUE; */
srv_is_being_started = TRUE; srv_is_being_started = TRUE;
srv_startup_is_before_trx_rollback_phase = TRUE; srv_startup_is_before_trx_rollback_phase = TRUE;
if (0 == ut_strcmp(srv_unix_file_flush_method_str, if (0 == ut_strcmp(srv_unix_file_flush_method_str, "fdatasync")) {
(char *) "fdatasync")) { srv_unix_file_flush_method = SRV_UNIX_FDATASYNC;
srv_unix_file_flush_method = SRV_UNIX_FDATASYNC;
} else if (0 == ut_strcmp(srv_unix_file_flush_method_str, "O_DSYNC")) {
srv_unix_file_flush_method = SRV_UNIX_O_DSYNC;
} else if (0 == ut_strcmp(srv_unix_file_flush_method_str, } else if (0 == ut_strcmp(srv_unix_file_flush_method_str,
(char *) "O_DSYNC")) { "littlesync")) {
srv_unix_file_flush_method = SRV_UNIX_O_DSYNC; srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC;
} else if (0 == ut_strcmp(srv_unix_file_flush_method_str, } else if (0 == ut_strcmp(srv_unix_file_flush_method_str, "nosync")) {
(char *) "littlesync")) { srv_unix_file_flush_method = SRV_UNIX_NOSYNC;
srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC;
} else if (0 == ut_strcmp(srv_unix_file_flush_method_str,
(char *) "nosync")) {
srv_unix_file_flush_method = SRV_UNIX_NOSYNC;
} else { } else {
fprintf(stderr, fprintf(stderr,
"InnoDB: Unrecognized value %s for innodb_flush_method\n", "InnoDB: Unrecognized value %s for innodb_flush_method\n",
@ -1005,7 +1019,7 @@ innobase_start_or_create_for_mysql(void)
os_aio_use_native_aio = FALSE; os_aio_use_native_aio = FALSE;
if (!os_aio_use_native_aio) { if (!os_aio_use_native_aio) {
os_aio_init(4 * SRV_N_PENDING_IOS_PER_THREAD os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD
* srv_n_file_io_threads, * srv_n_file_io_threads,
srv_n_file_io_threads, srv_n_file_io_threads,
SRV_MAX_N_PENDING_SYNC_IOS); SRV_MAX_N_PENDING_SYNC_IOS);
@ -1350,9 +1364,15 @@ innobase_shutdown_for_mysql(void)
"InnoDB: inside InnoDB at shutdown\n", "InnoDB: inside InnoDB at shutdown\n",
srv_conc_n_threads); srv_conc_n_threads);
} }
/*
TODO: We should exit the i/o-handler and other utility threads
before freeing all memory. Now this can potentially cause a seg
fault!
*/
#ifdef NOT_WORKING_YET #ifdef NOT_WORKING_YET
ut_free_all_mem(); ut_free_all_mem();
#endif #endif
return((int) DB_SUCCESS); return((int) DB_SUCCESS);
} }

View File

@ -441,7 +441,8 @@ static
void void
sync_array_cell_print( sync_array_cell_print(
/*==================*/ /*==================*/
FILE* file, /* in: file where to print */ char* buf, /* in: buffer where to print, must be
at least 400 characters */
sync_cell_t* cell) /* in: sync cell */ sync_cell_t* cell) /* in: sync cell */
{ {
mutex_t* mutex; mutex_t* mutex;
@ -451,7 +452,7 @@ sync_array_cell_print(
type = cell->request_type; type = cell->request_type;
fprintf(file, buf += sprintf(buf,
"--Thread %lu has waited at %s line %lu for %.2f seconds the semaphore:\n", "--Thread %lu has waited at %s line %lu for %.2f seconds the semaphore:\n",
(ulint)cell->thread, cell->file, cell->line, (ulint)cell->thread, cell->file, cell->line,
difftime(time(NULL), cell->reservation_time)); difftime(time(NULL), cell->reservation_time));
@ -461,54 +462,58 @@ sync_array_cell_print(
been freed meanwhile */ been freed meanwhile */
mutex = cell->old_wait_mutex; mutex = cell->old_wait_mutex;
fprintf(file, buf += sprintf(buf,
"Mutex at %lx created file %s line %lu, lock var %lu\n", "Mutex at %lx created file %s line %lu, lock var %lu\n",
(ulint)mutex, mutex->cfile_name, mutex->cline, (ulint)mutex, mutex->cfile_name, mutex->cline,
mutex->lock_word); mutex->lock_word);
fprintf(file, buf += sprintf(buf,
"Last time reserved in file %s line %lu, waiters flag %lu\n", "Last time reserved in file %s line %lu, waiters flag %lu\n",
mutex->file_name, mutex->line, mutex->waiters); mutex->file_name, mutex->line, mutex->waiters);
} else if (type == RW_LOCK_EX || type == RW_LOCK_SHARED) { } else if (type == RW_LOCK_EX || type == RW_LOCK_SHARED) {
if (type == RW_LOCK_EX) { if (type == RW_LOCK_EX) {
fprintf(file, "X-lock on"); buf += sprintf(buf, "X-lock on");
} else { } else {
fprintf(file, "S-lock on"); buf += sprintf(buf, "S-lock on");
} }
rwlock = cell->old_wait_rw_lock; rwlock = cell->old_wait_rw_lock;
fprintf(file, " RW-latch at %lx created in file %s line %lu\n", buf += sprintf(buf,
" RW-latch at %lx created in file %s line %lu\n",
(ulint)rwlock, rwlock->cfile_name, rwlock->cline); (ulint)rwlock, rwlock->cfile_name, rwlock->cline);
if (rwlock->writer != RW_LOCK_NOT_LOCKED) { if (rwlock->writer != RW_LOCK_NOT_LOCKED) {
fprintf(file, buf += sprintf(buf,
"a writer (thread id %lu) has reserved it in mode", "a writer (thread id %lu) has reserved it in mode",
(ulint)rwlock->writer_thread); (ulint)rwlock->writer_thread);
if (rwlock->writer == RW_LOCK_EX) { if (rwlock->writer == RW_LOCK_EX) {
fprintf(file, " exclusive\n"); buf += sprintf(buf, " exclusive\n");
} else { } else {
fprintf(file, " wait exclusive\n"); buf += sprintf(buf, " wait exclusive\n");
} }
} }
fprintf(file, "number of readers %lu, waiters flag %lu\n", buf += sprintf(buf,
"number of readers %lu, waiters flag %lu\n",
rwlock->reader_count, rwlock->waiters); rwlock->reader_count, rwlock->waiters);
fprintf(file, "Last time read locked in file %s line %lu\n", buf += sprintf(buf,
"Last time read locked in file %s line %lu\n",
rwlock->last_s_file_name, rwlock->last_s_line); rwlock->last_s_file_name, rwlock->last_s_line);
fprintf(file, "Last time write locked in file %s line %lu\n", buf += sprintf(buf,
"Last time write locked in file %s line %lu\n",
rwlock->last_x_file_name, rwlock->last_x_line); rwlock->last_x_file_name, rwlock->last_x_line);
} else { } else {
ut_error; ut_error;
} }
if (!cell->waiting) { if (!cell->waiting) {
fprintf(file, "wait has ended\n"); buf += sprintf(buf, "wait has ended\n");
} }
if (cell->event_set) { if (cell->event_set) {
fprintf(file, "wait is ending\n"); buf += sprintf(buf, "wait is ending\n");
} }
} }
@ -610,6 +615,7 @@ sync_array_detect_deadlock(
os_thread_id_t thread; os_thread_id_t thread;
ibool ret; ibool ret;
rw_lock_debug_t* debug; rw_lock_debug_t* debug;
char buf[500];
ut_a(arr && start && cell); ut_a(arr && start && cell);
ut_ad(cell->wait_object); ut_ad(cell->wait_object);
@ -642,11 +648,12 @@ sync_array_detect_deadlock(
ret = sync_array_deadlock_step(arr, start, thread, 0, ret = sync_array_deadlock_step(arr, start, thread, 0,
depth); depth);
if (ret) { if (ret) {
sync_array_cell_print(buf, cell);
printf( printf(
"Mutex %lx owned by thread %lu file %s line %lu\n", "Mutex %lx owned by thread %lu file %s line %lu\n%s",
(ulint)mutex, mutex->thread_id, (ulint)mutex, mutex->thread_id,
mutex->file_name, mutex->line); mutex->file_name, mutex->line,
sync_array_cell_print(stdout, cell); buf);
return(TRUE); return(TRUE);
} }
} }
@ -678,9 +685,9 @@ sync_array_detect_deadlock(
debug->pass, debug->pass,
depth); depth);
if (ret) { if (ret) {
printf("rw-lock %lx ", (ulint) lock); sync_array_cell_print(buf, cell);
printf("rw-lock %lx %s ", (ulint) lock, buf);
rw_lock_debug_print(debug); rw_lock_debug_print(debug);
sync_array_cell_print(stdout, cell);
return(TRUE); return(TRUE);
} }
@ -711,9 +718,9 @@ sync_array_detect_deadlock(
debug->pass, debug->pass,
depth); depth);
if (ret) { if (ret) {
printf("rw-lock %lx ", (ulint) lock); sync_array_cell_print(buf, cell);
printf("rw-lock %lx %s ", (ulint) lock, buf);
rw_lock_debug_print(debug); rw_lock_debug_print(debug);
sync_array_cell_print(stdout, cell);
return(TRUE); return(TRUE);
} }
@ -898,6 +905,7 @@ sync_array_print_long_waits(void)
sync_cell_t* cell; sync_cell_t* cell;
ibool old_val; ibool old_val;
ibool noticed = FALSE; ibool noticed = FALSE;
char buf[500];
ulint i; ulint i;
for (i = 0; i < sync_primary_wait_array->n_cells; i++) { for (i = 0; i < sync_primary_wait_array->n_cells; i++) {
@ -907,9 +915,10 @@ sync_array_print_long_waits(void)
if (cell->wait_object != NULL if (cell->wait_object != NULL
&& difftime(time(NULL), cell->reservation_time) > 240) { && difftime(time(NULL), cell->reservation_time) > 240) {
sync_array_cell_print(buf, cell);
fprintf(stderr, fprintf(stderr,
"InnoDB: Warning: a long semaphore wait:\n"); "InnoDB: Warning: a long semaphore wait:\n%s", buf);
sync_array_cell_print(stderr, cell);
noticed = TRUE; noticed = TRUE;
} }
@ -948,6 +957,8 @@ static
void void
sync_array_output_info( sync_array_output_info(
/*===================*/ /*===================*/
char* buf, /* in/out: buffer where to print */
char* buf_end,/* in: buffer end */
sync_array_t* arr) /* in: wait array; NOTE! caller must own the sync_array_t* arr) /* in: wait array; NOTE! caller must own the
mutex */ mutex */
{ {
@ -955,18 +966,29 @@ sync_array_output_info(
ulint count; ulint count;
ulint i; ulint i;
printf("OS WAIT ARRAY INFO: reservation count %ld, signal count %ld\n", if (buf_end - buf < 500) {
return;
}
buf += sprintf(buf,
"OS WAIT ARRAY INFO: reservation count %ld, signal count %ld\n",
arr->res_count, arr->sg_count); arr->res_count, arr->sg_count);
i = 0; i = 0;
count = 0; count = 0;
while (count < arr->n_reserved) { while (count < arr->n_reserved) {
if (buf_end - buf < 500) {
return;
}
cell = sync_array_get_nth_cell(arr, i); cell = sync_array_get_nth_cell(arr, i);
if (cell->wait_object != NULL) { if (cell->wait_object != NULL) {
count++; count++;
sync_array_cell_print(stdout, cell); sync_array_cell_print(buf, cell);
buf = buf + strlen(buf);
} }
i++; i++;
@ -979,11 +1001,13 @@ Prints info of the wait array. */
void void
sync_array_print_info( sync_array_print_info(
/*==================*/ /*==================*/
char* buf, /* in/out: buffer where to print */
char* buf_end,/* in: buffer end */
sync_array_t* arr) /* in: wait array */ sync_array_t* arr) /* in: wait array */
{ {
sync_array_enter(arr); sync_array_enter(arr);
sync_array_output_info(arr); sync_array_output_info(buf, buf_end, arr);
sync_array_exit(arr); sync_array_exit(arr);
} }

View File

@ -874,6 +874,7 @@ sync_thread_levels_empty_gen(
sync_level_t* slot; sync_level_t* slot;
rw_lock_t* lock; rw_lock_t* lock;
mutex_t* mutex; mutex_t* mutex;
char* buf;
ulint i; ulint i;
if (!sync_order_checks_on) { if (!sync_order_checks_on) {
@ -907,7 +908,9 @@ sync_thread_levels_empty_gen(
mutex = slot->latch; mutex = slot->latch;
mutex_exit(&sync_thread_mutex); mutex_exit(&sync_thread_mutex);
sync_print(); buf = mem_alloc(20000);
sync_print(buf, buf + 18000);
ut_error; ut_error;
return(FALSE); return(FALSE);
@ -1243,14 +1246,21 @@ sync_close(void)
Prints wait info of the sync system. */ Prints wait info of the sync system. */
void void
sync_print_wait_info(void) sync_print_wait_info(
/*======================*/ /*=================*/
char* buf, /* in/out: buffer where to print */
char* buf_end) /* in: buffer end */
{ {
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
printf("Mutex exits %lu, rws exits %lu, rwx exits %lu\n", printf("Mutex exits %lu, rws exits %lu, rwx exits %lu\n",
mutex_exit_count, rw_s_exit_count, rw_x_exit_count); mutex_exit_count, rw_s_exit_count, rw_x_exit_count);
#endif #endif
printf( if (buf_end - buf < 500) {
return;
}
sprintf(buf,
"Mutex spin waits %lu, rounds %lu, OS waits %lu\n" "Mutex spin waits %lu, rounds %lu, OS waits %lu\n"
"RW-shared spins %lu, OS waits %lu; RW-excl spins %lu, OS waits %lu\n", "RW-shared spins %lu, OS waits %lu; RW-excl spins %lu, OS waits %lu\n",
mutex_spin_wait_count, mutex_spin_round_count, mutex_spin_wait_count, mutex_spin_round_count,
@ -1263,11 +1273,18 @@ sync_print_wait_info(void)
Prints info of the sync system. */ Prints info of the sync system. */
void void
sync_print(void) sync_print(
/*============*/ /*=======*/
char* buf, /* in/out: buffer where to print */
char* buf_end) /* in: buffer end */
{ {
mutex_list_print_info(); mutex_list_print_info();
rw_lock_list_print_info(); rw_lock_list_print_info();
sync_array_print_info(sync_primary_wait_array);
sync_print_wait_info(); sync_array_print_info(buf, buf_end, sync_primary_wait_array);
buf = buf + strlen(buf);
sync_print_wait_info(buf, buf_end);
} }

View File

@ -160,11 +160,13 @@ trx_rollback_last_sql_stat_for_mysql(
} }
/*********************************************************************** /***********************************************************************
Rollback uncommitted transactions which have no user session. */ Rollback or clean up transactions which have no user session. If the
transaction already was committed, then we clean up a possible insert
undo log. If the transaction was not yet committed, then we roll it back. */
void void
trx_rollback_all_without_sess(void) trx_rollback_or_clean_all_without_sess(void)
/*===============================*/ /*========================================*/
{ {
mem_heap_t* heap; mem_heap_t* heap;
que_fork_t* fork; que_fork_t* fork;
@ -217,6 +219,19 @@ loop:
trx->sess = trx_dummy_sess; trx->sess = trx_dummy_sess;
if (trx->conc_state == TRX_COMMITTED_IN_MEMORY) {
fprintf(stderr, "InnoDB: Cleaning up trx with id %lu %lu\n",
ut_dulint_get_high(trx->id),
ut_dulint_get_low(trx->id));
trx_cleanup_at_db_startup(trx);
mem_heap_free(heap);
goto loop;
}
fork = que_fork_create(NULL, NULL, QUE_FORK_RECOVERY, heap); fork = que_fork_create(NULL, NULL, QUE_FORK_RECOVERY, heap);
fork->trx = trx; fork->trx = trx;
@ -264,9 +279,17 @@ loop:
/* If the transaction was for a dictionary operation, we /* If the transaction was for a dictionary operation, we
drop the relevant table, if it still exists */ drop the relevant table, if it still exists */
fprintf(stderr,
"InnoDB: Dropping table with id %lu %lu in recovery if it exists\n",
ut_dulint_get_high(trx->table_id),
ut_dulint_get_low(trx->table_id));
table = dict_table_get_on_id_low(trx->table_id, trx); table = dict_table_get_on_id_low(trx->table_id, trx);
if (table) { if (table) {
fprintf(stderr,
"InnoDB: Table found: dropping table %s in recovery\n", table->name);
err = row_drop_table_for_mysql(table->name, trx, err = row_drop_table_for_mysql(table->name, trx,
TRUE); TRUE);
ut_a(err == (int) DB_SUCCESS); ut_a(err == (int) DB_SUCCESS);

View File

@ -26,6 +26,14 @@ Created 3/26/1996 Heikki Tuuri
trx_sys_t* trx_sys = NULL; trx_sys_t* trx_sys = NULL;
trx_doublewrite_t* trx_doublewrite = NULL; trx_doublewrite_t* trx_doublewrite = NULL;
/* In a MySQL replication slave, in crash recovery we store the master log
file name and position here. We have successfully got the updates to InnoDB
up to this position. If .._pos is -1, it means no crash recovery was needed,
or there was no master log position info inside InnoDB. */
char trx_sys_mysql_master_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
ib_longlong trx_sys_mysql_master_log_pos = -1;
/******************************************************************** /********************************************************************
Determines if a page number is located inside the doublewrite buffer. */ Determines if a page number is located inside the doublewrite buffer. */
@ -427,75 +435,62 @@ trx_sys_flush_max_trx_id(void)
/********************************************************************* /*********************************************************************
Updates the offset information about the end of the MySQL binlog entry Updates the offset information about the end of the MySQL binlog entry
which corresponds to the transaction just being committed. */ which corresponds to the transaction just being committed. In a MySQL
replication slave updates the latest master binlog position up to which
replication has proceeded. */
void void
trx_sys_update_mysql_binlog_offset( trx_sys_update_mysql_binlog_offset(
/*===============================*/ /*===============================*/
trx_t* trx, /* in: transaction being committed */ char* file_name,/* in: MySQL log file name */
mtr_t* mtr) /* in: mtr */ ib_longlong offset, /* in: position in that log file */
ulint field, /* in: offset of the MySQL log info field in
the trx sys header */
mtr_t* mtr) /* in: mtr */
{ {
trx_sysf_t* sys_header; trx_sysf_t* sys_header;
char namebuf[TRX_SYS_MYSQL_LOG_NAME_LEN];
ut_ad(trx->mysql_log_file_name);
memset(namebuf, ' ', TRX_SYS_MYSQL_LOG_NAME_LEN - 1); if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) {
namebuf[TRX_SYS_MYSQL_LOG_NAME_LEN - 1] = '\0';
/* Copy the whole MySQL log file name to the buffer, or only the /* We cannot fit the name to the 512 bytes we have reserved */
last characters, if it does not fit */
if (ut_strlen(trx->mysql_log_file_name) return;
> TRX_SYS_MYSQL_LOG_NAME_LEN - 1) {
ut_memcpy(namebuf, trx->mysql_log_file_name
+ ut_strlen(trx->mysql_log_file_name)
- (TRX_SYS_MYSQL_LOG_NAME_LEN - 1),
TRX_SYS_MYSQL_LOG_NAME_LEN - 1);
} else {
ut_memcpy(namebuf, trx->mysql_log_file_name,
1 + ut_strlen(trx->mysql_log_file_name));
} }
namebuf[TRX_SYS_MYSQL_LOG_NAME_LEN - 1] = '\0';
sys_header = trx_sysf_get(mtr); sys_header = trx_sysf_get(mtr);
if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO if (mach_read_from_4(sys_header + field
+ TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
!= TRX_SYS_MYSQL_LOG_MAGIC_N) { != TRX_SYS_MYSQL_LOG_MAGIC_N) {
mlog_write_ulint(sys_header + TRX_SYS_MYSQL_LOG_INFO mlog_write_ulint(sys_header + field
+ TRX_SYS_MYSQL_LOG_MAGIC_N_FLD, + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD,
TRX_SYS_MYSQL_LOG_MAGIC_N, TRX_SYS_MYSQL_LOG_MAGIC_N,
MLOG_4BYTES, mtr); MLOG_4BYTES, mtr);
} }
if (0 != ut_memcmp(sys_header + TRX_SYS_MYSQL_LOG_INFO if (0 != ut_memcmp(sys_header + field + TRX_SYS_MYSQL_LOG_NAME,
+ TRX_SYS_MYSQL_LOG_NAME, file_name, 1 + ut_strlen(file_name))) {
namebuf, TRX_SYS_MYSQL_LOG_NAME_LEN)) {
mlog_write_string(sys_header + TRX_SYS_MYSQL_LOG_INFO mlog_write_string(sys_header + field
+ TRX_SYS_MYSQL_LOG_NAME, + TRX_SYS_MYSQL_LOG_NAME,
namebuf, TRX_SYS_MYSQL_LOG_NAME_LEN, mtr); file_name, 1 + ut_strlen(file_name), mtr);
} }
if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO if (mach_read_from_4(sys_header + field
+ TRX_SYS_MYSQL_LOG_OFFSET_HIGH) > 0 + TRX_SYS_MYSQL_LOG_OFFSET_HIGH) > 0
|| (trx->mysql_log_offset >> 32) > 0) { || (offset >> 32) > 0) {
mlog_write_ulint(sys_header + TRX_SYS_MYSQL_LOG_INFO mlog_write_ulint(sys_header + field
+ TRX_SYS_MYSQL_LOG_OFFSET_HIGH, + TRX_SYS_MYSQL_LOG_OFFSET_HIGH,
(ulint)(trx->mysql_log_offset >> 32), (ulint)(offset >> 32),
MLOG_4BYTES, mtr); MLOG_4BYTES, mtr);
} }
mlog_write_ulint(sys_header + TRX_SYS_MYSQL_LOG_INFO mlog_write_ulint(sys_header + field
+ TRX_SYS_MYSQL_LOG_OFFSET_LOW, + TRX_SYS_MYSQL_LOG_OFFSET_LOW,
(ulint)(trx->mysql_log_offset & 0xFFFFFFFF), (ulint)(offset & 0xFFFFFFFF),
MLOG_4BYTES, mtr); MLOG_4BYTES, mtr);
trx->mysql_log_file_name = NULL;
} }
/********************************************************************* /*********************************************************************
@ -533,6 +528,58 @@ trx_sys_print_mysql_binlog_offset(void)
mtr_commit(&mtr); mtr_commit(&mtr);
} }
/*********************************************************************
Prints to stderr the MySQL master log offset info in the trx system header if
the magic number shows it valid. */
void
trx_sys_print_mysql_master_log_pos(void)
/*====================================*/
{
trx_sysf_t* sys_header;
mtr_t mtr;
mtr_start(&mtr);
sys_header = trx_sysf_get(&mtr);
if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
+ TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
!= TRX_SYS_MYSQL_LOG_MAGIC_N) {
mtr_commit(&mtr);
return;
}
fprintf(stderr,
"InnoDB: In a MySQL replication slave the last master binlog file\n"
"InnoDB: position %lu %lu, file name %s\n",
mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
+ TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
+ TRX_SYS_MYSQL_LOG_OFFSET_LOW),
sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
+ TRX_SYS_MYSQL_LOG_NAME);
/* Copy the master log position info to global variables we can
use in ha_innobase.cc to initialize glob_mi to right values */
ut_memcpy(trx_sys_mysql_master_log_name,
sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
+ TRX_SYS_MYSQL_LOG_NAME,
TRX_SYS_MYSQL_LOG_NAME_LEN);
trx_sys_mysql_master_log_pos =
(((ib_longlong)mach_read_from_4(
sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
+ TRX_SYS_MYSQL_LOG_OFFSET_HIGH))
<< 32)
+ (ib_longlong)
mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
+ TRX_SYS_MYSQL_LOG_OFFSET_LOW);
mtr_commit(&mtr);
}
/******************************************************************** /********************************************************************
Looks for a free slot for a rollback segment in the trx system file copy. */ Looks for a free slot for a rollback segment in the trx system file copy. */
@ -660,7 +707,7 @@ trx_sys_init_at_db_start(void)
if (UT_LIST_GET_LEN(trx_sys->trx_list) > 0) { if (UT_LIST_GET_LEN(trx_sys->trx_list) > 0) {
fprintf(stderr, fprintf(stderr,
"InnoDB: %lu uncommitted transaction(s) which must be rolled back\n", "InnoDB: %lu transaction(s) which must be rolled back or cleaned up\n",
UT_LIST_GET_LEN(trx_sys->trx_list)); UT_LIST_GET_LEN(trx_sys->trx_list));
fprintf(stderr, "InnoDB: Trx id counter is %lu %lu\n", fprintf(stderr, "InnoDB: Trx id counter is %lu %lu\n",

View File

@ -26,9 +26,11 @@ Created 3/26/1996 Heikki Tuuri
/* Copy of the prototype for innobase_mysql_print_thd: this /* Copy of the prototype for innobase_mysql_print_thd: this
copy must be equal to the one in mysql/sql/ha_innobase.cc ! */ copy MUST be equal to the one in mysql/sql/ha_innobase.cc ! */
void innobase_mysql_print_thd(void* thd); void innobase_mysql_print_thd(
char* buf,
void* thd);
/* Dummy session used currently in MySQL interface */ /* Dummy session used currently in MySQL interface */
sess_t* trx_dummy_sess = NULL; sess_t* trx_dummy_sess = NULL;
@ -83,6 +85,8 @@ trx_create(
trx->mysql_log_file_name = NULL; trx->mysql_log_file_name = NULL;
trx->mysql_log_offset = 0; trx->mysql_log_offset = 0;
trx->mysql_master_log_file_name = "";
trx->mysql_master_log_pos = 0;
trx->ignore_duplicates_in_insert = FALSE; trx->ignore_duplicates_in_insert = FALSE;
@ -363,16 +367,31 @@ trx_lists_init_at_db_start(void)
trx = trx_create(NULL); trx = trx_create(NULL);
trx->id = undo->trx_id;
trx->insert_undo = undo;
trx->rseg = rseg;
if (undo->state != TRX_UNDO_ACTIVE) { if (undo->state != TRX_UNDO_ACTIVE) {
trx->conc_state = TRX_COMMITTED_IN_MEMORY; trx->conc_state = TRX_COMMITTED_IN_MEMORY;
/* We give a dummy value for the trx no;
this should have no relevance since purge
is not interested in committed transaction
numbers, unless they are in the history
list, in which case it looks the number
from the disk based undo log structure */
trx->no = trx->id;
} else { } else {
trx->conc_state = TRX_ACTIVE; trx->conc_state = TRX_ACTIVE;
}
trx->id = undo->trx_id; /* A running transaction always has the number
trx->insert_undo = undo; field inited to ut_dulint_max */
trx->rseg = rseg;
trx->no = ut_dulint_max;
}
if (undo->dict_operation) { if (undo->dict_operation) {
trx->dict_operation = undo->dict_operation; trx->dict_operation = undo->dict_operation;
@ -397,14 +416,25 @@ trx_lists_init_at_db_start(void)
if (NULL == trx) { if (NULL == trx) {
trx = trx_create(NULL); trx = trx_create(NULL);
trx->id = undo->trx_id;
if (undo->state != TRX_UNDO_ACTIVE) { if (undo->state != TRX_UNDO_ACTIVE) {
trx->conc_state = trx->conc_state =
TRX_COMMITTED_IN_MEMORY; TRX_COMMITTED_IN_MEMORY;
/* We give a dummy value for the trx
number */
trx->no = trx->id;
} else { } else {
trx->conc_state = TRX_ACTIVE; trx->conc_state = TRX_ACTIVE;
/* A running transaction always has
the number field inited to
ut_dulint_max */
trx->no = ut_dulint_max;
} }
trx->id = undo->trx_id;
trx->rseg = rseg; trx->rseg = rseg;
trx_list_insert_ordered(trx); trx_list_insert_ordered(trx);
@ -583,7 +613,7 @@ trx_commit_off_kernel(
if (undo) { if (undo) {
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
#ifdef notdefined #ifdef notdefined
/* ########## There is a bug here: purge and rollback /* !!!!!!!!! There is a bug here: purge and rollback
need the whole stack of old record versions even if no need the whole stack of old record versions even if no
consistent read would need them!! This is because they consistent read would need them!! This is because they
decide on the basis of the old versions when we can decide on the basis of the old versions when we can
@ -627,12 +657,25 @@ trx_commit_off_kernel(
mutex_exit(&(rseg->mutex)); mutex_exit(&(rseg->mutex));
/* Update the latest MySQL binlog name and offset info /* Update the latest MySQL binlog name and offset info
in trx sys header if MySQL binlogging is on */ in trx sys header if MySQL binlogging is on or the database
server is a MySQL replication slave */
if (trx->mysql_log_file_name) { if (trx->mysql_log_file_name) {
trx_sys_update_mysql_binlog_offset(trx, &mtr); trx_sys_update_mysql_binlog_offset(
trx->mysql_log_file_name,
trx->mysql_log_offset,
TRX_SYS_MYSQL_LOG_INFO, &mtr);
trx->mysql_log_file_name = NULL;
} }
if (trx->mysql_master_log_file_name[0] != '\0') {
/* This database server is a MySQL replication slave */
trx_sys_update_mysql_binlog_offset(
trx->mysql_master_log_file_name,
trx->mysql_master_log_pos,
TRX_SYS_MYSQL_MASTER_LOG_INFO, &mtr);
}
/* If we did not take the shortcut, the following call /* If we did not take the shortcut, the following call
commits the mini-transaction, making the whole transaction commits the mini-transaction, making the whole transaction
committed in the file-based world at this log sequence number; committed in the file-based world at this log sequence number;
@ -707,12 +750,12 @@ trx_commit_off_kernel(
/*-------------------------------------*/ /*-------------------------------------*/
/* Most MySQL users run with srv_flush.. set to FALSE: */ /* Most MySQL users run with srv_flush_.. set to FALSE: */
if (srv_flush_log_at_trx_commit) { if (srv_flush_log_at_trx_commit) {
log_flush_up_to(lsn, LOG_WAIT_ONE_GROUP); log_flush_up_to(lsn, LOG_WAIT_ONE_GROUP);
} }
/*-------------------------------------*/ /*-------------------------------------*/
@ -730,6 +773,29 @@ trx_commit_off_kernel(
UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx); UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
} }
/********************************************************************
Cleans up a transaction at database startup. The cleanup is needed if
the transaction already got to the middle of a commit when the database
crashed, andf we cannot roll it back. */
void
trx_cleanup_at_db_startup(
/*======================*/
trx_t* trx) /* in: transaction */
{
if (trx->insert_undo != NULL) {
trx_undo_insert_cleanup(trx);
}
trx->conc_state = TRX_NOT_STARTED;
trx->rseg = NULL;
trx->undo_no = ut_dulint_zero;
trx->last_sql_stat_start.least_undo_no = ut_dulint_zero;
UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
}
/************************************************************************ /************************************************************************
Assigns a read view for a consistent read query. All the consistent reads Assigns a read view for a consistent read query. All the consistent reads
within the same transaction will get the same read view, which is created within the same transaction will get the same read view, which is created
@ -1395,54 +1461,63 @@ own the kernel mutex. */
void void
trx_print( trx_print(
/*======*/ /*======*/
char* buf, /* in/out: buffer where to print, must be at least
500 bytes */
trx_t* trx) /* in: transaction */ trx_t* trx) /* in: transaction */
{ {
printf("TRANSACTION %lu %lu, OS thread id %lu", buf += sprintf(buf, "TRANSACTION %lu %lu, OS thread id %lu",
ut_dulint_get_high(trx->id), ut_dulint_get_high(trx->id),
ut_dulint_get_low(trx->id), ut_dulint_get_low(trx->id),
(ulint)trx->mysql_thread_id); (ulint)trx->mysql_thread_id);
if (ut_strlen(trx->op_info) > 0) { if (ut_strlen(trx->op_info) > 0) {
printf(" %s", trx->op_info); buf += sprintf(buf, " %s", trx->op_info);
} }
if (trx->type != TRX_USER) { if (trx->type != TRX_USER) {
printf(" purge trx"); buf += sprintf(buf, " purge trx");
} }
switch (trx->conc_state) { switch (trx->conc_state) {
case TRX_NOT_STARTED: printf(", not started"); break; case TRX_NOT_STARTED: buf += sprintf(buf,
case TRX_ACTIVE: printf(", active"); break; ", not started"); break;
case TRX_COMMITTED_IN_MEMORY: printf(", committed in memory"); case TRX_ACTIVE: buf += sprintf(buf,
", active"); break;
case TRX_COMMITTED_IN_MEMORY: buf += sprintf(buf,
", committed in memory");
break; break;
default: printf(" state %lu", trx->conc_state); default: buf += sprintf(buf, " state %lu", trx->conc_state);
} }
switch (trx->que_state) { switch (trx->que_state) {
case TRX_QUE_RUNNING: printf(", runs or sleeps"); break; case TRX_QUE_RUNNING: buf += sprintf(buf,
case TRX_QUE_LOCK_WAIT: printf(", lock wait"); break; ", runs or sleeps"); break;
case TRX_QUE_ROLLING_BACK: printf(", rolling back"); break; case TRX_QUE_LOCK_WAIT: buf += sprintf(buf,
case TRX_QUE_COMMITTING: printf(", committing"); break; ", lock wait"); break;
default: printf(" que state %lu", trx->que_state); case TRX_QUE_ROLLING_BACK: buf += sprintf(buf,
", rolling back"); break;
case TRX_QUE_COMMITTING: buf += sprintf(buf,
", committing"); break;
default: buf += sprintf(buf, " que state %lu", trx->que_state);
} }
if (0 < UT_LIST_GET_LEN(trx->trx_locks)) { if (0 < UT_LIST_GET_LEN(trx->trx_locks)) {
printf(", has %lu lock struct(s)", buf += sprintf(buf, ", has %lu lock struct(s)",
UT_LIST_GET_LEN(trx->trx_locks)); UT_LIST_GET_LEN(trx->trx_locks));
} }
if (trx->has_search_latch) { if (trx->has_search_latch) {
printf(", holds adaptive hash latch"); buf += sprintf(buf, ", holds adaptive hash latch");
} }
if (ut_dulint_cmp(trx->undo_no, ut_dulint_zero) != 0) { if (ut_dulint_cmp(trx->undo_no, ut_dulint_zero) != 0) {
printf(", undo log entries %lu", buf += sprintf(buf, ", undo log entries %lu",
ut_dulint_get_low(trx->undo_no)); ut_dulint_get_low(trx->undo_no));
} }
printf("\n"); buf += sprintf(buf, "\n");
if (trx->mysql_thd != NULL) { if (trx->mysql_thd != NULL) {
innobase_mysql_print_thd(trx->mysql_thd); innobase_mysql_print_thd(buf, trx->mysql_thd);
} }
} }

View File

@ -1147,7 +1147,7 @@ trx_undo_mem_create_at_db_start(
/* If the log segment is being freed, the page list is inconsistent! */ /* If the log segment is being freed, the page list is inconsistent! */
if (state == TRX_UNDO_TO_FREE) { if (state == TRX_UNDO_TO_FREE) {
return(undo); goto add_to_list;
} }
last_addr = flst_get_last(seg_header + TRX_UNDO_PAGE_LIST, mtr); last_addr = flst_get_last(seg_header + TRX_UNDO_PAGE_LIST, mtr);
@ -1166,7 +1166,7 @@ trx_undo_mem_create_at_db_start(
undo->top_offset = rec - last_page; undo->top_offset = rec - last_page;
undo->top_undo_no = trx_undo_rec_get_undo_no(rec); undo->top_undo_no = trx_undo_rec_get_undo_no(rec);
} }
add_to_list:
if (type == TRX_UNDO_INSERT) { if (type == TRX_UNDO_INSERT) {
if (state != TRX_UNDO_CACHED) { if (state != TRX_UNDO_CACHED) {
UT_LIST_ADD_LAST(undo_list, rseg->insert_undo_list, UT_LIST_ADD_LAST(undo_list, rseg->insert_undo_list,

View File

@ -38,6 +38,8 @@ os_fast_mutex_t ut_list_mutex; /* this protects the list */
ibool ut_mem_block_list_inited = FALSE; ibool ut_mem_block_list_inited = FALSE;
ulint* ut_mem_null_ptr = NULL;
/************************************************************************** /**************************************************************************
Initializes the mem block list at database startup. */ Initializes the mem block list at database startup. */
static static
@ -83,12 +85,16 @@ ut_malloc_low(
"InnoDB: Check if you should increase the swap file or\n" "InnoDB: Check if you should increase the swap file or\n"
"InnoDB: ulimits of your operating system.\n" "InnoDB: ulimits of your operating system.\n"
"InnoDB: On FreeBSD check you have compiled the OS with\n" "InnoDB: On FreeBSD check you have compiled the OS with\n"
"InnoDB: a big enough maximum process size.\n", "InnoDB: a big enough maximum process size.\n"
"InnoDB: We now intentionally generate a seg fault so that\n"
"InnoDB: on Linux we get a stack trace.\n",
n, ut_total_allocated_memory, errno); n, ut_total_allocated_memory, errno);
os_fast_mutex_unlock(&ut_list_mutex); os_fast_mutex_unlock(&ut_list_mutex);
exit(1); /* Make an intentional seg fault so that we get a stack
trace */
printf("%lu\n", *ut_mem_null_ptr);
} }
if (set_to_zero) { if (set_to_zero) {

View File

@ -110,6 +110,49 @@ ut_print_timestamp(
#endif #endif
} }
/**************************************************************
Sprintfs a timestamp to a buffer. */
void
ut_sprintf_timestamp(
/*=================*/
char* buf) /* in: buffer where to sprintf */
{
#ifdef __WIN__
SYSTEMTIME cal_tm;
GetLocalTime(&cal_tm);
sprintf(buf, "%02d%02d%02d %2d:%02d:%02d",
(int)cal_tm.wYear % 100,
(int)cal_tm.wMonth,
(int)cal_tm.wDay,
(int)cal_tm.wHour,
(int)cal_tm.wMinute,
(int)cal_tm.wSecond);
#else
struct tm cal_tm;
struct tm* cal_tm_ptr;
time_t tm;
time(&tm);
#ifdef HAVE_LOCALTIME_R
localtime_r(&tm, &cal_tm);
cal_tm_ptr = &cal_tm;
#else
cal_tm_ptr = localtime(&tm);
#endif
sprintf(buf, "%02d%02d%02d %2d:%02d:%02d",
cal_tm_ptr->tm_year % 100,
cal_tm_ptr->tm_mon + 1,
cal_tm_ptr->tm_mday,
cal_tm_ptr->tm_hour,
cal_tm_ptr->tm_min,
cal_tm_ptr->tm_sec);
#endif
}
/************************************************************** /**************************************************************
Returns current year, month, day. */ Returns current year, month, day. */
@ -258,3 +301,26 @@ ut_ulint_sort(ulint* arr, ulint* aux_arr, ulint low, ulint high)
UT_SORT_FUNCTION_BODY(ut_ulint_sort, arr, aux_arr, low, high, UT_SORT_FUNCTION_BODY(ut_ulint_sort, arr, aux_arr, low, high,
ut_ulint_cmp); ut_ulint_cmp);
} }
/*****************************************************************
Calculates fast the number rounded up to the nearest power of 2. */
ulint
ut_2_power_up(
/*==========*/
/* out: first power of 2 which is >= n */
ulint n) /* in: number != 0 */
{
ulint res;
res = 1;
ut_ad(n > 0);
while (res < n) {
res = res * 2;
}
return(res);
}

View File

@ -284,9 +284,10 @@ static void print_version(void)
static void usage(void) static void usage(void)
{ {
print_version(); print_version();
puts("Copyright (C) 1994-2000 TcX AB & Monty Program KB & Detron HB."); puts("Copyright (C) 2002 MySQL AB");
puts("This is not free software. You must have a licence to use this program"); puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,");
puts("This software comes with ABSOLUTELY NO WARRANTY\n"); puts("and you are welcome to modify and redistribute it under the GPL license\n");
puts("Pack a ISAM-table to take much smaller space"); puts("Pack a ISAM-table to take much smaller space");
puts("Keys are not updated, so you must run isamchk -rq on any table"); puts("Keys are not updated, so you must run isamchk -rq on any table");
puts("that has keys after you have compressed it"); puts("that has keys after you have compressed it");

View File

@ -72,8 +72,8 @@ int _mi_read_cache(IO_CACHE *info, byte *buff, my_off_t pos, uint length,
in_buff_length=0; in_buff_length=0;
if (flag & READING_NEXT || info->share) if (flag & READING_NEXT || info->share)
{ {
if (pos != (info->pos_in_file + (uint) (info->read_end - if (pos != (info->pos_in_file +
info->request_pos))) (uint) (info->rc_end - info->rc_request_pos)))
{ {
info->pos_in_file=pos; /* Force start here */ info->pos_in_file=pos; /* Force start here */
info->read_pos=info->read_end=info->request_pos; /* Everything used */ info->read_pos=info->read_end=info->request_pos; /* Everything used */

View File

@ -26,7 +26,7 @@ int myrg_rnext(MYRG_INFO *info, byte *buf, int inx)
MI_INFO *mi; MI_INFO *mi;
if (!info->current_table) if (!info->current_table)
return HA_ERR_KEY_NOT_FOUND; return (HA_ERR_KEY_NOT_FOUND);
/* at first, do rnext for the table found before */ /* at first, do rnext for the table found before */
if ((err=mi_rnext(info->current_table->table,NULL,inx))) if ((err=mi_rnext(info->current_table->table,NULL,inx)))

View File

@ -26,7 +26,7 @@ int myrg_rprev(MYRG_INFO *info, byte *buf, int inx)
MI_INFO *mi; MI_INFO *mi;
if (!info->current_table) if (!info->current_table)
return HA_ERR_KEY_NOT_FOUND; return (HA_ERR_KEY_NOT_FOUND);
/* at first, do rprev for the table found before */ /* at first, do rprev for the table found before */
if ((err=mi_rprev(info->current_table->table,NULL,inx))) if ((err=mi_rprev(info->current_table->table,NULL,inx)))

View File

@ -21,7 +21,10 @@ INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include -I.. -I$(srcdir)
pkglib_LIBRARIES = libmysys.a pkglib_LIBRARIES = libmysys.a
LDADD = libmysys.a ../dbug/libdbug.a \ LDADD = libmysys.a ../dbug/libdbug.a \
../strings/libmystrings.a ../strings/libmystrings.a
noinst_HEADERS = mysys_priv.h my_static.h noinst_HEADERS = mysys_priv.h my_static.h \
my_os2cond.c my_os2dirsrch.c my_os2dirsrch.h \
my_os2dlfcn.c my_os2file64.c my_os2mutex.c \
my_os2thread.c my_os2tls.c
libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\
mf_path.c mf_loadpath.c\ mf_path.c mf_loadpath.c\
my_open.c my_create.c my_dup.c my_seek.c my_read.c \ my_open.c my_create.c my_dup.c my_seek.c my_read.c \

View File

@ -22,6 +22,7 @@ void _OS2errno( APIRET rc);
longlong _lseek64( int fd, longlong offset, int seektype); longlong _lseek64( int fd, longlong offset, int seektype);
int _lock64( int fd, int locktype, my_off_t start, int _lock64( int fd, int locktype, my_off_t start,
my_off_t length, myf MyFlags); my_off_t length, myf MyFlags);
int _sopen64( const char *name, int oflag, int shflag, int mask);
// //
// this class is used to define a global c++ variable, that // this class is used to define a global c++ variable, that
@ -191,8 +192,17 @@ inline _SetFileLocksL(HFILE hFile,
ULONG timeout, ULONG timeout,
ULONG flags) ULONG flags)
{ {
if (_DosSetFileLocksL) if (_DosSetFileLocksL) {
return _DosSetFileLocksL( hFile, pflUnlock, pflLock, timeout, flags); APIRET rc;
rc = _DosSetFileLocksL( hFile, pflUnlock, pflLock, timeout, flags);
// on FAT/HPFS/LAN a INVALID_PARAMETER is returned, seems that
// only JFS can handle >2GB ranges.
if (rc != 87)
return rc;
// got INVALID_PARAMETER, fallback to standard call
}
FILELOCK flUnlock = { pflUnlock->lOffset, pflUnlock->lRange }; FILELOCK flUnlock = { pflUnlock->lOffset, pflUnlock->lRange };
FILELOCK flLock = { pflLock->lOffset, pflLock->lRange }; FILELOCK flLock = { pflLock->lOffset, pflLock->lRange };
@ -254,7 +264,7 @@ int _lock64( int fd, int locktype, my_off_t start,
return(-1); return(-1);
} }
int _sopen( const char *name, int oflag, int shflag, int mask) int sopen( const char *name, int oflag, int shflag, int mask)
{ {
int fail_errno; int fail_errno;
APIRET rc = 0; APIRET rc = 0;

View File

@ -53,6 +53,7 @@ void win_pthread_init(void)
static pthread_handler_decl(pthread_start,param) static pthread_handler_decl(pthread_start,param)
{ {
DBUG_ENTER("pthread_start");
pthread_handler func=((struct pthread_map *) param)->func; pthread_handler func=((struct pthread_map *) param)->func;
void *func_param=((struct pthread_map *) param)->param; void *func_param=((struct pthread_map *) param)->param;
my_thread_init(); /* Will always succeed in windows */ my_thread_init(); /* Will always succeed in windows */
@ -60,8 +61,10 @@ static pthread_handler_decl(pthread_start,param)
win_pthread_self=((struct pthread_map *) param)->pthreadself; win_pthread_self=((struct pthread_map *) param)->pthreadself;
pthread_mutex_unlock(&THR_LOCK_thread); pthread_mutex_unlock(&THR_LOCK_thread);
free((char*) param); /* Free param from create */ free((char*) param); /* Free param from create */
pthread_exit((void*) (*func)(func_param)); //pthread_exit((void*) (*func)(func_param));
return 0; /* Safety */ (*func)(func_param);
DBUG_RETURN(0);
//return 0; /* Safety */
} }

BIN
os2/BldLevel.RES Normal file

Binary file not shown.

View File

@ -4,7 +4,7 @@ REM I'm using resources for BLDLEVEL info, because VA4 linker has the bad
REM feature of using versionstring content for padding files. REM feature of using versionstring content for padding files.
REM To set fixpak level: -P"fixpak level" REM To set fixpak level: -P"fixpak level"
SET MYSQL_VERSION=3.23.42 SET MYSQL_VERSION=3.23.50
SET MYSQL_BUILD=1 SET MYSQL_BUILD=B1
BldLevelInf -V%MYSQL_VERSION% -N"MySQL AB, Yuri Dario" -D"MySQL %MYSQL_VERSION% for OS/2 - Build %MYSQL_BUILD%" -Len BldLevel.rc BldLevelInf -V%MYSQL_VERSION% -N"MySQL AB, Yuri Dario" -D"MySQL %MYSQL_VERSION% for OS/2 - Build %MYSQL_BUILD%" -Len BldLevel.rc

View File

@ -1 +1 @@
RCDATA 1 { "@#MySQL AB, Yuri Dario:3.23.42#@##1## 10 Sep 2001 11:57:17 paperino::en::::@@MySQL 3.23.42 for OS/2 - Build 1" } RCDATA 1 { "@#MySQL AB, Yuri Dario:3.23.50#@##1## 24 Jun 2002 22:42:20 paperino::en::::@@MySQL 3.23.50 for OS/2 - Build B1" }

View File

@ -1,4 +1,25 @@
2002/05/02
- now libinit is automatically called on client dll startup
2002/01/27
- fixed console output for get_password
2002/01/20
- back-ported fix for fulltext indexes (wrong report by myisamchk)
2001/11/21
- MySQL 3.32.42 build 3 released.
2001/11/19
- got GNU Readline to compile with VAC++, now console has a working
history.
2001/11/10
- fixed file locking on non-JFS disks; DosSetFileLocksL does not
support ranges > 2GB on non-JFS disks.
2001/09/16 2001/09/16
- fixed creation directory of temporary files - fixed creation directory of temporary files
- enabled cached list file for deleting temp open files - enabled cached list file for deleting temp open files
@ -30,4 +51,3 @@
2001/05/19 2001/05/19
- new TLS code, fixed parser crashes and many other problems. - new TLS code, fixed parser crashes and many other problems.
- fixed pthread_cond_timedwait, now handle manager expires - fixed pthread_cond_timedwait, now handle manager expires

View File

@ -16,14 +16,13 @@
## Process this file with automake to create Makefile.in ## Process this file with automake to create Makefile.in
EXTRA_DIST = BldLevel.cmd BldLevel.rc BldLevelInf.cmd ChangeLog.os2 \ EXTRA_DIST = BldLevel.RES BldLevel.cmd BldLevel.rc \
MySQL-All.icc MySQL-Client.icc MySQL-Client.irs \ BldLevelInf.cmd ChangeLog.os2 MySQL-Client.icc \
MySQL-Lib.icc MySQL-Opt.icc MySQL-ReadLine.icc \ MySQL-Opt.icc MySQL-Source.icc MySQL-Sql.icc \
MySQL-Source.icc MySQL-Sql.icc MySQL-Util.icc MySQL-Util.irs \ MySQL-Sql.irs MySQL-Util.icc MySQL-Util.irs \
MySQL-binlog.icc MySQL-binlog.irs MySQL-sql.irs ReadMe.txt \ ReadMe.txt build-all.cmd mysql-inf.wis \
build-all.cmd build-all.log mysql-inf.wis mysql.base \ mysql.wis mysqlalt.wis rint.cmd rint.obj rint.s
mysql.ih mysql.wis mysqlalt.wis readme.os2 rint.cmd rint.obj \ SUBDIRS = include
rint.s
# Don't update the files from bitkeeper # Don't update the files from bitkeeper
%::SCCS/s.% %::SCCS/s.%

View File

@ -1,13 +0,0 @@
// create directories
for dir in "..\\bin", "..\\lib", "..\\obj", "..\\obj\\zlib", "..\\obj\\readline" {
run "if not exist "dir" mkdir "dir
}
// build sequence
run "vacbld MySQL-Lib.icc -showprogress=10 -showwarning"
run "vacbld MySQL-Client.icc -showprogress=10 -showwarning"
run "vacbld MySQL-Sql.icc -showprogress=10 -showwarning"
// need only for utilities and test applications
run "vacbld MySQL-Util.icc -showprogress=10 -showwarning"

View File

@ -43,11 +43,13 @@ option ProjectOptions = MySQLOptions
// target source files // target source files
source type('cpp') "..\\client\\mysql.cc" source type('cpp') "..\\client\\mysql.cc"
source BldLevelInfo source BldLevelInfo
option define("HAVE_STRING_H", ), define("HAVE_CONFIG_H", )
{
source GnuReadline
}
} }
} }
option file(genobject, "..\\OBJ\\READLINE\\")
{
target "..\\bin\\mysqladmin.exe" target "..\\bin\\mysqladmin.exe"
{ {
// optimized precompiled headers // optimized precompiled headers
@ -59,7 +61,6 @@ option ProjectOptions = MySQLOptions
source type('cpp') "..\\client\\mysqladmin.c" source type('cpp') "..\\client\\mysqladmin.c"
source BldLevelInfo source BldLevelInfo
} }
}
target "..\\bin\\mysqldump.exe" target "..\\bin\\mysqldump.exe"
{ {

File diff suppressed because it is too large Load Diff

View File

@ -1,72 +0,0 @@
// disable code inlining when building static libs
InlineCode = "no"
// include common options
include "MySQL-Opt.icc"
include "MySQL-Source.icc"
option ProjectOptions = MySQLOptions
{
option file(genobject, "..\\OBJ\\ZLIB\\")
{
target "..\\lib\\common.lib"
{
// optimized precompiled headers
option macros('global', 'yes')
{
source type('cpp') client_pch //, 'sql_string.h'
}
// target source files
source zlib
if debug_build {
source type('cpp') dbug
}
source type('cpp') heap
//source type('cpp') merge
source type('cpp') my_sys
source type('cpp') my_sys_cli
source type('cpp') my_sys_sql
source type('cpp') strings
}
}
/*
option file(genobject, "..\\OBJ\\READLINE\\")
{
target "..\\lib\\readline.lib"
{
// optimized precompiled headers
option macros('global', 'yes')
{
source type('cpp') client_pch //, 'sql_string.h'
}
// target source files
source readline
}
}
*/
target "..\\lib\\myisam.lib"
{
// optimized precompiled headers
option macros('global', 'yes')
{
source type('cpp') client_pch //, 'sql_string.h'
}
// target source files
source type('cpp') myisam
}
target "..\\lib\\isam.lib"
{
// optimized precompiled headers
option macros('global', 'yes')
{
source type('cpp') client_pch //, 'sql_string.h'
}
// target source files
source type('cpp') isam
}
}

View File

@ -1,6 +1,9 @@
// set to 1 to enable debug code // set to 1 to enable debug code
debug_build = 0 debug_build = 0
// set to zlib relative directory name
zlib_dir = '../../zlib-1.1.4'
// common options // common options
option BaseOptions = link(defaultlibsname, "tcpip32.lib") option BaseOptions = link(defaultlibsname, "tcpip32.lib")
, link(libsearchpath, "..\\lib\\") , link(libsearchpath, "..\\lib\\")
@ -9,6 +12,7 @@ option BaseOptions = link(defaultlibsname, "tcpip32.lib")
, link(padding, no) , link(padding, no)
, link(linkwithmultithreadlib, "yes") , link(linkwithmultithreadlib, "yes")
, link(linkwithsharedlib, "no") , link(linkwithsharedlib, "no")
, link(stack, 131072, 131072)
, gen(initauto, "yes") , gen(initauto, "yes")
, define("__MT__", ) , define("__MT__", )
, define("HAVE_BSD_SIGNALS", ) , define("HAVE_BSD_SIGNALS", )
@ -19,11 +23,12 @@ option BaseOptions = link(defaultlibsname, "tcpip32.lib")
, define("USE_TLS", ) , define("USE_TLS", )
, lang(signedchars, yes) , lang(signedchars, yes)
, incl(searchpath, "..") , incl(searchpath, "..")
, incl(searchpath, "include")
, incl(searchpath, "..\\include") , incl(searchpath, "..\\include")
, incl(searchpath, "..\\my_sys") , incl(searchpath, "..\\my_sys")
, incl(searchpath, "..\\regex") , incl(searchpath, "..\\regex")
, incl(searchpath, "..\\sql") , incl(searchpath, "..\\sql")
, incl(searchpath, "..\\..\\zlib-1.1.3") , incl(searchpath, zlib_dir)
, incl(searchpath, "..\\..\\ufc") , incl(searchpath, "..\\..\\ufc")
, incl(searchpath, "..\\os2") , incl(searchpath, "..\\os2")

View File

@ -1,27 +0,0 @@
// disable code inlining when building static libs
InlineCode = "no"
// include common options
include "MySQL-Opt.icc"
include "MySQL-Source.icc"
option ProjectOptions = MySQLOptions
{
option file(genobject, "..\\OBJ\\READLINE\\")
{
target "..\\lib\\readline.lib"
{
// optimized precompiled headers
option macros('global', 'yes')
{
source type('cpp') client_pch //, 'sql_string.h'
}
// target source files
source readline
}
}
}

View File

@ -30,7 +30,7 @@ group server_global_pch =
'm_string.h', 'm_ctype.h', 'm_string.h', 'm_ctype.h',
'myisam.h', 'myisampack.h', '.\myisam\myisamdef.h', 'myisam.h', 'myisampack.h', '.\myisam\myisamdef.h',
'sql_string.h', 'item.h', 'unireg.h', 'sql_string.h', 'item.h', 'unireg.h',
'field.h', 'sql_lex.h', 'sql_list.h', 'field.h', 'sql_lex.h', 'sql_list.h', 'sql_repl.h',
'md5.h', 'sql_acl.h', 'slave.h', 'md5.h', 'sql_acl.h', 'slave.h',
'ha_myisam.h', 'procedure.h', 'sql_select.h', 'ha_myisam.h', 'procedure.h', 'sql_select.h',
'errmsg.h', 't_ctype.h', 'direct.h', 'errmsg.h', 't_ctype.h', 'direct.h',
@ -57,12 +57,20 @@ group mysqlclientlib =
"..\\libmysql\\violite.c" "..\\libmysql\\violite.c"
group zlib = group zlib =
"..\\..\\zlib-1.1.3\\compress.c", "..\\..\\zlib-1.1.3\\crc32.c", zlib_dir "/compress.c",
"..\\..\\zlib-1.1.3\\deflate.c", "..\\..\\zlib-1.1.3\\gzio.c", "..\\..\\zlib-1.1.3\\infblock.c", zlib_dir "/crc32.c",
"..\\..\\zlib-1.1.3\\infcodes.c", "..\\..\\zlib-1.1.3\\inffast.c", zlib_dir "/deflate.c",
"..\\..\\zlib-1.1.3\\inflate.c", "..\\..\\zlib-1.1.3\\inftrees.c", zlib_dir "/gzio.c",
"..\\..\\zlib-1.1.3\\infutil.c", "..\\..\\zlib-1.1.3\\trees.c", "..\\..\\zlib-1.1.3\\uncompr.c", zlib_dir "/infblock.c",
"..\\..\\zlib-1.1.3\\zutil.c", "..\\..\\zlib-1.1.3\\adler32.c" zlib_dir "/infcodes.c",
zlib_dir "/inffast.c",
zlib_dir "/inflate.c",
zlib_dir "/inftrees.c",
zlib_dir "/infutil.c",
zlib_dir "/trees.c",
zlib_dir "/uncompr.c",
zlib_dir "/zutil.c",
zlib_dir "/adler32.c"
group ufc = group ufc =
"..\\..\\ufc\\crypt.c", "..\\..\\ufc\\crypt.c",
@ -118,6 +126,7 @@ group sql =
"..\\sql\\sql_class.cc", "..\\sql\\sql_class.cc",
"..\\sql\\sql_crypt.cc", "..\\sql\\sql_crypt.cc",
"..\\sql\\sql_db.cc", "..\\sql\\sql_db.cc",
"..\\sql\\sql_do.cc",
"..\\sql\\sql_delete.cc", "..\\sql\\sql_delete.cc",
"..\\sql\\sql_insert.cc", "..\\sql\\sql_insert.cc",
"..\\sql\\sql_lex.cc", "..\\sql\\sql_lex.cc",
@ -308,24 +317,32 @@ group strings =
group dbug = "..\\dbug\\dbug.c", "..\\dbug\\factorial.c", "..\\dbug\\sanity.c" group dbug = "..\\dbug\\dbug.c", "..\\dbug\\factorial.c", "..\\dbug\\sanity.c"
group readline = "..\\readline\\bind.c", "..\\readline\\callback.c",
"..\\readline\\complete.c", "..\\readline\\display.c",
//"..\\readline\\emacs_keymap.c",
"..\\readline\\funmap.c", "..\\readline\\histexpand.c",
"..\\readline\\histfile.c", "..\\readline\\history.c",
"..\\readline\\histsearch.c", "..\\readline\\input.c",
"..\\readline\\isearch.c", "..\\readline\\keymaps.c",
"..\\readline\\kill.c", "..\\readline\\macro.c",
"..\\readline\\nls.c", "..\\readline\\parens.c",
"..\\readline\\readline.c", "..\\readline\\rltty.c",
"..\\readline\\search.c", "..\\readline\\shell.c",
"..\\readline\\signals.c", "..\\readline\\terminal.c",
"..\\readline\\tilde.c", "..\\readline\\undo.c",
"..\\readline\\util.c",
//"..\\readline\\vi_keymap.c",
"..\\readline\\vi_mode.c", "..\\readline\\xmalloc.c"
group regex = "..\\regex\\regcomp.c", "..\\regex\\regerror.c", group regex = "..\\regex\\regcomp.c", "..\\regex\\regerror.c",
"..\\regex\\regexec.c", "..\\regex\\regfree.c", "..\\regex\\reginit.c" "..\\regex\\regexec.c", "..\\regex\\regfree.c", "..\\regex\\reginit.c"
group BldLevelInfo = 'os2\BldLevel.rc' group BldLevelInfo = 'os2\BldLevel.rc'
group GnuReadline =
"..\\readline\\bind.c",
"..\\readline\\callback.c",
"..\\readline\\complete.c",
"..\\readline\\display.c",
"..\\readline\\funmap.c",
"..\\readline\\histexpand.c", "..\\readline\\histfile.c",
"..\\readline\\history.c", "..\\readline\\histsearch.c",
"..\\readline\\input.c", "..\\readline\\isearch.c",
"..\\readline\\keymaps.c",
"..\\readline\\kill.c",
"..\\readline\\macro.c",
"..\\readline\\nls.c", "..\\readline\\parens.c",
"..\\readline\\readline.c",
"..\\readline\\rltty.c",
"..\\readline\\search.c",
"..\\readline\\shell.c",
"..\\readline\\signals.c",
"..\\readline\\terminal.c",
"..\\readline\\tilde.c",
"..\\readline\\undo.c",
"..\\readline\\util.c",
"..\\readline\\vi_mode.c",
"..\\readline\\xmalloc.c"

View File

@ -1,5 +1,5 @@
31 Run Specifications: Version 1.1 31 Run Specifications: Version 1.1
45 E:\rd\mysql\vacpp-3.23.40\bin\mysqlbinlog.exe 40 E:\rd\MySQL\vacpp-3.23.50\bin\mysqld.exe
1 1
0 0
0 0

View File

@ -153,6 +153,7 @@ option ProjectOptions = MySQLOptions
} }
} }
*/ */
target "..\\bin\\test\\insert_test.exe" target "..\\bin\\test\\insert_test.exe"
{ {
// optimized precompiled headers // optimized precompiled headers
@ -179,4 +180,4 @@ option ProjectOptions = MySQLOptions
} }
run after sources('..\bin\gen_lex_hash.exe') targets('..\sql\lex_hash.h') run after sources('..\bin\gen_lex_hash.exe') targets('..\sql\lex_hash.h')
'..\bin\gen_lex_has.exe > ..\sql\lex_hash.h' 'cd ..\bin & ..\bin\gen_lex_hash.exe > ..\sql\lex_hash.h'

File diff suppressed because it is too large Load Diff

View File

@ -1,68 +0,0 @@
// disable code inlining when building static libs
InlineCode = "no"
// include common options
include "MySQL-Opt.icc"
include "MySQL-Source.icc"
option ProjectOptions = MySQLOptions
, define( "MYSQL_SERVER", "")
, link(defaultlibsname, "common.lib")
, link(defaultlibsname, "myisam.lib")
, link(defaultlibsname, "isam.lib")
, link(defaultlibsname, "mysql.lib")
{
option define( "MYSQL_SERVER", "")
{
target "..\\bin\\mysqlbinlog.exe"
{
// optimized precompiled headers
option macros('global', 'yes')
{
source type('cpp') 'os2.h'
source type('cpp') 'errno.h', 'nerrno.h'
source type('cpp') 'config-os2.h', 'mysql_com.h'
/*
source type('cpp')
'global.h', 'my_base.h', 'config-os2.h',
'my_dir.h', 'my_sys.h', 'mysql.h',
'my_bitmap.h', 'violite.h',
'mysql_priv.h',
'm_string.h'
*/
}
// target source files
source type('cpp')
"..\\sql\\mysqlbinlog.cc"
option macros('global', 'yes')
{
source type('cpp') 'sys/stat.h'
}
source type('cpp') "..\\sql\\mini_client.cc"
option macros('global', 'yes')
{
source type('cpp') 'os2.h'
source type('cpp') 'math.h'
source type('cpp') 'stdio.h'
source type('cpp') 'stdlib.h'
source type('cpp') 'stddef.h'
source type('cpp') 'limits.h'
source type('cpp') 'sys/types.h'
source type('cpp') 'sys/time.h'
source type('cpp') 'types.h'
source type('cpp') 'stdarg.h'
source type('cpp') 'string.h'
}
source type('cpp') "..\\sql\\net_serv.cc",
"..\\sql\\mini_client_errors.c"
option macros('global', 'yes')
{
source type('cpp') 'assert.h'
}
source type('cpp') "..\\sql\\violite.c",
"..\\sql\\password.c"
//"..\\sql\\thr_malloc.cc"
}
}
}

View File

@ -1,13 +0,0 @@
31 Run Specifications: Version 1.1
40 E:\rd\mysql\vacpp-3.23.40\bin\mysqld.exe
1
0
0
5 Local
0
40 E:\rd\mysql\vacpp-3.23.40\bin\mysqld.exe
1
0
0
5 Local
0

Some files were not shown because too many files have changed in this diff Show More