From 9e95f76000b1ae66a9fbfa8a8ccc40137579752b Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 23 Jul 2002 01:59:43 +0300 Subject: [PATCH 01/30] univ.i: Fix a bug in the storage of the SQL NULL value in 64-bit computers: the value code must fit in 32 bits innobase/include/univ.i: Fix a bug in the storage of the SQL NULL value in 64-bit computers: the value code must fit in 32 bits --- innobase/include/univ.i | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/innobase/include/univ.i b/innobase/include/univ.i index e7d93a594c1..4c1ca929aa8 100644 --- a/innobase/include/univ.i +++ b/innobase/include/univ.i @@ -204,8 +204,12 @@ headers may define 'bool' differently. Do not assume that 'bool' is a ulint! */ #endif /* The following number as the length of a logical field means that the field -has the SQL NULL as its value. */ -#define UNIV_SQL_NULL ULINT_UNDEFINED +has the SQL NULL as its value. NOTE that because we assume that the length +of a field is a 32-bit integer when we store it, for example, to an undo log +on disk, we must have also this number fit in 32 bits, also in 64-bit +computers! */ + +#define UNIV_SQL_NULL ULINT32_UNDEFINED /* Lengths which are not UNIV_SQL_NULL, but bigger than the following number indicate that a field contains a reference to an externally From 4a6b039c1521f401f43ac6158e222978ac610d43 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 23 Jul 2002 04:24:09 +0300 Subject: [PATCH 02/30] os0thread.c, configure.in: Make the typecast trick pthread_t -> os_thread_id_t safer, but a full fix needs usage of appropriate Posix functions innobase/configure.in: Make the typecast trick pthread_t -> os_thread_id_t safer, but a full fix needs usage of appropriate Posix functions innobase/os/os0thread.c: Make the typecast trick pthread_t -> os_thread_id_t safer, but a full fix needs usage of appropriate Posix functions --- innobase/configure.in | 2 +- innobase/os/os0thread.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/innobase/configure.in b/innobase/configure.in index b606ecfffc0..e98dc3d0f0d 100644 --- a/innobase/configure.in +++ b/innobase/configure.in @@ -86,7 +86,7 @@ fi case "$target_os" in hp*) - CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";; + CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE -DUNIV_HPUX";; irix*) CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";; osf*) diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index 11bff73608a..74f5fbd9494 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -32,12 +32,27 @@ os_thread_get_curr_id(void) pthr = pthread_self(); +#ifdef UNIV_HPUX /* TODO: in the future we have to change os_thread_id to pthread_t; the following cast may work in a wrong way on some systems if pthread_t is a struct; this is just a quick fix for HP-UX to eliminate a compiler warning */ + + /* The below typecast trick will certainly not work if this assertion + fails */ + + ut_a(sizeof(pthread_t) >= sizeof(os_thread_id_t)); + return(*(os_thread_id_t*)((void*) (&pthr))); +#else + /* TODO: define os_thread_id_t in Unix as the same as pthread_t + and compare them with appropriate Posix pthread functions! + The following typecast will not work if pthread_t is not + an integer or a pointer to a unique object for the thread! */ + + return((os_thread_id_t)pthr); +#endif #endif } From a3800d6d9b069c9f6e5c903192dbe1284c5af1ba Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 25 Jul 2002 12:30:41 +0200 Subject: [PATCH 03/30] bugfix: uniques did not contributed to MYI tot_length estimation, which resulted in "Index file full" error on huge SELECT DISTINCT's --- myisam/mi_create.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/myisam/mi_create.c b/myisam/mi_create.c index 7abf274d621..6941db158e1 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -392,6 +392,9 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, uniquedef->key=keys+i; unique_key_parts+=uniquedef->keysegs; share.state.key_root[keys+i]= HA_OFFSET_ERROR; + tot_length+= (max_rows/(ulong) (((uint) myisam_block_size-5)/ + ((MI_UNIQUE_HASH_LENGTH + pointer)*2)))* + (ulong) myisam_block_size; } keys+=uniques; /* Each unique has 1 key */ key_segs+=uniques; /* Each unique has 1 key seg */ From cdddb960be6251fedc6d0f8c2309d898039d7a7b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 25 Jul 2002 22:51:43 +0300 Subject: [PATCH 04/30] row0vers.c: Add diagnostic code to track a probable table corruption reported by a user innobase/row/row0vers.c: Add diagnostic code to track a probable table corruption reported by a user --- innobase/row/row0vers.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/innobase/row/row0vers.c b/innobase/row/row0vers.c index 9508e73f45d..cd8b18e5e12 100644 --- a/innobase/row/row0vers.c +++ b/innobase/row/row0vers.c @@ -58,6 +58,7 @@ row_vers_impl_x_locked_off_kernel( ibool rec_del; ulint err; mtr_t mtr; + char err_buf[1000]; ut_ad(mutex_own(&kernel_mutex)); ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED)); @@ -74,7 +75,26 @@ row_vers_impl_x_locked_off_kernel( clust_rec = row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr); - ut_a(clust_rec); + if (!clust_rec) { + rec_sprintf(err_buf, 900, rec); + + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: Error: cannot find the clustered index record\n" +"InnoDB: for a secondary index record in table %s index %s.\n" +"InnoDB: Secondary index record %s.\n" +"InnoDB: The table is probably corrupt. Please run CHECK TABLE on it.\n" +"InnoDB: You can try to repair the table by dump + drop + reimport.\n" +"InnoDB: Send a detailed bug report to mysql@lists.mysql.com.\n", + index->table_name, index->name, err_buf); + mutex_enter(&kernel_mutex); + mtr_commit(&mtr); + + /* We assume there is no lock on the record, though this + is not certain because the table is apparently corrupt */ + + return(NULL); + } trx_id = row_get_rec_trx_id(clust_rec, clust_index); From 48e8ed29ebbd0846e0c32a94be0413902d7d9198 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 26 Jul 2002 18:25:16 +0300 Subject: [PATCH 05/30] dyn0dyn.ic, dyn0dyn.h: Backport the AIX crash fix changes from 4.0 innobase/include/dyn0dyn.h: Backport the AIX crash fix changes from 4.0 innobase/include/dyn0dyn.ic: Backport the AIX crash fix changes from 4.0 --- innobase/include/dyn0dyn.h | 2 +- innobase/include/dyn0dyn.ic | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/innobase/include/dyn0dyn.h b/innobase/include/dyn0dyn.h index 0952a8b4647..6f08da1533b 100644 --- a/innobase/include/dyn0dyn.h +++ b/innobase/include/dyn0dyn.h @@ -17,7 +17,7 @@ typedef struct dyn_block_struct dyn_block_t; typedef dyn_block_t dyn_array_t; -/* Initial 'payload' size in bytes in a dynamic array block */ +/* This must be > MLOG_BUF_MARGIN + 30 */ #define DYN_ARRAY_DATA_SIZE 512 /************************************************************************* diff --git a/innobase/include/dyn0dyn.ic b/innobase/include/dyn0dyn.ic index dc004efbb8b..787615cae09 100644 --- a/innobase/include/dyn0dyn.ic +++ b/innobase/include/dyn0dyn.ic @@ -185,7 +185,8 @@ dyn_array_open( /*===========*/ /* out: pointer to the buffer */ dyn_array_t* arr, /* in: dynamic array */ - ulint size) /* in: size in bytes of the buffer */ + ulint size) /* in: size in bytes of the buffer; MUST be + smaller than DYN_ARRAY_DATA_SIZE! */ { dyn_block_t* block; ulint used; @@ -207,6 +208,7 @@ dyn_array_open( if (used + size > DYN_ARRAY_DATA_SIZE) { block = dyn_array_add_block(arr); used = block->used; + ut_a(size <= DYN_ARRAY_DATA_SIZE); } } From 01152fb14637d1fb324bac0de496164a6e1ba46f Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 29 Jul 2002 09:35:25 +0300 Subject: [PATCH 06/30] Merge of ha_innobase.cc from 4.0; This fixes that MySQL doesn't allocate too big buffers when sorting innobase rows Changed name of variables NO_FOREIGN_KEY_CHECKS -> FOREIGN_KEY_CHECKS RELAXED_UNIQUE_CHECKS -> UNIQUE_CHECKS to avoid confusion with 'not...' variables. Write name of adminstrator command to slow log. Added mysqldumpslow to RPM Docs/manual.texi: Changelog sql/gen_lex_hash.cc: Updated values sql/ha_innobase.cc: Remove return value of sprintf Merged back optimizations done in 4.0 Fixed ref_length; Caused MySQL to use big buffers when using InnoDB sql/lex.h: Changed name of variables NO_FOREIGN_KEY_CHECKS -> FOREIGN_KEY_CHECKS RELAXED_UNIQUE_CHECKS -> UNIQUE_CHECKS sql/log.cc: Write name of adminstrator command to slow log sql/sql_yacc.yy: Changed name of variables NO_FOREIGN_KEY_CHECKS -> FOREIGN_KEY_CHECKS RELAXED_UNIQUE_CHECKS -> UNIQUE_CHECKS support-files/mysql.spec.sh: Added mysqldumpslow to RPM --- Docs/manual.texi | 2 + sql/gen_lex_hash.cc | 2 +- sql/ha_innobase.cc | 153 +++++++++++++++++++----------------- sql/lex.h | 4 +- sql/log.cc | 10 +-- sql/sql_yacc.yy | 16 ++-- support-files/mysql.spec.sh | 1 + 7 files changed, 99 insertions(+), 89 deletions(-) diff --git a/Docs/manual.texi b/Docs/manual.texi index 19ce75e5d7d..f6398627e34 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -46928,6 +46928,8 @@ not yet 100% confident in this code. @appendixsubsec Changes in release 3.23.52 @itemize @bullet @item +Added name of 'administrator command' logs. +@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 diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc index 7bbf08b50f3..d47019ee040 100644 --- a/sql/gen_lex_hash.cc +++ b/sql/gen_lex_hash.cc @@ -481,7 +481,7 @@ int main(int argc,char **argv) int error; MY_INIT(argv[0]); - start_value=6130115L; best_t1=3632784L; best_t2=86437L; best_type=3; /* mode=4229 add=2 type: 0 */ + start_value=7740512L; best_t1=7953583L; best_t2=6918639L; best_type=1; /* mode=5449 add=1 type: 0 */ if (get_options(argc,(char **) argv)) exit(1); diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc index 33bc4613ef5..ed96b81740c 100644 --- a/sql/ha_innobase.cc +++ b/sql/ha_innobase.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & InnoDB Oy +/* Copyright (C) 2000 MySQL AB & InnoDB Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -93,8 +93,8 @@ are determined in innobase_init below: */ /* innobase_data_file_path=ibdata:15,idata2:1,... */ -char* innobase_data_home_dir = NULL; char* innobase_data_file_path = NULL; +char* innobase_data_home_dir = NULL; char* innobase_log_group_home_dir = NULL; char* innobase_log_arch_dir = NULL; char* innobase_unix_file_flush_method = NULL; @@ -254,8 +254,6 @@ convert_error_code_to_mysql( return(HA_ERR_TO_BIG_ROW); } else { - dbug_assert(0); - return(-1); // Unknown error } } @@ -277,29 +275,40 @@ innobase_mysql_print_thd( thd = (THD*) input_thd; - buf += sprintf(buf, "MySQL thread id %lu, query id %lu", - thd->thread_id, thd->query_id); - if (thd->host) { - buf += sprintf(buf, " %.30s", thd->host); + /* We can't use value of sprintf() as this is not portable */ + buf=my_sprintf(buf, + (buf, "MySQL thread id %lu, query id %lu", + thd->thread_id, thd->query_id)); + if (thd->host) + { + *buf++=' '; + buf=strnmov(buf, thd->host, 30); } - if (thd->ip) { - buf += sprintf(buf, " %.20s", thd->ip); + if (thd->ip) + { + *buf++=' '; + buf=strnmov(buf, thd->ip, 20); } - if (thd->user) { - buf += sprintf(buf, " %.20s", thd->user); + if (thd->user) + { + *buf++=' '; + buf=strnmov(buf, thd->user, 20); } - if (thd->proc_info) { - buf += sprintf(buf, " %.50s", thd->proc_info); + if (thd->proc_info) + { + *buf++=' '; + buf=strnmov(buf, thd->procinfo, 50); } - if (thd->query) { - buf += sprintf(buf, "\n%.150s", thd->query); + if (thd->query) + { + *buf++=' '; + buf=strnmov(buf, thd->query, 150); } - - buf += sprintf(buf, "\n"); + *buf='\n'; } } @@ -401,6 +410,11 @@ innobase_init(void) os_innodb_umask = (ulint)my_umask; + /* Use current_dir if no paths are set */ + current_dir[0] = FN_CURLIB; + current_dir[1] = FN_LIBCHAR; + current_dir[2] = 0; + if (specialflag & SPECIAL_NO_PRIOR) { srv_set_thread_priorities = FALSE; } else { @@ -408,11 +422,6 @@ innobase_init(void) srv_query_thread_priority = QUERY_PRIOR; } - /* Use current_dir if no paths are set */ - current_dir[0] = FN_CURLIB; - current_dir[1] = FN_LIBCHAR; - current_dir[2] = 0; - /* Set InnoDB initialization parameters according to the values read from MySQL .cnf file */ @@ -452,9 +461,8 @@ innobase_init(void) DBUG_RETURN(TRUE); } - if (!innobase_log_group_home_dir) { + if (!innobase_log_group_home_dir) innobase_log_group_home_dir = current_dir; - } ret = (bool) srv_parse_log_group_home_dirs(innobase_log_group_home_dir, @@ -797,7 +805,7 @@ normalize_table_name( name_ptr = ptr + 1; - dbug_assert(ptr > name); + DBUG_ASSERT(ptr > name); ptr--; @@ -824,7 +832,7 @@ normalize_table_name( } /********************************************************************* -Creates and opens a handle to a table which already exists in an Innnobase +Creates and opens a handle to a table which already exists in an Innobase database. */ int @@ -909,20 +917,22 @@ ha_innobase::open( primary_key = 0; key_used_on_scan = 0; - /* MySQL allocates the buffer for ref */ + /* + MySQL allocates the buffer for ref. + This includes all keys + one byte for each column + that may be NULL. + The ref_length must be exact as possible as + all reference buffers are allocated based on this. + */ - ref_length = table->key_info->key_length - + table->key_info->key_parts + 10; - - /* One byte per key field is consumed to the SQL NULL - info of the field; we add also 10 bytes of safety margin */ + ref_length = table->key_info->key_length; } else { ((row_prebuilt_t*)innobase_prebuilt) ->clust_index_was_generated = TRUE; - ref_length = DATA_ROW_ID_LEN + 10; + ref_length = DATA_ROW_ID_LEN; - dbug_assert(key_used_on_scan == MAX_KEY); + DBUG_ASSERT(key_used_on_scan == MAX_KEY); } auto_inc_counter_for_this_stat = 0; @@ -1069,8 +1079,8 @@ innobase_mysql_cmp( enum_field_types mysql_tp; int ret; - dbug_assert(a_length != UNIV_SQL_NULL); - dbug_assert(b_length != UNIV_SQL_NULL); + DBUG_ASSERT(a_length != UNIV_SQL_NULL); + DBUG_ASSERT(b_length != UNIV_SQL_NULL); mysql_tp = (enum_field_types) mysql_type; @@ -1108,11 +1118,11 @@ get_innobase_type_from_mysql_type( 8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to the type */ - dbug_assert((ulint)FIELD_TYPE_STRING < 256); - dbug_assert((ulint)FIELD_TYPE_VAR_STRING < 256); - dbug_assert((ulint)FIELD_TYPE_DOUBLE < 256); - dbug_assert((ulint)FIELD_TYPE_FLOAT < 256); - dbug_assert((ulint)FIELD_TYPE_DECIMAL < 256); + DBUG_ASSERT((ulint)FIELD_TYPE_STRING < 256); + DBUG_ASSERT((ulint)FIELD_TYPE_VAR_STRING < 256); + DBUG_ASSERT((ulint)FIELD_TYPE_DOUBLE < 256); + DBUG_ASSERT((ulint)FIELD_TYPE_FLOAT < 256); + DBUG_ASSERT((ulint)FIELD_TYPE_DECIMAL < 256); switch (field->type()) { case FIELD_TYPE_VAR_STRING: if (field->flags & BINARY_FLAG) { @@ -1204,7 +1214,12 @@ ha_innobase::store_key_val_for_row( buff += key_part->length; } - DBUG_RETURN(buff - buff_start); + /* + We have to zero-fill the buffer to be able to compare two + keys to see if they are equal + */ + bzero(buff, (ref_length- (uint) (buff - buff_start))); + DBUG_RETURN(ref_length); } /****************************************************************** @@ -1994,7 +2009,7 @@ ha_innobase::change_active_index( statistic_increment(ha_read_key_count, &LOCK_status); - DBUG_ENTER("index_read_idx"); + DBUG_ENTER("change_active_index"); active_index = keynr; @@ -2013,10 +2028,10 @@ ha_innobase::change_active_index( "InnoDB: Could not find key n:o %u with name %s from dict cache\n" "InnoDB: for table %s\n", keynr, key ? key->name : "NULL", prebuilt->table->name); - return(1); + DBUG_RETURN(1); } - assert(prebuilt->search_tuple); + assert(prebuilt->search_tuple != 0); dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields); @@ -2029,7 +2044,7 @@ ha_innobase::change_active_index( build_template(prebuilt, user_thd, table, ROW_MYSQL_WHOLE_ROW); - return(0); + DBUG_RETURN(0); } /************************************************************************** @@ -2349,7 +2364,7 @@ ha_innobase::position( len = store_key_val_for_row(primary_key, (char*) ref, record); } - dbug_assert(len <= ref_length); + DBUG_ASSERT(len == ref_length); ref_stored_len = len; } @@ -2441,7 +2456,8 @@ create_index( ind_type = 0; - if (strcmp(key->name, "PRIMARY") == 0) { + if (key_num == form->primary_key) + { ind_type = ind_type | DICT_CLUSTERED; } @@ -2513,23 +2529,23 @@ ha_innobase::create( int error; dict_table_t* innobase_table; trx_t* trx; - int primary_key_no = -1; - KEY* key; + int primary_key_no; uint i; char name2[FN_REFLEN]; char norm_name[FN_REFLEN]; + THD *thd= current_thd; DBUG_ENTER("ha_innobase::create"); - assert(current_thd != NULL); + DBUG_ASSERT(thd != NULL); trx = trx_allocate_for_mysql(); - if (current_thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { + if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { trx->check_foreigns = FALSE; } - if (current_thd->options & OPTION_RELAXED_UNIQUE_CHECKS) { + if (thd->options & OPTION_RELAXED_UNIQUE_CHECKS) { trx->check_unique_secondary = FALSE; } @@ -2559,13 +2575,9 @@ ha_innobase::create( /* Look for a primary key */ - for (i = 0; i < form->keys; i++) { - key = form->key_info + i; - - if (strcmp(key->name, "PRIMARY") == 0) { - primary_key_no = (int) i; - } - } + primary_key_no= (table->primary_key != MAX_KEY ? + (int) table->primary_key : + -1); /* Our function row_get_mysql_key_number_for_index assumes the primary key is always number 0, if it exists */ @@ -2651,7 +2663,7 @@ ha_innobase::create( innobase_table = dict_table_get(norm_name, NULL); - assert(innobase_table); + assert(innobase_table != 0); /* Tell the InnoDB server that there might be work for utility threads: */ @@ -2750,14 +2762,7 @@ innobase_drop_database( namebuf[len + 1] = '\0'; #ifdef __WIN__ - /* Put to lower case */ - - ptr = namebuf; - - while (*ptr != '\0') { - *ptr = tolower(*ptr); - ptr++; - } + casedn_str(namebuf); #endif trx = trx_allocate_for_mysql(); @@ -2948,7 +2953,7 @@ ha_innobase::estimate_number_of_rows(void) estimate = 2 * data_file_length / dict_index_calc_min_rec_len(index); - return((ha_rows) estimate); + DBUG_RETURN((ha_rows) estimate); } /************************************************************************* @@ -3144,8 +3149,9 @@ ha_innobase::update_table_comment( *pos++=' '; } - pos += sprintf(pos, "InnoDB free: %lu kB", - (ulong) innobase_get_free_space()); + pos += my_sprintf(pos, + (pos,"InnoDB free: %lu kB", + (ulong) innobase_get_free_space())); /* We assume 450 - length bytes of space to print info */ @@ -3322,6 +3328,7 @@ ha_innobase::external_lock( & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))) { innobase_commit(thd, trx); + thd->transaction.all.innodb_active_trans=0; } } } diff --git a/sql/lex.h b/sql/lex.h index a242f751053..776e03b811b 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -232,7 +232,7 @@ static SYMBOL symbols[] = { { "NCHAR", SYM(NCHAR_SYM),0,0}, { "NUMERIC", SYM(NUMERIC_SYM),0,0}, { "NO", SYM(NO_SYM),0,0}, - { "NO_FOREIGN_KEY_CHECKS", SYM(NO_FOREIGN_KEY_CHECKS), 0, 0}, + { "FOREIGN_KEY_CHECKS", SYM(FOREIGN_KEY_CHECKS), 0, 0}, { "NOT", SYM(NOT),0,0}, { "NULL", SYM(NULL_SYM),0,0}, { "ON", SYM(ON),0,0}, @@ -261,7 +261,7 @@ static SYMBOL symbols[] = { { "REFERENCES", SYM(REFERENCES),0,0}, { "RELOAD", SYM(RELOAD),0,0}, { "REGEXP", SYM(REGEXP),0,0}, - { "RELAXED_UNIQUE_CHECKS", SYM(RELAXED_UNIQUE_CHECKS), 0, 0}, + { "UNIQUE_CHECKS", SYM(UNIQUE_CHECKS), 0, 0}, { "RENAME", SYM(RENAME),0,0}, { "REPAIR", SYM(REPAIR),0,0}, { "REPLACE", SYM(REPLACE),0,0}, diff --git a/sql/log.cc b/sql/log.cc index ee5818fc594..b90659fdf55 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -948,16 +948,16 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, if (end != buff) { *end++=';'; - *end++='\n'; - *end=0; + *end='\n'; if (my_b_write(&log_file, (byte*) "SET ",4) || - my_b_write(&log_file, (byte*) buff+1,(uint) (end-buff)-1)) + my_b_write(&log_file, (byte*) buff+1,(uint) (end-buff))) tmp_errno=errno; } if (!query) { - query="#adminstrator command"; - query_length=21; + end=strxmov(buff, "# administrator command: ", + command_name[thd->command], NullS); + query_length=(ulong) (end-buff); } if (my_b_write(&log_file, (byte*) query,query_length) || my_b_write(&log_file, (byte*) ";\n",2) || diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e258f5d3827..1e92c833872 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -224,7 +224,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token NATURAL %token NCHAR_SYM %token NOT -%token NO_FOREIGN_KEY_CHECKS +%token FOREIGN_KEY_CHECKS %token NO_SYM %token NULL_SYM %token NUM @@ -253,7 +253,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token REAL_NUM %token REFERENCES %token REGEXP -%token RELAXED_UNIQUE_CHECKS %token RELOAD %token RENAME %token REPEATABLE_SYM @@ -289,6 +288,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token UNCOMMITTED_SYM %token UNION_SYM %token UNIQUE_SYM +%token UNIQUE_CHECKS %token USAGE %token USE_SYM %token USING @@ -2606,7 +2606,7 @@ keyword: | MYISAM_SYM {} | NATIONAL_SYM {} | NCHAR_SYM {} - | NO_FOREIGN_KEY_CHECKS {} + | FOREIGN_KEY_CHECKS {} | NO_SYM {} | OPEN_SYM {} | PACK_KEYS_SYM {} @@ -2619,7 +2619,7 @@ keyword: | RAID_CHUNKSIZE {} | RAID_STRIPED_SYM {} | RAID_TYPE {} - | RELAXED_UNIQUE_CHECKS {} + | UNIQUE_CHECKS {} | RELOAD {} | REPAIR {} | REPEATABLE_SYM {} @@ -2777,16 +2777,16 @@ option_value: slave_skip_counter = $3; pthread_mutex_unlock(&LOCK_slave); } - | NO_FOREIGN_KEY_CHECKS equal NUM + | FOREIGN_KEY_CHECKS equal NUM { - if (atoi($3.str) != 0) + if (atoi($3.str) == 0) Lex->options|= OPTION_NO_FOREIGN_KEY_CHECKS; else Lex->options&= ~(OPTION_NO_FOREIGN_KEY_CHECKS); } - | RELAXED_UNIQUE_CHECKS equal NUM + | UNIQUE_CHECKS equal NUM { - if (atoi($3.str) != 0) + if (atoi($3.str) == 0) Lex->options|= OPTION_RELAXED_UNIQUE_CHECKS; else Lex->options&= ~(OPTION_RELAXED_UNIQUE_CHECKS); diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 4c37ff31a0b..110d3c9e397 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -382,6 +382,7 @@ fi %attr(755, root, root) /usr/bin/safe_mysqld %attr(755, root, root) /usr/bin/mysqld_multi %attr(755, root, root) /usr/bin/my_print_defaults +%attr(755, root, root) /usr/bin/mysqldumpslow %attr(644, root, root) /usr/info/mysql.info* From 7ad970a01bae9ba3b10e38b23a0bfc8c245f1c73 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 29 Jul 2002 09:40:04 +0300 Subject: [PATCH 07/30] Fixed wrong usage of return value of sprintf() (From prev change set) --- sql/ha_innobase.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc index ed96b81740c..9c732b9c715 100644 --- a/sql/ha_innobase.cc +++ b/sql/ha_innobase.cc @@ -276,9 +276,9 @@ innobase_mysql_print_thd( thd = (THD*) input_thd; /* We can't use value of sprintf() as this is not portable */ - buf=my_sprintf(buf, - (buf, "MySQL thread id %lu, query id %lu", - thd->thread_id, thd->query_id)); + buf+= my_sprintf(buf, + (buf, "MySQL thread id %lu, query id %lu", + thd->thread_id, thd->query_id)); if (thd->host) { *buf++=' '; From d47ee142efe9696ebdb2faaae6fa8b4ed4b5799f Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 30 Jul 2002 02:07:01 +0300 Subject: [PATCH 08/30] ha_innobase.h, ha_innobase.cc: procinfo -> proc_info to make ha_innobase.cc to compile, add more comments about ref sql/ha_innobase.cc: procinfo -> proc_info to make ha_innobase.cc to compile, add more comments about ref sql/ha_innobase.h: procinfo -> proc_info to make ha_innobase.cc to compile, add more comments about ref --- sql/ha_innobase.cc | 96 ++++++++++++++++++++++++++++------------------ sql/ha_innobase.h | 2 - 2 files changed, 59 insertions(+), 39 deletions(-) diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc index 9c732b9c715..49ad21c0a41 100644 --- a/sql/ha_innobase.cc +++ b/sql/ha_innobase.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & InnoDB Oy +/* Copyright (C) 2000 MySQL AB & Innobase Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -300,7 +300,7 @@ innobase_mysql_print_thd( if (thd->proc_info) { *buf++=' '; - buf=strnmov(buf, thd->procinfo, 50); + buf=strnmov(buf, thd->proc_info, 50); } if (thd->query) @@ -832,7 +832,7 @@ normalize_table_name( } /********************************************************************* -Creates and opens a handle to a table which already exists in an Innobase +Creates and opens a handle to a table which already exists in an InnoDB database. */ int @@ -903,13 +903,13 @@ ha_innobase::open( primary_key = MAX_KEY; - if (!row_table_got_default_clust_index(ib_table)) { + /* Allocate a buffer for a 'row reference'. A row reference is + a string of bytes of length ref_length which uniquely specifies + a row in our table. Note that MySQL may also compare two row + references for equality by doing a simple memcmp on the strings + of length ref_length! */ - /* If we automatically created the clustered index, - then MySQL does not know about it and it must not be aware - of the index used on scan, to avoid checking if we update - the column of the index. The column is the row id in - the automatical case, and it will not be updated. */ + if (!row_table_got_default_clust_index(ib_table)) { ((row_prebuilt_t*)innobase_prebuilt) ->clust_index_was_generated = FALSE; @@ -917,13 +917,11 @@ ha_innobase::open( primary_key = 0; key_used_on_scan = 0; - /* - MySQL allocates the buffer for ref. - This includes all keys + one byte for each column - that may be NULL. - The ref_length must be exact as possible as - all reference buffers are allocated based on this. - */ + /* MySQL allocates the buffer for ref. key_info->key_length + includes space for all key columns + one byte for each column + that may be NULL. ref_length must be as exact as possible to + save space, because all row reference buffers are allocated + based on ref_length. */ ref_length = table->key_info->key_length; } else { @@ -932,6 +930,14 @@ ha_innobase::open( ref_length = DATA_ROW_ID_LEN; + /* If we automatically created the clustered index, then + MySQL does not know about it, and MySQL must NOT be aware + of the index used on scan, to make it avoid checking if we + update the column of the index. That is why we assert below + that key_used_on_scan is the undefined value MAX_KEY. + The column is the row id in the automatical generation case, + and it will never be updated anyway. */ + DBUG_ASSERT(key_used_on_scan == MAX_KEY); } @@ -1178,7 +1184,8 @@ get_innobase_type_from_mysql_type( } /*********************************************************************** -Stores a key value for a row to a buffer. */ +Stores a key value for a row to a buffer. This must currently only be used +to store a row reference to the 'ref' buffer of this table handle! */ uint ha_innobase::store_key_val_for_row( @@ -1186,7 +1193,8 @@ ha_innobase::store_key_val_for_row( /* out: key value length as stored in buff */ uint keynr, /* in: key number */ char* buff, /* in/out: buffer for the key value (in MySQL - format) */ + format); currently this MUST be the 'ref' + buffer! */ const mysql_byte* record)/* in: row in MySQL format */ { KEY* key_info = table->key_info + keynr; @@ -1214,11 +1222,12 @@ ha_innobase::store_key_val_for_row( buff += key_part->length; } - /* - We have to zero-fill the buffer to be able to compare two - keys to see if they are equal - */ - bzero(buff, (ref_length- (uint) (buff - buff_start))); + /* We have to zero-fill the 'ref' buffer so that MySQL is able to + use a simple memcmp to compare two key values to determine if they are + equal */ + + bzero(buff, (ref_length - (uint) (buff - buff_start))); + DBUG_RETURN(ref_length); } @@ -1904,7 +1913,10 @@ ha_innobase::index_read( row */ const mysql_byte* key_ptr,/* in: key value; if this is NULL we position the cursor at the - start or end of index */ + start or end of index; this can + also contain an InnoDB row id, in + which case key_len is the InnoDB + row id length */ uint key_len,/* in: key value length */ enum ha_rkey_function find_flag)/* in: search flags from my_base.h */ { @@ -1931,10 +1943,8 @@ ha_innobase::index_read( index = prebuilt->index; - /* Note that if the select is used for an update, we always - fetch the clustered index record: therefore the index for which the - template is built is not necessarily prebuilt->index, but can also - be the clustered index */ + /* Note that if the index for which the search template is built is not + necessarily prebuilt->index, but can also be the clustered index */ if (prebuilt->sql_stat_start) { build_template(prebuilt, user_thd, table, @@ -1942,6 +1952,9 @@ ha_innobase::index_read( } if (key_ptr) { + /* Convert the search key value to InnoDB format into + prebuilt->search_tuple */ + row_sel_convert_mysql_key_to_innobase(prebuilt->search_tuple, (byte*) key_val_buff, index, @@ -2289,8 +2302,7 @@ ha_innobase::rnd_next( } /************************************************************************** -Fetches a row from the table based on a reference. TODO: currently we use -'ref_stored_len' of the handle as the key length. This may change. */ +Fetches a row from the table based on a row reference. */ int ha_innobase::rnd_pos( @@ -2298,7 +2310,11 @@ ha_innobase::rnd_pos( /* out: 0, HA_ERR_KEY_NOT_FOUND, or error code */ mysql_byte* buf, /* in/out: buffer for the row */ - mysql_byte* pos) /* in: primary key value in MySQL format */ + mysql_byte* pos) /* in: primary key value of the row in the + MySQL format, or the row id if the clustered + index was internally generated by InnoDB; + the length of data in pos has to be + ref_length */ { row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; int error; @@ -2314,7 +2330,7 @@ ha_innobase::rnd_pos( /* No primary key was defined for the table and we generated the clustered index from the row id: the row reference is the row id, not any key value - that MySQL knows */ + that MySQL knows of */ error = change_active_index(MAX_KEY); } else { @@ -2325,7 +2341,10 @@ ha_innobase::rnd_pos( DBUG_RETURN(error); } - error = index_read(buf, pos, ref_stored_len, HA_READ_KEY_EXACT); + /* Note that we assume the length of the row reference is fixed + for the table, and it is == ref_length */ + + error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT); change_active_index(keynr); @@ -2334,7 +2353,8 @@ ha_innobase::rnd_pos( /************************************************************************* Stores a reference to the current row to 'ref' field of the handle. Note -that the function parameter is illogical: we must assume that 'record' +that in the case where we have generated the clustered index for the +table, the function parameter is illogical: we MUST ASSUME that 'record' is the current 'position' of the handle, because if row ref is actually the row id internally generated in InnoDB, then 'record' does not contain it. We just guess that the row id must be for the record where the handle @@ -2355,7 +2375,7 @@ ha_innobase::position( /* No primary key was defined for the table and we generated the clustered index from row id: the row reference will be the row id, not any key value - that MySQL knows */ + that MySQL knows of */ len = DATA_ROW_ID_LEN; @@ -2364,9 +2384,11 @@ ha_innobase::position( len = store_key_val_for_row(primary_key, (char*) ref, record); } - DBUG_ASSERT(len == ref_length); + /* Since we do not store len to the buffer 'ref', we must assume + that len is always fixed for this table. The following assertion + checks this. */ - ref_stored_len = len; + DBUG_ASSERT(len == ref_length); } /********************************************************************* diff --git a/sql/ha_innobase.h b/sql/ha_innobase.h index aa497132b25..4a9f3a6251b 100644 --- a/sql/ha_innobase.h +++ b/sql/ha_innobase.h @@ -51,8 +51,6 @@ class ha_innobase: public handler byte* key_val_buff; /* buffer used in converting search key values from MySQL format to Innobase format */ - uint ref_stored_len; /* length of the key value stored to - 'ref' buffer of the handle, if any */ ulong int_option_flag; uint primary_key; uint last_dup_key; From 95cb4cc84581e29e034a0264b7bd802de6430071 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 30 Jul 2002 13:12:09 +0300 Subject: [PATCH 09/30] ha_innobase.cc: Since MySQL commits the stmt always at the end of an INSERT, it is enough to release auto-inc lock at innobase_commit and innobase_rollback; add also more comments to code sql/ha_innobase.cc: Since MySQL commits the stmt always at the end of an INSERT, it is enough to release auto-inc lock at innobase_commit and innobase_rollback; add also more comments to code --- sql/ha_innobase.cc | 84 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 72 insertions(+), 12 deletions(-) diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc index 49ad21c0a41..1bf619855c9 100644 --- a/sql/ha_innobase.cc +++ b/sql/ha_innobase.cc @@ -130,8 +130,9 @@ static void innobase_print_error(const char* db_errpfx, char* buffer); /* General functions */ /********************************************************************** -Releases possible search latch, auto inc lock, and InnoDB thread FIFO ticket. -These should be released at each SQL statement end. */ +Releases possible search latch and InnoDB thread FIFO ticket. These should +be released at each SQL statement end. It does no harm to release these +also in the middle of an SQL statement. */ static void innobase_release_stat_resources( @@ -142,16 +143,6 @@ innobase_release_stat_resources( trx_search_latch_release_if_reserved(trx); } - if (trx->auto_inc_lock) { - - /* If we had reserved the auto-inc lock for - some table in this SQL statement, we release it now */ - - srv_conc_enter_innodb(trx); - row_unlock_table_autoinc_for_mysql(trx); - srv_conc_exit_innodb(trx); - } - if (trx->declared_to_be_inside_innodb) { /* Release our possible ticket in the FIFO */ @@ -635,6 +626,16 @@ innobase_commit( trx = check_trx_exists(thd); + if (trx->auto_inc_lock) { + + /* If we had reserved the auto-inc lock for + some table in this SQL statement, we release it now */ + + srv_conc_enter_innodb(trx); + row_unlock_table_autoinc_for_mysql(trx); + srv_conc_exit_innodb(trx); + } + if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) { innobase_commit_low(trx); } @@ -704,6 +705,16 @@ innobase_rollback( trx = check_trx_exists(thd); + if (trx->auto_inc_lock) { + + /* If we had reserved the auto-inc lock for + some table in this SQL statement, we release it now */ + + srv_conc_enter_innodb(trx); + row_unlock_table_autoinc_for_mysql(trx); + srv_conc_exit_innodb(trx); + } + srv_conc_enter_innodb(trx); if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) { @@ -1900,6 +1911,55 @@ convert_search_mode_to_innobase( return(0); } +/* + BACKGROUND INFO: HOW A SELECT SQL QUERY IS EXECUTED + --------------------------------------------------- +The following does not cover all the details, but explains how we determine +the start of a new SQL statement, and what is associated with it. + +For each table in the database the MySQL interpreter may have several +table handle instances in use, also in a single SQL query. For each table +handle instance there is an InnoDB 'prebuilt' struct which contains most +of the InnoDB data associated with this table handle instance. + + A) if the user has not explicitly set any MySQL table level locks: + + 1) MySQL calls ::external_lock to set an 'intention' table level lock on +the table of the handle instance. There we set +prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should be set +true if we are taking this table handle instance to use in a new SQL +statement issued by the user. We also increment trx->n_mysql_tables_in_use. + + 2) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search +instructions to prebuilt->template of the table handle instance in +::index_read. The template is used to save CPU time in large joins. + + 3) In row_search_for_mysql, if prebuilt->sql_stat_start is true, we +allocate a new consistent read view for the trx if it does not yet have one, +or in the case of a locking read, set an InnoDB 'intention' table level +lock on the table. + + 4) We do the SELECT. MySQL may repeatedly call ::index_read for the +same table handle instance, if it is a join. + + 5) When the SELECT ends, MySQL removes its intention table level locks +in ::external_lock. When trx->n_mysql_tables_in_use drops to zero, + (a) we execute a COMMIT there if the autocommit is on, + (b) we also release possible 'SQL statement level resources' InnoDB may +have for this SQL statement. The MySQL interpreter does NOT execute +autocommit for pure read transactions, though it should. That is why the +table handler in that case has to execute the COMMIT in ::external_lock. + + B) If the user has explicitly set MySQL table level locks, then MySQL +does NOT call ::external_lock at the start of the statement. To determine +when we are at the start of a new SQL statement we at the start of +::index_read also compare the query id to the latest query id where the +table handle instance was used. If it has changed, we know we are at the +start of a new SQL statement. Since the query id can theoretically +overwrap, we use this test only as a secondary way of determining the +start of a new SQL statement. */ + + /************************************************************************** Positions an index cursor to the index specified in the handle. Fetches the row if any. */ From da35a07477a643beea0c1335fbf4fcf72ea9e333 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 30 Jul 2002 23:01:36 +0200 Subject: [PATCH 10/30] - added the init script to support the LSB init script spec - overhauled the RPM spec file (more macros, package descriptions) support-files/mysql.server.sh: - Added LSB-compliant init script header support-files/mysql.spec.sh: - Use some more macros (_mandir and _infodir) - Updated package description - Install binaries stripped to save disk space - Rearranged file list (make sure man pages are in the same package as the binaries) - clean up the BuildRoot directory afterwards - added mysqldumpslow to the server package --- support-files/mysql.server.sh | 12 +++ support-files/mysql.spec.sh | 180 ++++++++++++++++------------------ 2 files changed, 95 insertions(+), 97 deletions(-) diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index 62381ccf0d3..0d96cdc1bb1 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -13,6 +13,18 @@ # chkconfig: 2345 90 90 # description: A very fast and reliable SQL database engine. +# Comments to support LSB init script conventions +### BEGIN INIT INFO +# Provides: mysql +# Required-Start: $local_fs $network $remote_fs +# Required-Stop: $local_fs $network $remote_fs +# Default-Start: 3 5 +# Default-Stop: 3 5 +# Short-Description: start and stop MySLQ +# Description: MySQL is a very fast and reliable SQL database engine. +### END INIT INFO + + # The following variables are only set for letting mysql.server find things. # If you want to affect other MySQL variables, you should make your changes # in the /etc/my.cnf or other configuration files. diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 110d3c9e397..d1ee921e8db 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -18,54 +18,32 @@ Icon: mysql.gif URL: http://www.mysql.com/ Packager: Lenz Grimmer Vendor: MySQL AB +Requires: fileutils sh-utils Provides: msqlormysql MySQL-server mysql Obsoletes: mysql # Think about what you use here since the first step is to # run a rm -rf -BuildRoot: /var/tmp/mysql +BuildRoot: %{_tmppath}/%{name}-%{version}-build # From the manual %description -MySQL is a true multi-user, multi-threaded SQL (Structured Query -Language) database server. MySQL is a client/server implementation -that consists of a server daemon (mysqld) and many different client -programs/libraries. +The MySQL(TM) software delivers a very fast, multi-threaded, multi-user, +and robust SQL (Structured Query Language) database server. MySQL Server +is intended for mission-critical, heavy-load production systems as well +as for embedding into mass-deployed software. MySQL is a trademark of +MySQL AB. -The main goals of MySQL are speed, robustness and ease of use. MySQL -was originally developed because we needed a SQL server that could -handle very big databases with magnitude higher speed than what any -database vendor could offer to us. And since we did not need all the -features that made their server slow we made our own. We have now been -using MySQL since 1996 in a environment with more than 40 databases, -10,000 tables, of which more than 500 have more than 7 million -rows. This is about 200G of data. +The MySQL software has Dual Licensing, which means you can use the MySQL +software free of charge under the GNU General Public License +(http://www.gnu.org/licenses/). You can also purchase commercial MySQL +licenses from MySQL AB if you do not wish to be bound by the terms of +the GPL. See the chapter "Licensing and Support" in the manual for +further info. -The base upon which MySQL is built is a set of routines that have been -used in a highly demanding production environment for many -years. While MySQL is still in development, it already offers a rich -and highly useful function set. - -See the documentation for more information. - -%description -l pt_BR -O MySQL é um servidor de banco de dados SQL realmente multiusuário e\ -multi-tarefa. A linguagem SQL é a mais popular linguagem para banco de\ -dados no mundo. O MySQL é uma implementação cliente/servidor que\ -consiste de um servidor chamado mysqld e diversos\ -programas/bibliotecas clientes. Os principais objetivos do MySQL são:\ -velocidade, robustez e facilidade de uso. O MySQL foi originalmente\ -desenvolvido porque nós na Tcx precisávamos de um servidor SQL que\ -pudesse lidar com grandes bases de dados e com uma velocidade muito\ -maior do que a que qualquer vendedor podia nos oferecer. Estamos\ -usando\ -o MySQL desde 1996 em um ambiente com mais de 40 bases de dados com 10.000\ -tabelas, das quais mais de 500 têm mais de 7 milhões de linhas. Isto é o\ -equivalente a aproximadamente 50G de dados críticos. A base da construção do\ -MySQL é uma série de rotinas que foram usadas em um ambiente de produção com\ -alta demanda por muitos anos. Mesmo o MySQL estando ainda em desenvolvimento,\ -ele já oferece um conjunto de funções muito ricas e úteis. Veja a documentação\ -para maiores informações. +The MySQL web site (http://www.mysql.com/) provides the latest +news and information about the MySQL software. Also please see the +documentation and the manual for more information. %package client Release: %{release} @@ -86,7 +64,7 @@ Este pacote cont %package bench Release: %{release} -Requires: MySQL-client MySQL-DBI-perl-bin perl +Requires: %{name}-client MySQL-DBI-perl-bin perl Summary: MySQL - Benchmarks and test system Group: Applications/Databases Summary(pt_BR): MySQL - Medições de desempenho @@ -104,7 +82,7 @@ Este pacote cont %package devel Release: %{release} -Requires: MySQL-client +Requires: %{name}-client Summary: MySQL - Development header files and libraries Group: Applications/Databases Summary(pt_BR): MySQL - Medições de desempenho @@ -174,9 +152,9 @@ sh -c "PATH=\"${MYSQL_BUILD_PATH:-/bin:/usr/bin}\" \ --sysconfdir=/etc \ --datadir=/usr/share \ --localstatedir=/var/lib/mysql \ - --infodir=/usr/info \ + --infodir=%{_infodir} \ --includedir=/usr/include \ - --mandir=/usr/man \ + --mandir=%{_mandir} \ --with-comment=\"Official MySQL RPM\"; # Add this for more debugging support # --with-debug @@ -201,12 +179,9 @@ fi RBR=$RPM_BUILD_ROOT MBD=$RPM_BUILD_DIR/mysql-%{mysql_version} -if test -z "$RBR" -o "$RBR" = "/" -then - echo "RPM_BUILD_ROOT has insecure value" - exit 1 -fi -rm -rf $RBR + +# Clean up the BuildRoot first +[ "$RBR" != "/" ] && [ -d $RBR ] && rm -rf $RBR; mkdir -p $RBR # @@ -258,19 +233,18 @@ MBD=$RPM_BUILD_DIR/mysql-%{mysql_version} # Ensure that needed directories exists install -d $RBR/etc/{logrotate.d,rc.d/init.d} install -d $RBR/var/lib/mysql/mysql -install -d $RBR/usr/share/sql-bench -install -d $RBR/usr/share/mysql-test -install -d $RBR/usr/{sbin,share,man,include} -install -d $RBR/usr/doc/MySQL-%{mysql_version} -install -d $RBR/usr/lib -# Make install -make install DESTDIR=$RBR benchdir_root=/usr/share/ +install -d $RBR/usr/share/{sql-bench,mysql-test} +install -d $RBR%{_mandir} +install -d $RBR/usr/{sbin,lib,include} + +# Install all binaries stripped +make install-strip DESTDIR=$RBR benchdir_root=/usr/share/ # Install shared libraries (Disable for architectures that don't support it) (cd $RBR/usr/lib; tar xf $RBR/shared-libs.tar) -# install saved mysqld-max -install -m755 $MBD/sql/mysqld-max $RBR/usr/sbin/mysqld-max +# install and strip saved mysqld-max +install -s -m755 $MBD/sql/mysqld-max $RBR/usr/sbin/mysqld-max # install symbol files ( for stack trace resolution) install -m644 $MBD/sql/mysqld-max.sym $RBR/usr/lib/mysql/mysqld-max.sym @@ -280,18 +254,6 @@ install -m644 $MBD/sql/mysqld.sym $RBR/usr/lib/mysql/mysqld.sym install -m644 $MBD/support-files/mysql-log-rotate $RBR/etc/logrotate.d/mysql install -m755 $MBD/support-files/mysql.server $RBR/etc/rc.d/init.d/mysql -# Install docs -install -m644 $RPM_BUILD_DIR/mysql-%{mysql_version}/Docs/mysql.info \ - $RBR/usr/info/mysql.info -for file in README COPYING COPYING.LIB Docs/manual_toc.html Docs/manual.html \ - Docs/manual.txt Docs/manual.texi Docs/manual.ps \ - support-files/my-huge.cnf support-files/my-large.cnf \ - support-files/my-medium.cnf support-files/my-small.cnf -do - b=`basename $file` - install -m644 $MBD/$file $RBR/usr/doc/MySQL-%{mysql_version}/$b -done - %pre if test -x /etc/rc.d/init.d/mysql then @@ -358,33 +320,48 @@ fi # We do not remove the mysql user since it may still own a lot of # database files. +%clean +[ "$RBR" != "/" ] && [ -d $RBR ] && rm -rf $RBR; + %files -%attr(-, root, root) %doc /usr/doc/MySQL-%{mysql_version}/ +%defattr(-, root, root) +%doc %attr(644, root, root) COPYING COPYING.LIB README +%doc %attr(644, root, root) Docs/manual.{html,ps,texi,txt} Docs/manual_toc.html +%doc %attr(644, root, root) support-files/my-*.cnf + +%doc %attr(644, root, root) %{_infodir}/mysql.info* + +%doc %attr(644, root, man) %{_mandir}/man1/isamchk.1* +%doc %attr(644, root, man) %{_mandir}/man1/isamlog.1* +%doc %attr(644, root, man) %{_mandir}/man1/mysql_zap.1* +%doc %attr(644, root, man) %{_mandir}/man1/mysqld.1* +%doc %attr(644, root, man) %{_mandir}/man1/mysqld_multi.1* +%doc %attr(644, root, man) %{_mandir}/man1/safe_mysqld.1* +%doc %attr(644, root, man) %{_mandir}/man1/perror.1* +%doc %attr(644, root, man) %{_mandir}/man1/replace.1* %attr(755, root, root) /usr/bin/isamchk %attr(755, root, root) /usr/bin/isamlog -%attr(755, root, root) /usr/bin/pack_isam +%attr(755, root, root) /usr/bin/my_print_defaults %attr(755, root, root) /usr/bin/myisamchk %attr(755, root, root) /usr/bin/myisamlog %attr(755, root, root) /usr/bin/myisampack -%attr(755, root, root) /usr/bin/mysql_fix_privilege_tables %attr(755, root, root) /usr/bin/mysql_convert_table_format +%attr(755, root, root) /usr/bin/mysql_fix_privilege_tables %attr(755, root, root) /usr/bin/mysql_install_db %attr(755, root, root) /usr/bin/mysql_setpermission %attr(755, root, root) /usr/bin/mysql_zap %attr(755, root, root) /usr/bin/mysqlbug -%attr(755, root, root) /usr/bin/mysqltest +%attr(755, root, root) /usr/bin/mysqld_multi +%attr(755, root, root) /usr/bin/mysqldumpslow %attr(755, root, root) /usr/bin/mysqlhotcopy +%attr(755, root, root) /usr/bin/mysqltest +%attr(755, root, root) /usr/bin/pack_isam %attr(755, root, root) /usr/bin/perror %attr(755, root, root) /usr/bin/replace -%attr(755, root, root) /usr/bin/resolveip %attr(755, root, root) /usr/bin/resolve_stack_dump +%attr(755, root, root) /usr/bin/resolveip %attr(755, root, root) /usr/bin/safe_mysqld -%attr(755, root, root) /usr/bin/mysqld_multi -%attr(755, root, root) /usr/bin/my_print_defaults -%attr(755, root, root) /usr/bin/mysqldumpslow - -%attr(644, root, root) /usr/info/mysql.info* %attr(755, root, root) /usr/sbin/mysqld %attr(644, root, root) /usr/lib/mysql/mysqld.sym @@ -395,30 +372,23 @@ fi %attr(755, root, root) /usr/share/mysql/ %files client +%defattr(-, root, root) %attr(755, root, root) /usr/bin/msql2mysql %attr(755, root, root) /usr/bin/mysql +%attr(755, root, root) /usr/bin/mysql_find_rows %attr(755, root, root) /usr/bin/mysqlaccess %attr(755, root, root) /usr/bin/mysqladmin +%attr(755, root, root) /usr/bin/mysqlbinlog %attr(755, root, root) /usr/bin/mysqlcheck -%attr(755, root, root) /usr/bin/mysql_find_rows %attr(755, root, root) /usr/bin/mysqldump %attr(755, root, root) /usr/bin/mysqlimport %attr(755, root, root) /usr/bin/mysqlshow -%attr(755, root, root) /usr/bin/mysqlbinlog -%attr(644, root, man) %doc /usr/man/man1/mysql.1* -%attr(644, root, man) %doc /usr/man/man1/isamchk.1* -%attr(644, root, man) %doc /usr/man/man1/isamlog.1* -%attr(644, root, man) %doc /usr/man/man1/mysql_zap.1* -%attr(644, root, man) %doc /usr/man/man1/mysqlaccess.1* -%attr(644, root, man) %doc /usr/man/man1/mysqladmin.1* -%attr(644, root, man) %doc /usr/man/man1/mysqld.1* -%attr(644, root, man) %doc /usr/man/man1/mysqld_multi.1* -%attr(644, root, man) %doc /usr/man/man1/mysqldump.1* -%attr(644, root, man) %doc /usr/man/man1/mysqlshow.1* -%attr(644, root, man) %doc /usr/man/man1/perror.1* -%attr(644, root, man) %doc /usr/man/man1/replace.1* -%attr(644, root, man) %doc /usr/man/man1/safe_mysqld.1* +%doc %attr(644, root, man) %{_mandir}/man1/mysql.1* +%doc %attr(644, root, man) %{_mandir}/man1/mysqlaccess.1* +%doc %attr(644, root, man) %{_mandir}/man1/mysqladmin.1* +%doc %attr(644, root, man) %{_mandir}/man1/mysqldump.1* +%doc %attr(644, root, man) %{_mandir}/man1/mysqlshow.1* %post shared /sbin/ldconfig @@ -427,25 +397,41 @@ fi /sbin/ldconfig %files devel +%defattr(644 root, root) %attr(755, root, root) /usr/bin/comp_err -%attr(755, root, root) /usr/include/mysql/ -%attr(755, root, root) /usr/lib/mysql/*.a %attr(755, root, root) /usr/bin/mysql_config +%dir %attr(755, root, root) /usr/include/mysql +%dir %attr(755, root, root) /usr/lib/mysql +/usr/include/mysql/* +/usr/lib/mysql/*.a %files shared +%defattr(755 root, root) # Shared libraries (omit for architectures that don't support them) -%attr(755, root, root) /usr/lib/*.so* +/usr/lib/*.so* %files bench +%defattr(-, root, root) %attr(-, root, root) /usr/share/sql-bench %attr(-, root, root) /usr/share/mysql-test %files Max +%defattr(-, root, root) %attr(755, root, root) /usr/sbin/mysqld-max %attr(644, root, root) /usr/lib/mysql/mysqld-max.sym %changelog +* Thu Jul 30 2002 Lenz Grimmer + +- Use some more macros (mandir and infodir) +- Updated package description +- Install binaries stripped to save disk space +- Rearranged file list (make sure man pages are in + the same package as the binaries) +- clean up the BuildRoot directory afterwards +- added mysqldumpslow to the server package + * Mon Jul 15 2002 Lenz Grimmer - updated Packager tag From 39ee64cd7e7504b7958953b554c8eccf87c7e754 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 31 Jul 2002 00:47:20 +0300 Subject: [PATCH 11/30] Many files: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log sql/ha_innobase.h: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log sql/ha_innobase.cc: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/buf/buf0buf.c: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/dict/dict0dict.c: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/fil/fil0fil.c: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/fsp/fsp0fsp.c: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/ha/ha0ha.c: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/include/dict0dict.h: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/include/dict0mem.h: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/include/dyn0dyn.h: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/include/fsp0fsp.h: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/include/log0log.h: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/include/log0recv.h: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/include/trx0sys.h: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/include/trx0trx.h: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/include/log0log.ic: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/lock/lock0lock.c: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/log/log0log.c: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/log/log0recv.c: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/mem/mem0dbg.c: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/row/row0mysql.c: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/srv/srv0srv.c: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/srv/srv0start.c: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/trx/trx0sys.c: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log innobase/trx/trx0trx.c: Merge InnoDB-3.23.52c; improve AUTO-INC algorithm with SHOW TABLE STATUS; new checksum in log --- innobase/buf/buf0buf.c | 22 ++-- innobase/dict/dict0dict.c | 39 ++++-- innobase/fil/fil0fil.c | 2 +- innobase/fsp/fsp0fsp.c | 30 +++++ innobase/ha/ha0ha.c | 9 +- innobase/include/dict0dict.h | 20 +++- innobase/include/dict0mem.h | 4 +- innobase/include/dyn0dyn.h | 4 +- innobase/include/fsp0fsp.h | 10 ++ innobase/include/log0log.h | 34 ++++-- innobase/include/log0log.ic | 85 ++++++++----- innobase/include/log0recv.h | 6 + innobase/include/trx0sys.h | 13 +- innobase/include/trx0trx.h | 4 + innobase/lock/lock0lock.c | 9 +- innobase/log/log0log.c | 20 +--- innobase/log/log0recv.c | 167 ++++++++++++++------------ innobase/mem/mem0dbg.c | 2 +- innobase/row/row0mysql.c | 5 + innobase/srv/srv0srv.c | 13 +- innobase/srv/srv0start.c | 28 +++++ innobase/trx/trx0sys.c | 28 +++++ innobase/trx/trx0trx.c | 64 ++++++---- sql/ha_innobase.cc | 225 ++++++++++++++++++++++++----------- sql/ha_innobase.h | 1 + 25 files changed, 589 insertions(+), 255 deletions(-) diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index 80e89e16588..e3a4ae50a23 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -1707,10 +1707,11 @@ buf_print(void) mutex_enter(&(buf_pool->mutex)); - printf("LRU len %lu \n", UT_LIST_GET_LEN(buf_pool->LRU)); - printf("free len %lu \n", UT_LIST_GET_LEN(buf_pool->free)); - printf("flush len %lu \n", UT_LIST_GET_LEN(buf_pool->flush_list)); printf("buf_pool size %lu \n", size); + printf("database pages %lu \n", UT_LIST_GET_LEN(buf_pool->LRU)); + printf("free pages %lu \n", UT_LIST_GET_LEN(buf_pool->free)); + printf("modified database pages %lu \n", + UT_LIST_GET_LEN(buf_pool->flush_list)); printf("n pending reads %lu \n", buf_pool->n_pend_reads); @@ -1819,13 +1820,20 @@ buf_print_io( mutex_enter(&(buf_pool->mutex)); buf += sprintf(buf, - "Free list length %lu \n", UT_LIST_GET_LEN(buf_pool->free)); + "Buffer pool size %lu\n", size); buf += sprintf(buf, - "LRU list length %lu \n", UT_LIST_GET_LEN(buf_pool->LRU)); + "Free buffers %lu\n", UT_LIST_GET_LEN(buf_pool->free)); buf += sprintf(buf, - "Flush list length %lu \n", + "Database pages %lu\n", UT_LIST_GET_LEN(buf_pool->LRU)); +/* + buf += sprintf(buf, + "Lock heap buffers %lu\n", buf_pool->n_lock_heap_pages); + buf += sprintf(buf, + "Hash index buffers %lu\n", buf_pool->n_adaptive_hash_pages); +*/ + buf += sprintf(buf, + "Modified db pages %lu\n", UT_LIST_GET_LEN(buf_pool->flush_list)); - buf += sprintf(buf, "Buffer pool size %lu\n", size); buf += sprintf(buf, "Pending reads %lu \n", buf_pool->n_pend_reads); diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 9ed1d088290..65f40d345d8 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -261,7 +261,7 @@ dict_table_get_index_noninline( { return(dict_table_get_index(table, name)); } - + /************************************************************************ Initializes the autoinc counter. It is not an error to initialize an already initialized counter. */ @@ -270,7 +270,7 @@ void dict_table_autoinc_initialize( /*==========================*/ dict_table_t* table, /* in: table */ - ib_longlong value) /* in: value which was assigned to a row */ + ib_longlong value) /* in: next value to assign to a row */ { mutex_enter(&(table->autoinc_mutex)); @@ -281,8 +281,8 @@ dict_table_autoinc_initialize( } /************************************************************************ -Gets the next autoinc value, 0 if not yet initialized. If initialized, -increments the counter by 1. */ +Gets the next autoinc value (== autoinc counter value), 0 if not yet +initialized. If initialized, increments the counter by 1. */ ib_longlong dict_table_autoinc_get( @@ -298,8 +298,8 @@ dict_table_autoinc_get( value = 0; } else { - table->autoinc = table->autoinc + 1; value = table->autoinc; + table->autoinc = table->autoinc + 1; } mutex_exit(&(table->autoinc_mutex)); @@ -334,20 +334,43 @@ dict_table_autoinc_read( } /************************************************************************ -Updates the autoinc counter if the value supplied is bigger than the +Peeks the autoinc counter value, 0 if not yet initialized. Does not +increment the counter. The read not protected by any mutex! */ + +ib_longlong +dict_table_autoinc_peek( +/*====================*/ + /* out: value of the counter */ + dict_table_t* table) /* in: table */ +{ + ib_longlong value; + + if (!table->autoinc_inited) { + + value = 0; + } else { + value = table->autoinc; + } + + return(value); +} + +/************************************************************************ +Updates the autoinc counter if the value supplied is equal or bigger than the current value. If not inited, does nothing. */ void dict_table_autoinc_update( /*======================*/ + dict_table_t* table, /* in: table */ ib_longlong value) /* in: value which was assigned to a row */ { mutex_enter(&(table->autoinc_mutex)); if (table->autoinc_inited) { - if (value > table->autoinc) { - table->autoinc = value; + if (value >= table->autoinc) { + table->autoinc = value + 1; } } diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index 910ca842f21..29bd52ff94f 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -578,7 +578,7 @@ fil_read_flushed_lsn_and_arch_log_no( ulint arch_log_no; buf2 = ut_malloc(2 * UNIV_PAGE_SIZE); - /* Align the memory for a possibel read from a raw device */ + /* Align the memory for a possible read from a raw device */ buf = ut_align(buf2, UNIV_PAGE_SIZE); os_file_read(data_file, buf, 0, 0, UNIV_PAGE_SIZE); diff --git a/innobase/fsp/fsp0fsp.c b/innobase/fsp/fsp0fsp.c index d78db2a5ea8..679af640b99 100644 --- a/innobase/fsp/fsp0fsp.c +++ b/innobase/fsp/fsp0fsp.c @@ -933,6 +933,36 @@ fsp_header_get_free_limit( return(limit); } +/************************************************************************** +Gets the size of the tablespace from the tablespace header. If we do not +have an auto-extending data file, this should be equal to the size of the +data files. If there is an auto-extending data file, this can be smaller. */ + +ulint +fsp_header_get_tablespace_size( +/*===========================*/ + /* out: size in pages */ + ulint space) /* in: space id */ +{ + fsp_header_t* header; + ulint size; + mtr_t mtr; + + ut_a(space == 0); /* We have only one log_fsp_current_... variable */ + + mtr_start(&mtr); + + mtr_x_lock(fil_space_get_latch(space), &mtr); + + header = fsp_get_space_header(space, &mtr); + + size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr); + + mtr_commit(&mtr); + + return(size); +} + /*************************************************************************** Tries to extend the last data file file if it is defined as auto-extending. */ static diff --git a/innobase/ha/ha0ha.c b/innobase/ha/ha0ha.c index c3ad6cdca76..acde236bb2f 100644 --- a/innobase/ha/ha0ha.c +++ b/innobase/ha/ha0ha.c @@ -335,6 +335,11 @@ ha_print_info( } } - buf += sprintf(buf, "Hash table size %lu, used cells %lu\n", - hash_get_n_cells(table), cells); + buf += sprintf(buf, +"Hash table size %lu, used cells %lu", hash_get_n_cells(table), cells); + + if (table->heaps == NULL && table->heap != NULL) { + buf += sprintf(buf, +", node heap has %lu buffer(s)\n", UT_LIST_GET_LEN(table->heap->base)); + } } diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index fd79e17090a..832654d2666 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -96,17 +96,17 @@ dict_col_get_clust_pos( /*===================*/ dict_col_t* col); /************************************************************************ -Initializes the autoinc counter. It is not an error to initialize already +Initializes the autoinc counter. It is not an error to initialize an already initialized counter. */ void dict_table_autoinc_initialize( /*==========================*/ dict_table_t* table, /* in: table */ - ib_longlong value); /* in: value which was assigned to a row */ + ib_longlong value); /* in: next value to assign to a row */ /************************************************************************ -Gets the next autoinc value, 0 if not yet initialized. If initialized, -increments the counter by 1. */ +Gets the next autoinc value (== autoinc counter value), 0 if not yet +initialized. If initialized, increments the counter by 1. */ ib_longlong dict_table_autoinc_get( @@ -123,12 +123,22 @@ dict_table_autoinc_read( /* out: value of the counter */ dict_table_t* table); /* in: table */ /************************************************************************ -Updates the autoinc counter if the value supplied is bigger than the +Peeks the autoinc counter value, 0 if not yet initialized. Does not +increment the counter. The read not protected by any mutex! */ + +ib_longlong +dict_table_autoinc_peek( +/*====================*/ + /* out: value of the counter */ + dict_table_t* table); /* in: table */ +/************************************************************************ +Updates the autoinc counter if the value supplied is equal or bigger than the current value. If not inited, does nothing. */ void dict_table_autoinc_update( /*======================*/ + dict_table_t* table, /* in: table */ ib_longlong value); /* in: value which was assigned to a row */ /************************************************************************** diff --git a/innobase/include/dict0mem.h b/innobase/include/dict0mem.h index ef15c99fdba..cc27f2bad12 100644 --- a/innobase/include/dict0mem.h +++ b/innobase/include/dict0mem.h @@ -388,8 +388,8 @@ struct dict_table_struct{ /* TRUE if the autoinc counter has been inited; MySQL gets the init value by executing SELECT MAX(auto inc column) */ - ib_longlong autoinc;/* autoinc counter value already given to - a row */ + ib_longlong autoinc;/* autoinc counter value to give to the + next inserted row */ ulint magic_n;/* magic number */ }; #define DICT_TABLE_MAGIC_N 76333786 diff --git a/innobase/include/dyn0dyn.h b/innobase/include/dyn0dyn.h index 6f08da1533b..504aade29d2 100644 --- a/innobase/include/dyn0dyn.h +++ b/innobase/include/dyn0dyn.h @@ -17,7 +17,9 @@ typedef struct dyn_block_struct dyn_block_t; typedef dyn_block_t dyn_array_t; -/* This must be > MLOG_BUF_MARGIN + 30 */ +/* This is the initial 'payload' size of a dynamic array; +this must be > MLOG_BUF_MARGIN + 30! */ + #define DYN_ARRAY_DATA_SIZE 512 /************************************************************************* diff --git a/innobase/include/fsp0fsp.h b/innobase/include/fsp0fsp.h index a0197ec2d97..3494f336b1e 100644 --- a/innobase/include/fsp0fsp.h +++ b/innobase/include/fsp0fsp.h @@ -57,6 +57,16 @@ fsp_header_get_free_limit( /* out: free limit in megabytes */ ulint space); /* in: space id */ /************************************************************************** +Gets the size of the tablespace from the tablespace header. If we do not +have an auto-extending data file, this should be equal to the size of the +data files. If there is an auto-extending data file, this can be smaller. */ + +ulint +fsp_header_get_tablespace_size( +/*===========================*/ + /* out: size in pages */ + ulint space); /* in: space id */ +/************************************************************************** Initializes the space header of a new created space. */ void diff --git a/innobase/include/log0log.h b/innobase/include/log0log.h index 5d848b85658..4358577c59c 100644 --- a/innobase/include/log0log.h +++ b/innobase/include/log0log.h @@ -431,15 +431,30 @@ log_block_set_data_len( byte* log_block, /* in: log block */ ulint len); /* in: data length */ /**************************************************************** -Gets a log block number stored in the trailer. */ +Calculates the checksum for a log block. */ UNIV_INLINE ulint -log_block_get_trl_no( -/*=================*/ - /* out: log block number stored in the block - trailer */ +log_block_calc_checksum( +/*====================*/ + /* out: checksum */ + byte* block); /* in: log block */ +/**************************************************************** +Gets a log block checksum field value. */ +UNIV_INLINE +ulint +log_block_get_checksum( +/*===================*/ + /* out: checksum */ byte* log_block); /* in: log block */ /**************************************************************** +Sets a log block checksum field value. */ +UNIV_INLINE +void +log_block_set_checksum( +/*===================*/ + byte* log_block, /* in: log block */ + ulint checksum); /* in: checksum */ +/**************************************************************** Gets a log block first mtr log record group offset. */ UNIV_INLINE ulint @@ -544,10 +559,11 @@ extern log_t* log_sys; bytes */ /* Offsets of a log block trailer from the end of the block */ -#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_CHECKSUM 4 /* 4 byte checksum of the log block + contents; in InnoDB versions + < 3.23.52 this did not contain the + checksum but the same value as + .._HDR_NO */ #define LOG_BLOCK_TRL_SIZE 4 /* trailer size in bytes */ /* Offsets for a checkpoint field */ diff --git a/innobase/include/log0log.ic b/innobase/include/log0log.ic index 36e65239374..9167246fe45 100644 --- a/innobase/include/log0log.ic +++ b/innobase/include/log0log.ic @@ -169,33 +169,6 @@ log_block_set_checkpoint_no( ut_dulint_get_low(no)); } -/**************************************************************** -Gets a log block number stored in the trailer. */ -UNIV_INLINE -ulint -log_block_get_trl_no( -/*=================*/ - /* out: log block number stored in the block - trailer */ - byte* log_block) /* in: log block */ -{ - return(mach_read_from_3(log_block + OS_FILE_LOG_BLOCK_SIZE - - LOG_BLOCK_TRL_NO)); -} - -/**************************************************************** -Sets the log block number stored in the trailer. */ -UNIV_INLINE -void -log_block_set_trl_no( -/*=================*/ - byte* log_block, /* in: log block */ - ulint n) /* in: log block number */ -{ - mach_write_to_3(log_block + OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_NO, - n & 0xFFFFFF); -} - /**************************************************************** Converts a lsn to a log block number. */ UNIV_INLINE @@ -216,6 +189,61 @@ log_block_convert_lsn_to_no( return(no + 1); } +/**************************************************************** +Calculates the checksum for a log block. */ +UNIV_INLINE +ulint +log_block_calc_checksum( +/*====================*/ + /* out: checksum */ + byte* block) /* in: log block */ +{ + ulint sum; + ulint sh; + ulint i; + + sum = 1; + sh = 0; + + for (i = 0; i < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE; i++) { + sum = sum & 0x7FFFFFFF; + sum += ((ulint)(*(block + i))) << sh; + sh++; + if (sh > 24) { + sh = 0; + } + } + + return(sum); +} + +/**************************************************************** +Gets a log block checksum field value. */ +UNIV_INLINE +ulint +log_block_get_checksum( +/*===================*/ + /* out: checksum */ + byte* log_block) /* in: log block */ +{ + return(mach_read_from_4(log_block + OS_FILE_LOG_BLOCK_SIZE + - LOG_BLOCK_CHECKSUM)); +} + +/**************************************************************** +Sets a log block checksum field value. */ +UNIV_INLINE +void +log_block_set_checksum( +/*===================*/ + byte* log_block, /* in: log block */ + ulint checksum) /* in: checksum */ +{ + mach_write_to_4(log_block + OS_FILE_LOG_BLOCK_SIZE + - LOG_BLOCK_CHECKSUM, + checksum); +} + /**************************************************************** Initializes a log block in the log buffer. */ UNIV_INLINE @@ -232,7 +260,6 @@ log_block_init( no = log_block_convert_lsn_to_no(lsn); log_block_set_hdr_no(log_block, no); - log_block_set_trl_no(log_block, no); log_block_set_data_len(log_block, LOG_BLOCK_HDR_SIZE); log_block_set_first_rec_group(log_block, 0); @@ -256,7 +283,7 @@ log_block_init_in_old_format( 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_CHECKSUM, no); log_block_set_data_len(log_block, LOG_BLOCK_HDR_SIZE); log_block_set_first_rec_group(log_block, 0); } diff --git a/innobase/include/log0recv.h b/innobase/include/log0recv.h index 0825325965d..65f80deee93 100644 --- a/innobase/include/log0recv.h +++ b/innobase/include/log0recv.h @@ -313,6 +313,10 @@ struct recv_sys_struct{ this lsn */ dulint limit_lsn;/* recovery should be made at most up to this lsn */ + ibool found_corrupt_log; + /* this is set to TRUE if we during log + scan find a corrupt log block, or a corrupt + log record */ log_group_t* archive_group; /* in archive recovery: the log group whose archive is read */ @@ -328,6 +332,8 @@ extern ibool recv_recovery_on; extern ibool recv_no_ibuf_operations; extern ibool recv_needed_recovery; +extern ibool recv_is_making_a_backup; + /* Size of the parsing buffer; it must accommodate RECV_SCAN_SIZE many times! */ #define RECV_PARSING_BUF_SIZE (2 * 1024 * 1024) diff --git a/innobase/include/trx0sys.h b/innobase/include/trx0sys.h index b08df7f6901..a54a6424a4f 100644 --- a/innobase/include/trx0sys.h +++ b/innobase/include/trx0sys.h @@ -257,6 +257,15 @@ void trx_sys_print_mysql_binlog_offset(void); /*===================================*/ /********************************************************************* +Prints to stdout the MySQL binlog info in the system header if the +magic number shows it valid. */ + +void +trx_sys_print_mysql_binlog_offset_from_page( +/*========================================*/ + byte* page); /* in: buffer containing the trx system header page, + i.e., page number TRX_SYS_PAGE_NO in the tablespace */ +/********************************************************************* Prints to stderr the MySQL master log offset info in the trx system header if the magic number shows it valid. */ @@ -300,11 +309,11 @@ therefore 256; each slot is currently 8 bytes in size */ #define TRX_SYS_MYSQL_LOG_NAME_LEN 512 #define TRX_SYS_MYSQL_LOG_MAGIC_N 873422344 -/* The offset of the MySQL replication info on the trx system header page; +/* The offset of the MySQL replication info in the trx system header; 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 in the trx system header */ #define TRX_SYS_MYSQL_LOG_INFO (UNIV_PAGE_SIZE - 1000) #define TRX_SYS_MYSQL_LOG_MAGIC_N_FLD 0 /* magic number which shows if we have valid data in the diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 83789966514..6e98f22c34b 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -309,6 +309,9 @@ struct trx_struct{ of view of concurrency control: TRX_ACTIVE, TRX_COMMITTED_IN_MEMORY, ... */ + time_t start_time; /* time the trx object was created + or the state last time became + TRX_ACTIVE */ ibool check_foreigns; /* normally TRUE, but if the user wants to suppress foreign key checks, (in table imports, for example) we @@ -468,6 +471,7 @@ struct trx_struct{ TRX_QUE_LOCK_WAIT, this points to the lock request, otherwise this is NULL */ + time_t wait_started; /* lock wait started at this time */ UT_LIST_BASE_NODE_T(que_thr_t) wait_thrs; /* query threads belonging to this trx that are in the QUE_THR_LOCK_WAIT diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index f7ba49004d7..ea035dbdeb0 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -1565,6 +1565,7 @@ index->table_name); } trx->que_state = TRX_QUE_LOCK_WAIT; + trx->wait_started = time(NULL); ut_a(que_thr_stop(thr)); @@ -2961,6 +2962,7 @@ table->name); } trx->que_state = TRX_QUE_LOCK_WAIT; + trx->wait_started = time(NULL); ut_a(que_thr_stop(thr)); @@ -3503,6 +3505,10 @@ lock_print_info( return; } + buf += sprintf(buf, "Number of sessions %lu\n", + UT_LIST_GET_LEN(trx_sys->mysql_trx_list) + + UT_LIST_GET_LEN(trx_sys->trx_list)); + buf += sprintf(buf, "Trx id counter %lu %lu\n", ut_dulint_get_high(trx_sys->max_trx_id), ut_dulint_get_low(trx_sys->max_trx_id)); @@ -3587,7 +3593,8 @@ loop: if (trx->que_state == TRX_QUE_LOCK_WAIT) { buf += sprintf(buf, - "------------------TRX IS WAITING FOR THE LOCK:\n"); + "------- TRX HAS BEEN WAITING %lu SEC FOR THIS LOCK TO BE GRANTED:\n", + (ulint)difftime(time(NULL), trx->wait_started)); if (lock_get_type(trx->wait_lock) == LOCK_REC) { lock_rec_print(buf, trx->wait_lock); diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c index 9d79c19a586..644d53ac273 100644 --- a/innobase/log/log0log.c +++ b/innobase/log/log0log.c @@ -270,7 +270,7 @@ part_loop: log->lsn = ut_dulint_add(log->lsn, len); - /* Initialize the next block header and trailer */ + /* Initialize the next block header */ log_block_init(log_block + OS_FILE_LOG_BLOCK_SIZE, log->lsn); } else { log->lsn = ut_dulint_add(log->lsn, len); @@ -1070,28 +1070,16 @@ log_group_file_header_flush( } /********************************************************** -Stores a 1-byte checksum to the trailer checksum field of a log block +Stores a 4-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. */ +check the consistency of a log block. */ 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); + log_block_set_checksum(block, log_block_calc_checksum(block)); } /********************************************************** diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c index 53f75c176ea..62031005e05 100644 --- a/innobase/log/log0recv.c +++ b/innobase/log/log0recv.c @@ -63,7 +63,7 @@ log scan */ ulint recv_scan_print_counter = 0; ibool recv_is_from_backup = FALSE; - +ibool recv_is_making_a_backup = FALSE; /************************************************************ Creates the recovery system. */ @@ -124,6 +124,8 @@ recv_sys_init( recv_sys->last_block = ut_align(recv_sys->last_block_buf_start, OS_FILE_LOG_BLOCK_SIZE); + recv_sys->found_corrupt_log = FALSE; + mutex_exit(&(recv_sys->mutex)); } @@ -569,9 +571,9 @@ recv_read_cp_info_for_backup( } /********************************************************** -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. */ +Checks the 4-byte checksum to the trailer checksum field of a log block. +We also accept a log block in the old format < InnoDB-3.23.52 where the +checksum field contains the log block number. */ static ibool log_block_checksum_is_ok_or_old_format( @@ -580,29 +582,12 @@ log_block_checksum_is_ok_or_old_format( 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)) { + if (log_block_calc_checksum(block) == log_block_get_checksum(block)) { 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)) { + if (log_block_get_hdr_no(block) == log_block_get_checksum(block)) { /* We assume the log block is in the format of InnoDB version < 3.23.52 and the block is ok */ @@ -649,23 +634,20 @@ recv_scan_log_seg_for_backup( /* fprintf(stderr, "Log block header no %lu\n", no); */ - if ((no & 0xFFFFFF) != log_block_get_trl_no(log_block) - || no != log_block_convert_lsn_to_no(*scanned_lsn) + if (no != log_block_convert_lsn_to_no(*scanned_lsn) || !log_block_checksum_is_ok_or_old_format(log_block)) { /* printf( -"Log block n:o %lu, trailer n:o %lu, scanned lsn n:o %lu\n", - no, log_block_get_trl_no(log_block), - log_block_convert_lsn_to_no(*scanned_lsn)); +"Log block n:o %lu, scanned lsn n:o %lu\n", + no, log_block_convert_lsn_to_no(*scanned_lsn)); */ /* Garbage or an incompletely written log block */ log_block += OS_FILE_LOG_BLOCK_SIZE; /* printf( -"Next log block n:o %lu, trailer n:o %lu\n", - log_block_get_hdr_no(log_block), - log_block_get_trl_no(log_block)); +"Next log block n:o %lu\n", + log_block_get_hdr_no(log_block)); */ break; } @@ -713,7 +695,7 @@ byte* recv_parse_or_apply_log_rec_body( /*=============================*/ /* out: log record end, NULL if not a complete - record */ + record, or a corrupt record */ byte type, /* in: type */ byte* ptr, /* in: pointer to a buffer */ byte* end_ptr,/* in: pointer to the buffer end */ @@ -794,8 +776,11 @@ recv_parse_or_apply_log_rec_body( "InnoDB: is possible that the log scan did not proceed\n" "InnoDB: far enough in recovery. Please run CHECK TABLE\n" "InnoDB: on your InnoDB tables to check that they are ok!\n" - "InnoDB: Corrupt log record type %lu\n", - (ulint)type); + "InnoDB: Corrupt log record type %lu\n, lsn %lu %lu\n", + (ulint)type, ut_dulint_get_high(recv_sys->recovered_lsn), + ut_dulint_get_low(recv_sys->recovered_lsn)); + + recv_sys->found_corrupt_log = TRUE; } ut_ad(!page || new_ptr); @@ -1399,18 +1384,30 @@ recv_apply_log_recs_for_backup( OS_FILE_OPEN, OS_FILE_READ_WRITE, &success); - ut_a(success); + if (!success) { + printf( +"InnoDB: Error: cannot open %lu'th data file %s\n", nth_file); + + exit(1); + } } recv_addr = recv_get_fil_addr_struct(0, i); if (recv_addr != NULL) { - os_file_read(data_file, page, + success = os_file_read(data_file, page, (nth_page_in_file << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFF, nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT), UNIV_PAGE_SIZE); + if (!success) { + printf( +"InnoDB: Error: cannot read page no %lu from %lu'th data file %s\n", + nth_page_in_file, nth_file); + exit(1); + } + /* 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 @@ -1425,12 +1422,19 @@ recv_apply_log_recs_for_backup( mach_read_from_8(page + FIL_PAGE_LSN), 0, i); - os_file_write(data_files[nth_file], + success = os_file_write(data_files[nth_file], data_file, page, (nth_page_in_file << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFF, nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT), UNIV_PAGE_SIZE); + if (!success) { + printf( +"InnoDB: Error: cannot write page no %lu to %lu'th data file %s\n", + nth_page_in_file, nth_file); + + exit(1); + } } if ((100 * i) / n_pages_total @@ -1647,7 +1651,7 @@ ulint recv_parse_log_rec( /*===============*/ /* out: length of the record, or 0 if the record was - not complete */ + not complete or it was corrupt */ byte* ptr, /* in: pointer to a buffer */ byte* end_ptr,/* in: pointer to the buffer end */ byte* type, /* out: type */ @@ -1679,16 +1683,8 @@ recv_parse_log_rec( new_ptr = mlog_parse_initial_log_record(ptr, end_ptr, type, space, page_no); - - /* If the operating system writes to the log complete 512-byte - blocks, we should not get the warnings below in recovery. - A warning means that the header and the trailer appeared ok - in a 512-byte block, but in the middle there was something wrong. - TODO: (1) add similar warnings in the case there is an incompletely - written log record which does not extend to the boundary of a - 512-byte block. (2) Add a checksum to a log block. */ - if (!new_ptr) { + return(0); } @@ -1696,12 +1692,17 @@ recv_parse_log_rec( if (*space != 0 || *page_no > 0x8FFFFFFF) { fprintf(stderr, - "InnoDB: WARNING: the log file may have been corrupt and it\n" - "InnoDB: is possible that the log scan did not proceed\n" - "InnoDB: far enough in recovery. Please run CHECK TABLE\n" - "InnoDB: on your InnoDB tables to check that they are ok!\n" - "InnoDB: Corrupt log record type %lu, space id %lu, page no %lu\n", - (ulint)(*type), *space, *page_no); + "InnoDB: WARNING: the log file may have been corrupt and it\n" + "InnoDB: is possible that the log scan did not proceed\n" + "InnoDB: far enough in recovery. Please run CHECK TABLE\n" + "InnoDB: on your InnoDB tables to check that they are ok!\n" + "InnoDB: Corrupt log record type %lu, space id %lu, page no %lu\n", + "InnoDB: lsn %lu %lu\n", + (ulint)(*type), *space, *page_no, + ut_dulint_get_high(recv_sys->recovered_lsn), + ut_dulint_get_low(recv_sys->recovered_lsn)); + + recv_sys->found_corrupt_log = TRUE; return(0); } @@ -1790,6 +1791,7 @@ recv_parse_log_recs( ulint page_no; byte* body; ulint n_recs; + char err_buf[2500]; ut_ad(mutex_own(&(log_sys->mutex))); ut_ad(!ut_dulint_is_zero(recv_sys->parse_start_lsn)); @@ -1813,7 +1815,18 @@ loop: len = recv_parse_log_rec(ptr, end_ptr, &type, &space, &page_no, &body); if (len == 0) { - + if (recv_sys->found_corrupt_log) { + + ut_sprintf_buf(err_buf, + recv_sys->buf + ut_calc_align_down( + recv_sys->recovered_offset, + OS_FILE_LOG_BLOCK_SIZE) - 8, + OS_FILE_LOG_BLOCK_SIZE + 16); + + fprintf(stderr, +"InnoDB: hex dump of a corrupt log segment: %s\n", err_buf); + } + return(FALSE); } @@ -1851,9 +1864,10 @@ loop: #ifdef UNIV_LOG_DEBUG recv_check_incomplete_log_recs(ptr, len); #endif - recv_update_replicate(type, space, page_no, body, +/* recv_update_replicate(type, space, page_no, body, ptr + len); recv_compare_replicate(space, page_no); +*/ } } else { /* Check that all the records associated with the single mtr @@ -1867,7 +1881,18 @@ loop: &page_no, &body); if (len == 0) { - return(FALSE); + if (recv_sys->found_corrupt_log) { + ut_sprintf_buf(err_buf, + recv_sys->buf + ut_calc_align_down( + recv_sys->recovered_offset, + OS_FILE_LOG_BLOCK_SIZE) - 8, + OS_FILE_LOG_BLOCK_SIZE + 16); + + fprintf(stderr, +"InnoDB: hex dump of a corrupt log segment: %s\n", err_buf); + } + + return(FALSE); } if ((!store_to_hash) && (type != MLOG_MULTI_REC_END)) { @@ -1876,8 +1901,10 @@ loop: #ifdef UNIV_LOG_DEBUG recv_check_incomplete_log_recs(ptr, len); #endif +/* recv_update_replicate(type, space, page_no, body, ptr + len); +*/ } if (log_debug_writes) { @@ -1941,7 +1968,7 @@ loop: page has become identical with the original page */ - recv_compare_replicate(space, page_no); +/* recv_compare_replicate(space, page_no); */ } ptr += len; @@ -2095,32 +2122,19 @@ recv_scan_log_recs( /* fprintf(stderr, "Log block header no %lu\n", no); */ - if ((no & 0xFFFFFF) != log_block_get_trl_no(log_block) - || no != log_block_convert_lsn_to_no(scanned_lsn) + if (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) + if (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", +"InnoDB: ok header, but checksum field contains %lu, should be %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)); + log_block_get_checksum(log_block), + log_block_calc_checksum(log_block)); } /* Garbage or an incompletely written log block */ @@ -2213,7 +2227,8 @@ recv_scan_log_recs( *group_scanned_lsn = scanned_lsn; - if (recv_needed_recovery || recv_is_from_backup) { + if (recv_needed_recovery + || (recv_is_from_backup && !recv_is_making_a_backup)) { recv_scan_print_counter++; if (finished || (recv_scan_print_counter % 80 == 0)) { diff --git a/innobase/mem/mem0dbg.c b/innobase/mem/mem0dbg.c index f8f62dffa8b..6bedbd40fef 100644 --- a/innobase/mem/mem0dbg.c +++ b/innobase/mem/mem0dbg.c @@ -666,7 +666,7 @@ mem_print_info_low( mem_pool_print_info(outfile, mem_comm_pool); - mem_validate(); +/* mem_validate(); */ /* fclose(outfile); */ #endif diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 529007dfb26..bb33f7c1485 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -595,6 +595,11 @@ row_lock_table_autoinc_for_mysql( ut_ad(trx); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); + if (trx->auto_inc_lock) { + + return(DB_SUCCESS); + } + trx->op_info = "setting auto-inc lock"; if (node == NULL) { diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index 80de52dc4a1..3af2d96d921 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -2475,12 +2475,23 @@ srv_error_monitor_thread( void* arg) /* in: a dummy parameter required by os_thread_create */ { + ulint cnt = 0; + UT_NOT_USED(arg); loop: srv_error_monitor_active = TRUE; - os_thread_sleep(10000000); + cnt++; + os_thread_sleep(2000000); + +/* mem_print_new_info(); + + if (cnt % 10 == 0) { + + mem_print_info(); + } +*/ sync_array_print_long_waits(); /* Flush stdout and stderr so that a database user gets their output diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 9768d484ce6..b35bca1ea8e 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -927,6 +927,8 @@ innobase_start_or_create_for_mysql(void) ulint max_arch_log_no; ibool start_archive; ulint sum_of_new_sizes; + ulint sum_of_data_file_sizes; + ulint tablespace_size_in_header; ulint err; ulint i; ulint k; @@ -1324,7 +1326,33 @@ innobase_start_or_create_for_mysql(void) os_thread_create(&srv_master_thread, NULL, thread_ids + 1 + SRV_MAX_N_IO_THREADS); /* buf_debug_prints = TRUE; */ + + sum_of_data_file_sizes = 0; + for (i = 0; i < srv_n_data_files; i++) { + sum_of_data_file_sizes += srv_data_file_sizes[i]; + } + + tablespace_size_in_header = fsp_header_get_tablespace_size(0); + + if (!srv_auto_extend_last_data_file + && sum_of_data_file_sizes != tablespace_size_in_header) { + + fprintf(stderr, +"InnoDB: Error: tablespace size stored in header is %lu pages, but\n" +"InnoDB: the sum of data file sizes is %lu pages\n", + tablespace_size_in_header, sum_of_data_file_sizes); + } + + if (srv_auto_extend_last_data_file + && sum_of_data_file_sizes < tablespace_size_in_header) { + + fprintf(stderr, +"InnoDB: Error: tablespace size stored in header is %lu pages, but\n" +"InnoDB: the sum of data file sizes is only %lu pages\n", + tablespace_size_in_header, sum_of_data_file_sizes); + } + ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Started\n"); diff --git a/innobase/trx/trx0sys.c b/innobase/trx/trx0sys.c index 675cdf1b7e4..33c962772e8 100644 --- a/innobase/trx/trx0sys.c +++ b/innobase/trx/trx0sys.c @@ -493,6 +493,34 @@ trx_sys_update_mysql_binlog_offset( MLOG_4BYTES, mtr); } +/********************************************************************* +Prints to stdout the MySQL binlog info in the system header if the +magic number shows it valid. */ + +void +trx_sys_print_mysql_binlog_offset_from_page( +/*========================================*/ + byte* page) /* in: buffer containing the trx system header page, + i.e., page number TRX_SYS_PAGE_NO in the tablespace */ +{ + trx_sysf_t* sys_header; + + sys_header = page + TRX_SYS; + + if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO + + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) + == TRX_SYS_MYSQL_LOG_MAGIC_N) { + + printf( + "ibbackup: Last MySQL binlog file position %lu %lu, file name %s\n", + mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO + + TRX_SYS_MYSQL_LOG_OFFSET_HIGH), + mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO + + TRX_SYS_MYSQL_LOG_OFFSET_LOW), + sys_header + TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_NAME); + } +} + /********************************************************************* Prints to stderr the MySQL binlog offset info in the trx system header if the magic number shows it valid. */ diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index c2d99424d33..9c8bfc9f4db 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -72,6 +72,7 @@ trx_create( trx->type = TRX_USER; trx->conc_state = TRX_NOT_STARTED; + trx->start_time = time(NULL); trx->check_foreigns = TRUE; trx->check_unique_secondary = TRUE; @@ -516,6 +517,7 @@ trx_start_low( if (trx->type == TRX_PURGE) { trx->id = ut_dulint_zero; trx->conc_state = TRX_ACTIVE; + trx->start_time = time(NULL); return(TRUE); } @@ -539,6 +541,7 @@ trx_start_low( trx->rseg = rseg; trx->conc_state = TRX_ACTIVE; + trx->start_time = time(NULL); UT_LIST_ADD_FIRST(trx_list, trx_sys->trx_list, trx); @@ -1465,10 +1468,26 @@ trx_print( 500 bytes */ trx_t* trx) /* in: transaction */ { - buf += sprintf(buf, "TRANSACTION %lu %lu, OS thread id %lu", + char* start_of_line; + + buf += sprintf(buf, "TRANSACTION %lu %lu", ut_dulint_get_high(trx->id), - ut_dulint_get_low(trx->id), - (ulint)trx->mysql_thread_id); + ut_dulint_get_low(trx->id)); + + switch (trx->conc_state) { + case TRX_NOT_STARTED: buf += sprintf(buf, + ", not started"); break; + case TRX_ACTIVE: buf += sprintf(buf, + ", ACTIVE %lu sec", + (ulint)difftime(time(NULL), trx->start_time)); break; + case TRX_COMMITTED_IN_MEMORY: buf += sprintf(buf, + ", COMMITTED IN MEMORY"); + break; + default: buf += sprintf(buf, " state %lu", trx->conc_state); + } + + buf += sprintf(buf, ", OS thread id %lu", + (ulint)trx->mysql_thread_id); if (ut_strlen(trx->op_info) > 0) { buf += sprintf(buf, " %s", trx->op_info); @@ -1477,33 +1496,29 @@ trx_print( if (trx->type != TRX_USER) { buf += sprintf(buf, " purge trx"); } + + buf += sprintf(buf, "\n"); - switch (trx->conc_state) { - case TRX_NOT_STARTED: buf += sprintf(buf, - ", not started"); break; - case TRX_ACTIVE: buf += sprintf(buf, - ", active"); break; - case TRX_COMMITTED_IN_MEMORY: buf += sprintf(buf, - ", committed in memory"); - break; - default: buf += sprintf(buf, " state %lu", trx->conc_state); - } + start_of_line = buf; switch (trx->que_state) { - case TRX_QUE_RUNNING: buf += sprintf(buf, - ", runs or sleeps"); break; + case TRX_QUE_RUNNING: break; case TRX_QUE_LOCK_WAIT: buf += sprintf(buf, - ", lock wait"); break; + "LOCK WAIT "); break; case TRX_QUE_ROLLING_BACK: buf += sprintf(buf, - ", rolling back"); break; + "ROLLING BACK "); break; case TRX_QUE_COMMITTING: buf += sprintf(buf, - ", committing"); break; - default: buf += sprintf(buf, " que state %lu", trx->que_state); + "COMMITTING "); break; + default: buf += sprintf(buf, "que state %lu", trx->que_state); } - if (0 < UT_LIST_GET_LEN(trx->trx_locks)) { - buf += sprintf(buf, ", has %lu lock struct(s)", - UT_LIST_GET_LEN(trx->trx_locks)); + if (0 < UT_LIST_GET_LEN(trx->trx_locks) || + mem_heap_get_size(trx->lock_heap) > 400) { + + buf += sprintf(buf, +"%lu lock struct(s), heap size %lu", + UT_LIST_GET_LEN(trx->trx_locks), + mem_heap_get_size(trx->lock_heap)); } if (trx->has_search_latch) { @@ -1515,7 +1530,10 @@ trx_print( ut_dulint_get_low(trx->undo_no)); } - buf += sprintf(buf, "\n"); + if (buf != start_of_line) { + + buf += sprintf(buf, "\n"); + } if (trx->mysql_thd != NULL) { innobase_mysql_print_thd(buf, trx->mysql_thd); diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc index 1bf619855c9..b952e297c85 100644 --- a/sql/ha_innobase.cc +++ b/sql/ha_innobase.cc @@ -266,10 +266,39 @@ innobase_mysql_print_thd( thd = (THD*) input_thd; + buf += sprintf(buf, "MySQL thread id %lu, query id %lu", + thd->thread_id, thd->query_id); + if (thd->host) { + buf += sprintf(buf, " %.30s", thd->host); + } + + if (thd->ip) { + buf += sprintf(buf, " %.20s", thd->ip); + } + + if (thd->user) { + buf += sprintf(buf, " %.20s", thd->user); + } + + if (thd->proc_info) { + buf += sprintf(buf, " %.50s", thd->proc_info); + } + + if (thd->query) { + buf += sprintf(buf, "\n%.150s", thd->query); + } + + buf += sprintf(buf, "\n"); + +#ifdef notdefined + /* July 30, 2002 + Revert Monty's changes because they seem to make control + characters sometimes appear in the output */ + /* We can't use value of sprintf() as this is not portable */ buf+= my_sprintf(buf, - (buf, "MySQL thread id %lu, query id %lu", - thd->thread_id, thd->query_id)); + (buf, "MySQL thread id %lu", + thd->thread_id)); if (thd->host) { *buf++=' '; @@ -296,10 +325,11 @@ innobase_mysql_print_thd( if (thd->query) { - *buf++=' '; + *buf++='\n'; buf=strnmov(buf, thd->query, 150); } *buf='\n'; +#endif } } @@ -1414,6 +1444,7 @@ ha_innobase::write_row( row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt; int error; longlong auto_inc; + longlong dummy; DBUG_ENTER("ha_innobase::write_row"); @@ -1436,7 +1467,31 @@ ha_innobase::write_row( if (table->next_number_field && record == table->record[0]) { /* This is the case where the table has an auto-increment column */ - + + /* Initialize the auto-inc counter if it has not been + initialized yet */ + + if (0 == dict_table_autoinc_peek(prebuilt->table)) { + + /* This call initializes the counter */ + error = innobase_read_and_init_auto_inc(&dummy); + + if (error) { + /* Deadlock or lock wait timeout */ + + goto func_exit; + } + + /* We have to set sql_stat_start to TRUE because + the above call probably has called a select, and + has reset that flag; row_insert_for_mysql has to + know to set the IX intention lock on the table, + something it only does at the start of each + statement */ + + prebuilt->sql_stat_start = TRUE; + } + /* Fetch the value the user possibly has set in the autoincrement field */ @@ -1469,10 +1524,9 @@ ha_innobase::write_row( } if (auto_inc != 0) { - /* This call will calculate the max of the - current value and the value supplied by the user, if - the auto_inc counter is already initialized - for the table */ + /* This call will calculate the max of the current + value and the value supplied by the user and + update the counter accordingly */ /* We have to use the transactional lock mechanism on the auto-inc counter of the table to ensure @@ -1512,46 +1566,18 @@ ha_innobase::write_row( auto_inc = dict_table_autoinc_get(prebuilt->table); srv_conc_exit_innodb(prebuilt->trx); - /* If auto_inc is now != 0 the autoinc counter - was already initialized for the table: we can give - the new value for MySQL to place in the field */ + /* We can give the new value for MySQL to place in + the field */ - if (auto_inc != 0) { - user_thd->next_insert_id = auto_inc; - } + user_thd->next_insert_id = auto_inc; } - + + /* This call of a handler.cc function places + user_thd->next_insert_id to the column value, if the column + value was not set by the user */ + update_auto_increment(); - - if (auto_inc == 0) { - /* The autoinc counter for our table was not yet - initialized, initialize it now */ - - auto_inc = table->next_number_field->val_int(); - - srv_conc_enter_innodb(prebuilt->trx); - error = row_lock_table_autoinc_for_mysql(prebuilt); - srv_conc_exit_innodb(prebuilt->trx); - - if (error != DB_SUCCESS) { - - error = convert_error_code_to_mysql(error, - user_thd); - goto func_exit; - } - - dict_table_autoinc_initialize(prebuilt->table, - auto_inc); - } - - /* We have to set sql_stat_start to TRUE because - update_auto_increment may have called a select, and - has reset that flag; row_insert_for_mysql has to - know to set the IX intention lock on the table, something - it only does at the start of each statement */ - - prebuilt->sql_stat_start = TRUE; - } + } if (prebuilt->mysql_template == NULL || prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) { @@ -3572,37 +3598,53 @@ ha_innobase::store_lock( } /*********************************************************************** -Returns the next auto-increment column value for the table. write_row -normally fetches the value from the cache in the data dictionary. This -function in used by SHOW TABLE STATUS and when the first insert to the table -is done after database startup. */ +This function initializes the auto-inc counter if it has not been +initialized yet. This function does not change the value of the auto-inc +counter if it already has been initialized. In parameter ret returns +the value of the auto-inc counter. */ -longlong -ha_innobase::get_auto_increment() -/*=============================*/ - /* out: the next auto-increment column value */ +int +ha_innobase::innobase_read_and_init_auto_inc( +/*=========================================*/ + /* out: 0 or error code: deadlock or + lock wait timeout */ + longlong* ret) /* out: auto-inc value */ { row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; - longlong nr; + longlong auto_inc; int error; + ut_a(prebuilt); ut_a(prebuilt->trx == (trx_t*) current_thd->transaction.all.innobase_tid); + ut_a(prebuilt->table); + + auto_inc = dict_table_autoinc_read(prebuilt->table); - /* Also SHOW TABLE STATUS calls this function. Previously, when we did - always read the max autoinc key value, setting x-locks, users were - surprised that SHOW TABLE STATUS could end up in a deadlock with - ordinary SQL queries. We avoid these deadlocks if the auto-inc - counter for the table has been initialized by fetching the value - from the table struct in dictionary cache. */ + if (auto_inc != 0) { + /* Already initialized */ + *ret = auto_inc; + + return(0); + } - assert(prebuilt->table); - - nr = dict_table_autoinc_read(prebuilt->table); + srv_conc_enter_innodb(prebuilt->trx); + error = row_lock_table_autoinc_for_mysql(prebuilt); + srv_conc_exit_innodb(prebuilt->trx); - if (nr != 0) { + if (error != DB_SUCCESS) { + error = convert_error_code_to_mysql(error, user_thd); - return(nr + 1); + goto func_exit; + } + + /* Check again if someone has initialized the counter meanwhile */ + auto_inc = dict_table_autoinc_read(prebuilt->table); + + if (auto_inc != 0) { + *ret = auto_inc; + + return(0); } (void) extra(HA_EXTRA_KEYREAD); @@ -3622,22 +3664,63 @@ ha_innobase::get_auto_increment() prebuilt->hint_no_need_to_fetch_extra_cols = FALSE; - prebuilt->trx->mysql_n_tables_locked += 1; + prebuilt->trx->mysql_n_tables_locked += 1; - error = index_last(table->record[1]); + error = index_last(table->record[1]); if (error) { - nr = 1; + if (error == HA_ERR_END_OF_FILE) { + /* The table was empty, initialize to 1 */ + auto_inc = 1; + + error = 0; + } else { + /* Deadlock or a lock wait timeout */ + auto_inc = -1; + + goto func_exit; + } } else { - nr = (longlong) table->next_number_field-> + /* Initialize to max(col) + 1 */ + auto_inc = (longlong) table->next_number_field-> val_int_offset(table->rec_buff_length) + 1; } + dict_table_autoinc_initialize(prebuilt->table, auto_inc); + +func_exit: (void) extra(HA_EXTRA_NO_KEYREAD); - index_end(); + index_end(); - return(nr); + *ret = auto_inc; + + return(error); +} + +/*********************************************************************** +This function initializes the auto-inc counter if it has not been +initialized yet. This function does not change the value of the auto-inc +counter if it already has been initialized. Returns the value of the +auto-inc counter. */ + +longlong +ha_innobase::get_auto_increment() +/*=============================*/ + /* out: auto-increment column value, -1 if error + (deadlock or lock wait timeout) */ +{ + longlong nr; + int error; + + error = innobase_read_and_init_auto_inc(&nr); + + if (error) { + + return(-1); + } + + return(nr); } #endif /* HAVE_INNOBASE_DB */ diff --git a/sql/ha_innobase.h b/sql/ha_innobase.h index 4a9f3a6251b..abb6ade79f7 100644 --- a/sql/ha_innobase.h +++ b/sql/ha_innobase.h @@ -68,6 +68,7 @@ class ha_innobase: public handler int update_thd(THD* thd); int change_active_index(uint keynr); int general_fetch(byte* buf, uint direction, uint match_mode); + int innobase_read_and_init_auto_inc(longlong* ret); /* Init values for the class: */ public: From 6485267ce3854bfa867d9691a59f65bf79ac5867 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 31 Jul 2002 16:43:48 +0300 Subject: [PATCH 12/30] Changelog update Docs/manual.texi: Changelog --- Docs/manual.texi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Docs/manual.texi b/Docs/manual.texi index 209751aa4dc..84af1493063 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -46928,7 +46928,9 @@ not yet 100% confident in this code. @appendixsubsec Changes in release 3.23.52 @itemize @bullet @item -Fixed bug in ALTERing TABLE of BDB type. +Fixed a core-dump bug with @code{MERGE] tables and @code{MAX()} function. +@item +Fixed bug in @code{ALTER TABLE} with BDB tables. @item Fixed bug when logging @code{LOAD DATA INFILE} to binary log with no active database. From e2cf3f8e4501befbae0f785a422cb832fb3466c2 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 31 Jul 2002 18:02:24 +0300 Subject: [PATCH 13/30] Fixed wrong printf() string in InnoDB Removed some compiler warnings regarding 'static' from InnoDB Docs/manual.texi: Fixed wrong manual entry innobase/btr/btr0cur.c: Fixed wrong printf() string innobase/include/univ.i: Removed compiler warnings (static inline produces a lot of warnings and is probably not portable) --- Docs/manual.texi | 2 +- innobase/btr/btr0cur.c | 2 +- innobase/include/univ.i | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Docs/manual.texi b/Docs/manual.texi index 14e9e6576c2..11140681ceb 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -46937,7 +46937,7 @@ Don't write slave-timeout reconnects to the error log. @item Fixed bug with slave net read timeouting @item -Fixed a core-dump bug with @code{MERGE] tables and @code{MAX()} function. +Fixed a core-dump bug with @code{MERGE} tables and @code{MAX()} function. @item Fixed bug in @code{ALTER TABLE} with BDB tables. @item diff --git a/innobase/btr/btr0cur.c b/innobase/btr/btr0cur.c index 50f9584e86d..6caf940b34d 100644 --- a/innobase/btr/btr0cur.c +++ b/innobase/btr/btr0cur.c @@ -808,7 +808,7 @@ btr_cur_optimistic_insert( if (!dtuple_check_typed_no_assert(entry)) { fprintf(stderr, -"InnoDB: Error in a tuple to insert into table %lu index %lu\n", +"InnoDB: Error in a tuple to insert into table %s index %s\n", index->table_name, index->name); } diff --git a/innobase/include/univ.i b/innobase/include/univ.i index 4c1ca929aa8..8a9637acfda 100644 --- a/innobase/include/univ.i +++ b/innobase/include/univ.i @@ -116,7 +116,7 @@ memory is read outside the allocated blocks. */ #define UNIV_INLINE extern inline #else /* extern inline doesn't work with gcc 3.0.2 */ -#define UNIV_INLINE static inline +#define UNIV_INLINE inline #endif #endif From dd764d999ee270d3e3ad5e14881b7b16c247d762 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 1 Aug 2002 00:37:27 +0300 Subject: [PATCH 14/30] Innodb fixes: Added back 'static inline', as not having this caused more problems than having it Fixed wrong arguments to printf() innobase/buf/buf0buf.c: Fixed wrong argument to printf() innobase/fsp/fsp0fsp.c: Fixed wrong argument to printf() innobase/include/btr0btr.h: Removed UNIV_INLINE for functions that should not be inlined innobase/include/dyn0dyn.h: Removed UNIV_INLINE for functions that should not be inlined innobase/include/univ.i: Added back 'static inline', as not having this caused more problems than having it --- innobase/buf/buf0buf.c | 2 +- innobase/fsp/fsp0fsp.c | 2 +- innobase/include/btr0btr.h | 2 +- innobase/include/dyn0dyn.h | 2 +- innobase/include/univ.i | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index e3a4ae50a23..9cd4197165c 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -286,7 +286,7 @@ buf_page_print( ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Page dump in ascii and hex (%lu bytes):\n%s", - UNIV_PAGE_SIZE, buf); + (unsigned long) UNIV_PAGE_SIZE, buf); fprintf(stderr, "InnoDB: End of page dump\n"); mem_free(buf); diff --git a/innobase/fsp/fsp0fsp.c b/innobase/fsp/fsp0fsp.c index 679af640b99..10370731edf 100644 --- a/innobase/fsp/fsp0fsp.c +++ b/innobase/fsp/fsp0fsp.c @@ -2659,7 +2659,7 @@ fseg_free_page_low( "InnoDB: Dump of the tablespace extent descriptor: %s\n", errbuf); fprintf(stderr, -"InnoDB: Serious error! InnoDB is trying to free page %lu\n", +"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" diff --git a/innobase/include/btr0btr.h b/innobase/include/btr0btr.h index bf433c0c264..1b48eaeb4b2 100644 --- a/innobase/include/btr0btr.h +++ b/innobase/include/btr0btr.h @@ -315,7 +315,7 @@ btr_discard_page( mtr_t* mtr); /* in: mtr */ /************************************************************************ Declares the latching order level for the page latch in the debug version. */ -UNIV_INLINE + void btr_declare_page_latch( /*===================*/ diff --git a/innobase/include/dyn0dyn.h b/innobase/include/dyn0dyn.h index 504aade29d2..49a1a4c6129 100644 --- a/innobase/include/dyn0dyn.h +++ b/innobase/include/dyn0dyn.h @@ -127,7 +127,7 @@ dyn_block_get_data( dyn_block_t* block); /* in: dyn array block */ /************************************************************************ Gets the next block in a dyn array. */ -UNIV_INLINE + dyn_block_t* dyn_block_get_next( /*===============*/ diff --git a/innobase/include/univ.i b/innobase/include/univ.i index 8a9637acfda..15a6115c37e 100644 --- a/innobase/include/univ.i +++ b/innobase/include/univ.i @@ -116,7 +116,7 @@ memory is read outside the allocated blocks. */ #define UNIV_INLINE extern inline #else /* extern inline doesn't work with gcc 3.0.2 */ -#define UNIV_INLINE inline +#define UNIV_INLINE static inline #endif #endif From 0ebb78e8ef8fa1fc77ac8c9caeb8cbd37337030a Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 Aug 2002 23:16:19 +0300 Subject: [PATCH 15/30] Many files: Merge InnoDB-3.23.52c ha_innobase.cc: Test the ref length sanity also in the production version sql/ha_innobase.cc: Test the ref length sanity also in the production version innobase/btr/btr0cur.c: Merge InnoDB-3.23.52c innobase/buf/buf0buf.c: Merge InnoDB-3.23.52c innobase/buf/buf0lru.c: Merge InnoDB-3.23.52c innobase/ha/ha0ha.c: Merge InnoDB-3.23.52c innobase/log/log0recv.c: Merge InnoDB-3.23.52c innobase/mtr/mtr0log.c: Merge InnoDB-3.23.52c innobase/os/os0file.c: Merge InnoDB-3.23.52c innobase/page/page0cur.c: Merge InnoDB-3.23.52c innobase/include/btr0btr.h: Merge InnoDB-3.23.52c innobase/include/dyn0dyn.h: Merge InnoDB-3.23.52c innobase/include/log0recv.h: Merge InnoDB-3.23.52c innobase/include/buf0buf.ic: Merge InnoDB-3.23.52c innobase/include/log0log.ic: Merge InnoDB-3.23.52c --- innobase/btr/btr0cur.c | 8 +- innobase/buf/buf0buf.c | 2 +- innobase/buf/buf0lru.c | 38 +++++++++ innobase/ha/ha0ha.c | 14 +++- innobase/include/btr0btr.h | 8 -- innobase/include/buf0buf.ic | 37 +++++++-- innobase/include/dyn0dyn.h | 8 -- innobase/include/log0log.ic | 2 +- innobase/include/log0recv.h | 3 +- innobase/log/log0recv.c | 160 ++++++++++++++++++++++++------------ innobase/mtr/mtr0log.c | 37 ++++++++- innobase/os/os0file.c | 2 +- innobase/page/page0cur.c | 24 +++++- sql/ha_innobase.cc | 2 +- 14 files changed, 258 insertions(+), 87 deletions(-) diff --git a/innobase/btr/btr0cur.c b/innobase/btr/btr0cur.c index 6caf940b34d..ada7e482b7e 100644 --- a/innobase/btr/btr0cur.c +++ b/innobase/btr/btr0cur.c @@ -808,7 +808,7 @@ btr_cur_optimistic_insert( if (!dtuple_check_typed_no_assert(entry)) { fprintf(stderr, -"InnoDB: Error in a tuple to insert into table %s index %s\n", +"InnoDB: Error in a tuple to insert into table %lu index %s\n", index->table_name, index->name); } @@ -1213,6 +1213,8 @@ btr_cur_parse_update_in_place( rec_offset = mach_read_from_2(ptr); ptr += 2; + ut_a(rec_offset <= UNIV_PAGE_SIZE); + heap = mem_heap_create(256); ptr = row_upd_index_parse(ptr, end_ptr, heap, &update); @@ -1977,6 +1979,8 @@ btr_cur_parse_del_mark_set_clust_rec( offset = mach_read_from_2(ptr); ptr += 2; + ut_a(offset <= UNIV_PAGE_SIZE); + if (page) { rec = page + offset; @@ -2127,6 +2131,8 @@ btr_cur_parse_del_mark_set_sec_rec( offset = mach_read_from_2(ptr); ptr += 2; + ut_a(offset <= UNIV_PAGE_SIZE); + if (page) { rec = page + offset; diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index 9cd4197165c..a447f9692a7 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -286,7 +286,7 @@ buf_page_print( ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Page dump in ascii and hex (%lu bytes):\n%s", - (unsigned long) UNIV_PAGE_SIZE, buf); + (ulint)UNIV_PAGE_SIZE, buf); fprintf(stderr, "InnoDB: End of page dump\n"); mem_free(buf); diff --git a/innobase/buf/buf0lru.c b/innobase/buf/buf0lru.c index a2996eefca9..ffdc58f2224 100644 --- a/innobase/buf/buf0lru.c +++ b/innobase/buf/buf0lru.c @@ -204,6 +204,44 @@ buf_LRU_get_free_block(void) loop: mutex_enter(&(buf_pool->mutex)); + if (UT_LIST_GET_LEN(buf_pool->free) + + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 10) { + ut_print_timestamp(stderr); + + fprintf(stderr, +" InnoDB: ERROR: over 9 / 10 of the buffer pool is occupied by\n" +"InnoDB: lock heaps or the adaptive hash index!\n" +"InnoDB: We intentionally generate a seg fault to print a stack trace\n" +"InnoDB: on Linux!\n"); + + ut_a(0); + + } else if (UT_LIST_GET_LEN(buf_pool->free) + + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 5) { + + /* Over 80 % of the buffer pool is occupied by lock heaps + or the adaptive hash index. This may be a memory leak! */ + + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: WARNING: over 4 / 5 of the buffer pool is occupied by\n" +"InnoDB: lock heaps or the adaptive hash index! Check that your\n" +"InnoDB: transactions do not set too many row locks. Starting InnoDB\n" +"InnoDB: Monitor to print diagnostics, including lock heap and hash index\n" +"InnoDB: sizes.\n"); + + srv_print_innodb_monitor = TRUE; + + } else if (UT_LIST_GET_LEN(buf_pool->free) + + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 4) { + + /* Switch off the InnoDB Monitor; this is a simple way + to stop the monitor if the situation becomes less urgent, + but may also surprise users! */ + + srv_print_innodb_monitor = FALSE; + } + if (buf_pool->LRU_flush_ended > 0) { mutex_exit(&(buf_pool->mutex)); diff --git a/innobase/ha/ha0ha.c b/innobase/ha/ha0ha.c index acde236bb2f..4489b25ec2b 100644 --- a/innobase/ha/ha0ha.c +++ b/innobase/ha/ha0ha.c @@ -298,6 +298,7 @@ ha_print_info( ulint cells = 0; ulint len = 0; ulint max_len = 0; + ulint n_bufs; ulint i; if (buf_end - buf < 200) { @@ -339,7 +340,16 @@ ha_print_info( "Hash table size %lu, used cells %lu", hash_get_n_cells(table), cells); if (table->heaps == NULL && table->heap != NULL) { - buf += sprintf(buf, -", node heap has %lu buffer(s)\n", UT_LIST_GET_LEN(table->heap->base)); + + /* This calculation is intended for the adaptive hash + index: how many buffer frames we have reserved? */ + + n_bufs = UT_LIST_GET_LEN(table->heap->base) - 1; + + if (table->heap->free_block) { + n_bufs++; + } + + buf += sprintf(buf, ", node heap has %lu buffer(s)\n", n_bufs); } } diff --git a/innobase/include/btr0btr.h b/innobase/include/btr0btr.h index 1b48eaeb4b2..f66ad3639d4 100644 --- a/innobase/include/btr0btr.h +++ b/innobase/include/btr0btr.h @@ -313,14 +313,6 @@ btr_discard_page( btr_cur_t* cursor, /* in: cursor on the page to discard: not on the root page */ mtr_t* mtr); /* in: mtr */ -/************************************************************************ -Declares the latching order level for the page latch in the debug version. */ - -void -btr_declare_page_latch( -/*===================*/ - page_t* page, /* in: page */ - ibool leaf); /* in: TRUE if a leaf */ /******************************************************************** Parses the redo log record for setting an index record as the predefined minimum record. */ diff --git a/innobase/include/buf0buf.ic b/innobase/include/buf0buf.ic index 50248a7b2da..51e2541e04d 100644 --- a/innobase/include/buf0buf.ic +++ b/innobase/include/buf0buf.ic @@ -211,8 +211,15 @@ buf_block_align( block = buf_pool_get_nth_block(buf_pool, ((ulint)(ptr - frame_zero)) >> UNIV_PAGE_SIZE_SHIFT); - ut_a(block >= buf_pool->blocks); - ut_a(block < buf_pool->blocks + buf_pool->max_size); + if (block < buf_pool->blocks + || block >= buf_pool->blocks + buf_pool->max_size) { + + fprintf(stderr, +"InnoDB: Error: trying to access a stray pointer %lx\n" +"InnoDB: buf pool start is at %lx, number of pages %lu\n", (ulint)ptr, + (ulint)frame_zero, buf_pool->max_size); + ut_a(0); + } return(block); } @@ -238,8 +245,15 @@ buf_block_align_low( block = buf_pool_get_nth_block(buf_pool, ((ulint)(ptr - frame_zero)) >> UNIV_PAGE_SIZE_SHIFT); - ut_a(block >= buf_pool->blocks); - ut_a(block < buf_pool->blocks + buf_pool->max_size); + if (block < buf_pool->blocks + || block >= buf_pool->blocks + buf_pool->max_size) { + + fprintf(stderr, +"InnoDB: Error: trying to access a stray pointer %lx\n" +"InnoDB: buf pool start is at %lx, number of pages %lu\n", (ulint)ptr, + (ulint)frame_zero, buf_pool->max_size); + ut_a(0); + } return(block); } @@ -259,10 +273,17 @@ buf_frame_align( frame = ut_align_down(ptr, UNIV_PAGE_SIZE); - ut_a((ulint)frame - >= (ulint)(buf_pool_get_nth_block(buf_pool, 0)->frame)); - ut_a((ulint)frame <= (ulint)(buf_pool_get_nth_block(buf_pool, - buf_pool->max_size - 1)->frame)); + if (((ulint)frame + < (ulint)(buf_pool->frame_zero)) + || ((ulint)frame > (ulint)(buf_pool_get_nth_block(buf_pool, + buf_pool->max_size - 1)->frame))) { + fprintf(stderr, +"InnoDB: Error: trying to access a stray pointer %lx\n" +"InnoDB: buf pool start is at %lx, number of pages %lu\n", (ulint)ptr, + (ulint)(buf_pool->frame_zero), buf_pool->max_size); + ut_a(0); + } + return(frame); } diff --git a/innobase/include/dyn0dyn.h b/innobase/include/dyn0dyn.h index 49a1a4c6129..cca302994c1 100644 --- a/innobase/include/dyn0dyn.h +++ b/innobase/include/dyn0dyn.h @@ -125,14 +125,6 @@ dyn_block_get_data( /*===============*/ /* out: pointer to data */ dyn_block_t* block); /* in: dyn array block */ -/************************************************************************ -Gets the next block in a dyn array. */ - -dyn_block_t* -dyn_block_get_next( -/*===============*/ - /* out: pointer to next, NULL if end of list */ - dyn_block_t* block); /* in: dyn array block */ /************************************************************ Pushes n bytes to a dyn array. */ UNIV_INLINE diff --git a/innobase/include/log0log.ic b/innobase/include/log0log.ic index 9167246fe45..8de239df0bd 100644 --- a/innobase/include/log0log.ic +++ b/innobase/include/log0log.ic @@ -207,7 +207,7 @@ log_block_calc_checksum( for (i = 0; i < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE; i++) { sum = sum & 0x7FFFFFFF; - sum += ((ulint)(*(block + i))) << sh; + sum += (((ulint)(*(block + i))) << sh) + (ulint)(*(block + i)); sh++; if (sh > 24) { sh = 0; diff --git a/innobase/include/log0recv.h b/innobase/include/log0recv.h index 65f80deee93..baa2ba50c7d 100644 --- a/innobase/include/log0recv.h +++ b/innobase/include/log0recv.h @@ -316,7 +316,8 @@ struct recv_sys_struct{ ibool found_corrupt_log; /* this is set to TRUE if we during log scan find a corrupt log block, or a corrupt - log record */ + log record, or there is a log parsing + buffer overflow */ log_group_t* archive_group; /* in archive recovery: the log group whose archive is read */ diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c index 62031005e05..1223f9b6041 100644 --- a/innobase/log/log0recv.c +++ b/innobase/log/log0recv.c @@ -58,13 +58,17 @@ yet: the variable name is misleading */ ibool recv_no_ibuf_operations = FALSE; -/* the following counter is used to decide when to print info on +/* The following counter is used to decide when to print info on log scan */ ulint recv_scan_print_counter = 0; ibool recv_is_from_backup = FALSE; ibool recv_is_making_a_backup = FALSE; +ulint recv_previous_parsed_rec_type = 999999; +ulint recv_previous_parsed_rec_offset = 0; +ulint recv_previous_parsed_rec_is_multi = 0; + /************************************************************ Creates the recovery system. */ @@ -695,7 +699,7 @@ byte* recv_parse_or_apply_log_rec_body( /*=============================*/ /* out: log record end, NULL if not a complete - record, or a corrupt record */ + record */ byte type, /* in: type */ byte* ptr, /* in: pointer to a buffer */ byte* end_ptr,/* in: pointer to the buffer end */ @@ -770,15 +774,6 @@ recv_parse_or_apply_log_rec_body( new_ptr = mlog_parse_string(ptr, end_ptr, page); } else { new_ptr = NULL; - - fprintf(stderr, - "InnoDB: WARNING: the log file may have been corrupt and it\n" - "InnoDB: is possible that the log scan did not proceed\n" - "InnoDB: far enough in recovery. Please run CHECK TABLE\n" - "InnoDB: on your InnoDB tables to check that they are ok!\n" - "InnoDB: Corrupt log record type %lu\n, lsn %lu %lu\n", - (ulint)type, ut_dulint_get_high(recv_sys->recovered_lsn), - ut_dulint_get_low(recv_sys->recovered_lsn)); recv_sys->found_corrupt_log = TRUE; } @@ -1651,7 +1646,7 @@ ulint recv_parse_log_rec( /*===============*/ /* out: length of the record, or 0 if the record was - not complete or it was corrupt */ + not complete */ byte* ptr, /* in: pointer to a buffer */ byte* end_ptr,/* in: pointer to the buffer end */ byte* type, /* out: type */ @@ -1691,16 +1686,6 @@ recv_parse_log_rec( /* Check that space id and page_no are sensible */ if (*space != 0 || *page_no > 0x8FFFFFFF) { - fprintf(stderr, - "InnoDB: WARNING: the log file may have been corrupt and it\n" - "InnoDB: is possible that the log scan did not proceed\n" - "InnoDB: far enough in recovery. Please run CHECK TABLE\n" - "InnoDB: on your InnoDB tables to check that they are ok!\n" - "InnoDB: Corrupt log record type %lu, space id %lu, page no %lu\n", - "InnoDB: lsn %lu %lu\n", - (ulint)(*type), *space, *page_no, - ut_dulint_get_high(recv_sys->recovered_lsn), - ut_dulint_get_low(recv_sys->recovered_lsn)); recv_sys->found_corrupt_log = TRUE; @@ -1766,6 +1751,63 @@ recv_check_incomplete_log_recs( } } +/*********************************************************** +Prints diagnostic info of corrupt log. */ +static +void +recv_report_corrupt_log( +/*====================*/ + byte* ptr, /* in: pointer to corrupt log record */ + byte type, /* in: type of the record */ + ulint space, /* in: space id, this may also be garbage */ + ulint page_no)/* in: page number, this may also be garbage */ +{ + char* err_buf; + + fprintf(stderr, +"InnoDB: ############### CORRUPT LOG RECORD FOUND\n" +"InnoDB: Log record type %lu, space id %lu, page number %lu\n" +"InnoDB: Log parsing proceeded successfully up to %lu %lu\n", + (ulint)type, space, page_no, + ut_dulint_get_high(recv_sys->recovered_lsn), + ut_dulint_get_low(recv_sys->recovered_lsn)); + + err_buf = ut_malloc(1000000); + + fprintf(stderr, +"InnoDB: Previous log record type %lu, is multi %lu\n" +"InnoDB: Recv offset %lu, prev %lu\n", + recv_previous_parsed_rec_type, + recv_previous_parsed_rec_is_multi, + ptr - recv_sys->buf, + recv_previous_parsed_rec_offset); + + if ((ulint)(ptr - recv_sys->buf + 100) + > recv_previous_parsed_rec_offset + && (ulint)(ptr - recv_sys->buf + 100 + - recv_previous_parsed_rec_offset) + < 200000) { + + ut_sprintf_buf(err_buf, + recv_sys->buf + recv_previous_parsed_rec_offset - 100, + ptr - recv_sys->buf + 200 - + recv_previous_parsed_rec_offset); + fprintf(stderr, +"InnoDB: Hex dump of corrupt log starting 100 bytes before the start\n" +"InnoDB: of the previous log rec,\n" +"InnoDB: and ending 100 bytes after the start of the corrupt rec:\n%s\n", + err_buf); + } + + ut_free(err_buf); + + fprintf(stderr, + "InnoDB: WARNING: the log file may have been corrupt and it\n" + "InnoDB: is possible that the log scan did not proceed\n" + "InnoDB: far enough in recovery! Please run CHECK TABLE\n" + "InnoDB: on your InnoDB tables to check that they are ok!\n"); +} + /*********************************************************** Parses log records from a buffer and stores them to a hash table to wait merging to file pages. */ @@ -1773,8 +1815,7 @@ static ibool recv_parse_log_recs( /*================*/ - /* out: TRUE if the hash table of parsed log - records became full */ + /* out: currently always returns FALSE */ ibool store_to_hash) /* in: TRUE if the records should be stored to the hash table; this is set to FALSE if just debug checking is needed */ @@ -1791,7 +1832,6 @@ recv_parse_log_recs( ulint page_no; byte* body; ulint n_recs; - char err_buf[2500]; ut_ad(mutex_own(&(log_sys->mutex))); ut_ad(!ut_dulint_is_zero(recv_sys->parse_start_lsn)); @@ -1814,17 +1854,11 @@ loop: len = recv_parse_log_rec(ptr, end_ptr, &type, &space, &page_no, &body); - if (len == 0) { + if (len == 0 || recv_sys->found_corrupt_log) { if (recv_sys->found_corrupt_log) { - - ut_sprintf_buf(err_buf, - recv_sys->buf + ut_calc_align_down( - recv_sys->recovered_offset, - OS_FILE_LOG_BLOCK_SIZE) - 8, - OS_FILE_LOG_BLOCK_SIZE + 16); - - fprintf(stderr, -"InnoDB: hex dump of a corrupt log segment: %s\n", err_buf); + + recv_report_corrupt_log(ptr, + type, space, page_no); } return(FALSE); @@ -1841,6 +1875,10 @@ loop: return(FALSE); } + recv_previous_parsed_rec_type = (ulint)type; + recv_previous_parsed_rec_offset = recv_sys->recovered_offset; + recv_previous_parsed_rec_is_multi = 0; + recv_sys->recovered_offset += len; recv_sys->recovered_lsn = new_recovered_lsn; @@ -1879,22 +1917,22 @@ loop: for (;;) { len = recv_parse_log_rec(ptr, end_ptr, &type, &space, &page_no, &body); - if (len == 0) { + if (len == 0 || recv_sys->found_corrupt_log) { - if (recv_sys->found_corrupt_log) { - ut_sprintf_buf(err_buf, - recv_sys->buf + ut_calc_align_down( - recv_sys->recovered_offset, - OS_FILE_LOG_BLOCK_SIZE) - 8, - OS_FILE_LOG_BLOCK_SIZE + 16); - - fprintf(stderr, -"InnoDB: hex dump of a corrupt log segment: %s\n", err_buf); - } + if (recv_sys->found_corrupt_log) { - return(FALSE); + recv_report_corrupt_log(ptr, + type, space, page_no); + } + + return(FALSE); } + recv_previous_parsed_rec_type = (ulint)type; + recv_previous_parsed_rec_offset + = recv_sys->recovered_offset + total_len; + recv_previous_parsed_rec_is_multi = 1; + if ((!store_to_hash) && (type != MLOG_MULTI_REC_END)) { /* In debug checking, update a replicate page according to the log record */ @@ -1946,6 +1984,12 @@ loop: old_lsn = recv_sys->recovered_lsn; len = recv_parse_log_rec(ptr, end_ptr, &type, &space, &page_no, &body); + if (recv_sys->found_corrupt_log) { + + recv_report_corrupt_log(ptr, + type, space, page_no); + } + ut_a(len != 0); ut_a(0 == ((ulint)*ptr & MLOG_SINGLE_REC_FLAG)); @@ -2206,11 +2250,14 @@ recv_scan_log_recs( >= RECV_PARSING_BUF_SIZE) { fprintf(stderr, "InnoDB: Error: log parsing buffer overflow. Recovery may have failed!\n"); - finished = TRUE; + + recv_sys->found_corrupt_log = TRUE; + + } else if (!recv_sys->found_corrupt_log) { + more_data = recv_sys_add_to_parsing_buf( + log_block, scanned_lsn); } - more_data = recv_sys_add_to_parsing_buf(log_block, - scanned_lsn); recv_sys->scanned_lsn = scanned_lsn; recv_sys->scanned_checkpoint_no = log_block_get_checkpoint_no(log_block); @@ -2240,7 +2287,7 @@ recv_scan_log_recs( } } - if (more_data) { + if (more_data && !recv_sys->found_corrupt_log) { /* Try to parse more log records */ recv_parse_log_recs(store_to_hash); @@ -2617,6 +2664,17 @@ recv_recovery_from_checkpoint_finish(void) trx_sys_print_mysql_binlog_offset(); } + if (recv_sys->found_corrupt_log) { + + fprintf(stderr, + "InnoDB: WARNING: the log file may have been corrupt and it\n" + "InnoDB: is possible that the log scan or parsing did not proceed\n" + "InnoDB: far enough in recovery. Please run CHECK TABLE\n" + "InnoDB: on your InnoDB tables to check that they are ok!\n" + "InnoDB: It may be safest to recover your InnoDB database from\n" + "InnoDB: a backup!\n"); + } + /* Free the resources of the recovery system */ recv_recovery_on = FALSE; diff --git a/innobase/mtr/mtr0log.c b/innobase/mtr/mtr0log.c index b582afc5710..2cfe81d3261 100644 --- a/innobase/mtr/mtr0log.c +++ b/innobase/mtr/mtr0log.c @@ -14,6 +14,7 @@ Created 12/7/1995 Heikki Tuuri #include "buf0buf.h" #include "dict0boot.h" +#include "log0recv.h" /************************************************************ Catenates n bytes to the mtr log. */ @@ -121,7 +122,7 @@ byte* mlog_parse_nbytes( /*==============*/ /* out: parsed record end, NULL if not a complete - record */ + record or a corrupt record */ ulint type, /* in: log record type: MLOG_1BYTE, ... */ byte* ptr, /* in: buffer */ byte* end_ptr,/* in: buffer end */ @@ -141,6 +142,12 @@ mlog_parse_nbytes( offset = mach_read_from_2(ptr); ptr += 2; + if (offset >= UNIV_PAGE_SIZE) { + recv_sys->found_corrupt_log = TRUE; + + return(NULL); + } + if (type == MLOG_8BYTES) { ptr = mach_dulint_parse_compressed(ptr, end_ptr, &dval); @@ -163,13 +170,33 @@ mlog_parse_nbytes( return(NULL); } + if (type == MLOG_1BYTE) { + if (val > 0xFF) { + recv_sys->found_corrupt_log = TRUE; + + return(NULL); + } + } else if (type == MLOG_2BYTES) { + if (val > 0xFFFF) { + recv_sys->found_corrupt_log = TRUE; + + return(NULL); + } + } else { + if (type != MLOG_4BYTES) { + recv_sys->found_corrupt_log = TRUE; + + return(NULL); + } + } + if (page) { if (type == MLOG_1BYTE) { mach_write_to_1(page + offset, val); } else if (type == MLOG_2BYTES) { mach_write_to_2(page + offset, val); } else { - ut_ad(type == MLOG_4BYTES); + ut_a(type == MLOG_4BYTES); mach_write_to_4(page + offset, val); } } @@ -338,7 +365,11 @@ mlog_parse_string( offset = mach_read_from_2(ptr); ptr += 2; - ut_a(offset < UNIV_PAGE_SIZE); + if (offset >= UNIV_PAGE_SIZE) { + recv_sys->found_corrupt_log = TRUE; + + return(NULL); + } len = mach_read_from_2(ptr); ptr += 2; diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 4a1bbfa9874..e40de2198c1 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -22,7 +22,7 @@ Created 10/21/1995 Heikki Tuuri #endif -/* This specifies the file permissions InnoDB uses when it craetes files in +/* This specifies the file permissions InnoDB uses when it creates files in Unix; the value of os_innodb_umask is initialized in ha_innodb.cc to my_umask */ diff --git a/innobase/page/page0cur.c b/innobase/page/page0cur.c index dfe28fd40c4..6ce7008dce0 100644 --- a/innobase/page/page0cur.c +++ b/innobase/page/page0cur.c @@ -13,6 +13,7 @@ Created 10/4/1994 Heikki Tuuri #include "rem0cmp.h" #include "mtr0log.h" +#include "log0recv.h" ulint page_cur_short_succ = 0; @@ -481,6 +482,9 @@ page_cur_insert_rec_write_log( /* Write the mismatch index */ log_ptr += mach_write_compressed(log_ptr, i); + + ut_a(i < UNIV_PAGE_SIZE); + ut_a(extra_size < UNIV_PAGE_SIZE); } /* Write to the log the inserted index record end segment which @@ -533,6 +537,13 @@ page_cur_parse_insert_rec( } offset = mach_read_from_2(ptr); + + if (offset >= UNIV_PAGE_SIZE) { + + recv_sys->found_corrupt_log = TRUE; + + return(NULL); + } ptr += 2; } @@ -546,6 +557,12 @@ page_cur_parse_insert_rec( extra_info_yes = end_seg_len & 0x1; end_seg_len = end_seg_len / 2; + + if (end_seg_len >= UNIV_PAGE_SIZE) { + recv_sys->found_corrupt_log = TRUE; + + return(NULL); + } if (extra_info_yes) { /* Read the info bits */ @@ -565,12 +582,16 @@ page_cur_parse_insert_rec( return(NULL); } + ut_a(origin_offset < UNIV_PAGE_SIZE); + ptr = mach_parse_compressed(ptr, end_ptr, &mismatch_index); if (ptr == NULL) { return(NULL); } + + ut_a(mismatch_index < UNIV_PAGE_SIZE); } if (end_ptr < ptr + end_seg_len) { @@ -607,7 +628,6 @@ page_cur_parse_insert_rec( /* 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 + mismatch_index, ptr, end_seg_len); @@ -1009,6 +1029,8 @@ page_cur_parse_delete_rec( offset = mach_read_from_2(ptr); ptr += 2; + ut_a(offset <= UNIV_PAGE_SIZE); + if (page) { page_cur_position(page + offset, &cursor); diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc index b952e297c85..81af4636ff2 100644 --- a/sql/ha_innobase.cc +++ b/sql/ha_innobase.cc @@ -2474,7 +2474,7 @@ ha_innobase::position( that len is always fixed for this table. The following assertion checks this. */ - DBUG_ASSERT(len == ref_length); + ut_a(len == ref_length); } /********************************************************************* From 990b178c322fb24faa71ae4c09fc92945b439109 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 3 Aug 2002 17:21:21 +0300 Subject: [PATCH 16/30] Fixed a problem with privilege tables when downgrading from 4.0.2 to 3.23 --- Docs/manual.texi | 2 ++ sql/sql_acl.cc | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Docs/manual.texi b/Docs/manual.texi index 11140681ceb..01a0095646c 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -46928,6 +46928,8 @@ not yet 100% confident in this code. @appendixsubsec Changes in release 3.23.52 @itemize @bullet @item +Fixed problem with privilege tables when downgrading from 4.0.2 to 3.23 ... +@item Added name of 'administrator command' logs. @item Fixed bug with creating an auto-increment value on second part of a diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index edfc2ceeab8..f0131023157 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -215,7 +215,7 @@ int acl_init(bool dont_read_acl_tables) continue; /* purecov: tested */ } get_salt_from_password(user.salt,user.password); - user.access=get_access(table,3); + user.access=get_access(table,3) & GLOBAL_ACLS; user.sort=get_sort(2,user.host.hostname,user.user); user.hostname_length=user.host.hostname ? (uint) strlen(user.host.hostname) : 0; #ifndef TO_BE_REMOVED From 5414ede22f90a40e0f47d84c5ed6c24cc7dd2cce Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 3 Aug 2002 19:48:45 +0300 Subject: [PATCH 17/30] Two small patches proposed by Paul DuBois include/sslopt-usage.h: Paul's patch for --ssl-xxx options for the --help message scripts/mysqlhotcopy.sh: Paul's patch for --port option BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted --- BitKeeper/etc/logging_ok | 1 + include/sslopt-usage.h | 2 +- scripts/mysqlhotcopy.sh | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 16db163b051..2eaef09868f 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -25,3 +25,4 @@ zak@balfor.local monty@narttu. monty@mashka.mysql.fi bar@bar.udmsearch.izhnet.ru +salle@geopard.online.bg diff --git a/include/sslopt-usage.h b/include/sslopt-usage.h index 5b2b4a88709..406d94572b8 100644 --- a/include/sslopt-usage.h +++ b/include/sslopt-usage.h @@ -15,7 +15,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef OPEN_SSL +#ifdef HAVE_OPENSSL puts("\ --ssl Use SSL for connection (automatically set with other flags\n\ --ssl-key X509 key in PEM format (implies --ssl)\n\ diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index 45f1f1ed24a..707b4fc481c 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -156,6 +156,7 @@ $opt{allowold} = 1 if $opt{keepold}; # --- connect to the database --- my $dsn = ";host=localhost"; +$dsn = ";host=127.0.0.1" if $opt{port}; # use TCP/IP if port was given $dsn .= ";port=$opt{port}" if $opt{port}; $dsn .= ";mysql_socket=$opt{socket}" if $opt{socket}; From 5647f6e004243354f2503d74a71ca036d8acb251 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 3 Aug 2002 21:53:42 +0300 Subject: [PATCH 18/30] os0thread.c: Remove the complex typecast used to convert a HP-UX pthread struct to os_thread_id_t; the typecast seemed to work wrong in gcc-3.1 on HP-UX-10.20 innobase/os/os0thread.c: Remove the complex typecast used to convert a HP-UX pthread struct to os_thread_id_t; the typecast seemed to work wrong in gcc-3.1 on HP-UX-10.20 --- innobase/os/os0thread.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index 74f5fbd9494..44817302340 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -32,24 +32,20 @@ os_thread_get_curr_id(void) pthr = pthread_self(); -#ifdef UNIV_HPUX +#ifdef HPUX /* TODO: in the future we have to change os_thread_id - to pthread_t; the following cast may work in a wrong way on some - systems if pthread_t is a struct; this is just a quick fix - for HP-UX to eliminate a compiler warning */ + to pthread_t! */ + /* In HP-UX a pthread_t seems to be a struct of three fields: + field1, field2, field3, and the first probably determines (?) + the thread identity. */ - /* The below typecast trick will certainly not work if this assertion - fails */ - - ut_a(sizeof(pthread_t) >= sizeof(os_thread_id_t)); - - return(*(os_thread_id_t*)((void*) (&pthr))); + return((os_thread_id_t)(pthr.field1)); #else /* TODO: define os_thread_id_t in Unix as the same as pthread_t - and compare them with appropriate Posix pthread functions! - The following typecast will not work if pthread_t is not - an integer or a pointer to a unique object for the thread! */ + and compare them with appropriate Posix pthread functions! + The following typecast will not work if pthread_t is not + an integer or a pointer to a unique object for the thread! */ return((os_thread_id_t)pthr); #endif From f2dba61eefccc55f407f8ad0f7791e9a6646d229 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Aug 2002 13:09:12 +0300 Subject: [PATCH 19/30] Added some mutex locks to make SLAVE START and SLAVE STOP thread safe. Docs/manual.texi: Changelog sql/gen_lex_hash.cc: Merged --verbose option from 4.0 Smaller hash table sql/slave.cc: Added some mutex locks to make SLAVE START and SLAVE STOP thread safe. --- Docs/manual.texi | 2 ++ sql/gen_lex_hash.cc | 12 +++++++++--- sql/slave.cc | 4 ++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Docs/manual.texi b/Docs/manual.texi index 11140681ceb..b4d39667ec9 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -46928,6 +46928,8 @@ not yet 100% confident in this code. @appendixsubsec Changes in release 3.23.52 @itemize @bullet @item +Fixed thread bug in @code{SLAVE START} and @code{SLAVE STOP}. +@item Added name of 'administrator command' logs. @item Fixed bug with creating an auto-increment value on second part of a diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc index d47019ee040..22e40ff2830 100644 --- a/sql/gen_lex_hash.cc +++ b/sql/gen_lex_hash.cc @@ -216,7 +216,7 @@ you have to change 'main' to print out the new function\n"); return(1); } - if (opt_verbose) + if (opt_verbose > 1) fprintf (stderr,"Info: Possible add values: %d\n",found-type_count); for (prime=primes; (function_mod=*prime) ; prime++) @@ -385,7 +385,7 @@ static int get_options(int argc, char **argv) opt_search=1; break; case 'v': - opt_verbose=1; + opt_verbose++; break; case 'V': usage(1); exit(0); case 'I': @@ -481,7 +481,7 @@ int main(int argc,char **argv) int error; MY_INIT(argv[0]); - start_value=7740512L; best_t1=7953583L; best_t2=6918639L; best_type=1; /* mode=5449 add=1 type: 0 */ + start_value=2744811L; best_t1=5135075L; best_t2=1719450L; best_type=0; /* mode=4999 add=1 type: 0 */ if (get_options(argc,(char **) argv)) exit(1); @@ -502,6 +502,7 @@ int main(int argc,char **argv) start_value, best_t1,best_t2,best_type,best_mod,best_add, best_functype); + best_start_value=start_value; for (uint i=1 ; i <= opt_count ; i++) { if (i % 10 == 0) @@ -524,6 +525,11 @@ int main(int argc,char **argv) best_start_value,best_t1,best_t2,best_type,best_mod,best_add, best_functype); } + if (opt_verbose && (i % 20000) == 0) + printf("\nstart_value=%ldL; best_t1=%ldL; best_t2=%ldL; best_type=%d; +/* mode=%d add=%d type: %d */\n", + best_start_value,best_t1,best_t2,best_type,best_mod,best_add, + best_functype); } } diff --git a/sql/slave.cc b/sql/slave.cc index adbf3c106cc..6b79c567482 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1301,7 +1301,9 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) } thd->thread_stack = (char*)&thd; // remember where our stack is thd->temporary_tables = save_temporary_tables; // restore temp tables + (void) pthread_mutex_lock(&LOCK_thread_count); threads.append(thd); + (void) pthread_mutex_unlock(&LOCK_thread_count); glob_mi.pending = 0; //this should always be set to 0 when the slave thread // is started @@ -1501,7 +1503,9 @@ position %s", pthread_mutex_unlock(&LOCK_slave); net_end(&thd->net); // destructor will not free it, because we are weird slave_thd = 0; + (void) pthread_mutex_lock(&LOCK_thread_count); delete thd; + (void) pthread_mutex_unlock(&LOCK_thread_count); my_thread_end(); #ifndef DBUG_OFF if(abort_slave_event_count && !events_till_abort) From 529e1af2957828c4b8570933547b7202c8a36878 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Aug 2002 18:10:53 +0300 Subject: [PATCH 20/30] Fixed bug with GROUP BY on NULL fields. (Merge of code from 4.0) Docs/manual.texi: Changelog include/my_base.h: Fixed bug with GROUP BY on NULL fields. include/mysql_com.h: Fixed bug with GROUP BY on NULL fields. myisam/mi_search.c: Fixed bug with GROUP BY on NULL fields. myisam/mi_write.c: Fixed bug with GROUP BY on NULL fields. mysql-test/r/group_by.result: Fixed bug with GROUP BY on NULL fields. mysql-test/t/group_by.test: Fixed bug with GROUP BY on NULL fields. sql/sql_base.cc: Removed some not-needed comments in the trace file sql/sql_select.cc: Fixed bug with GROUP BY on NULL fields. --- Docs/manual.texi | 3 +++ include/my_base.h | 2 ++ include/mysql_com.h | 3 +++ myisam/mi_search.c | 5 ++-- myisam/mi_write.c | 4 +++ mysql-test/r/group_by.result | 16 ++++++++++++ mysql-test/t/group_by.test | 11 +++++++++ sql/sql_base.cc | 18 +++++++------- sql/sql_select.cc | 48 ++++++++++++++++++++++++------------ 9 files changed, 83 insertions(+), 27 deletions(-) diff --git a/Docs/manual.texi b/Docs/manual.texi index 5c871944d94..0d7604b436b 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -46928,6 +46928,9 @@ not yet 100% confident in this code. @appendixsubsec Changes in release 3.23.52 @itemize @bullet @item +Fixed problem with @code{GROUP BY} on result with expression that created a +@code{BLOB} field. +@item Fixed problem with privilege tables when downgrading from 4.0.2 to 3.23. @item Fixed thread bug in @code{SLAVE START} and @code{SLAVE STOP}. diff --git a/include/my_base.h b/include/my_base.h index 6275adab124..dff1553cf20 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -134,6 +134,7 @@ enum ha_base_keytype { #define HA_BINARY_PACK_KEY 32 /* Packing of all keys to prev key */ #define HA_FULLTEXT 128 /* SerG: for full-text search */ #define HA_UNIQUE_CHECK 256 /* Check the key for uniqueness */ +#define HA_NULL_ARE_EQUAL 2048 /* NULL in key are cmp as equal */ /* Automatic bits in key-flag */ @@ -235,6 +236,7 @@ enum ha_base_keytype { #define SEARCH_UPDATE 64 #define SEARCH_PREFIX 128 #define SEARCH_LAST 256 +#define SEARCH_NULL_ARE_EQUAL 32768 /* NULL in keys are equal */ /* bits in opt_flag */ #define QUICK_USED 1 diff --git a/include/mysql_com.h b/include/mysql_com.h index 525a631caf6..fcc9abc5bcd 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -110,6 +110,9 @@ typedef struct st_vio Vio; #endif #endif +#define MAX_CHAR_WIDTH 255 /* Max length for a CHAR colum */ +#define MAX_BLOB_WIDTH 8192 /* Default width for blob */ + typedef struct st_net { Vio* vio; my_socket fd; /* For Perl DBI/dbd */ diff --git a/myisam/mi_search.c b/myisam/mi_search.c index 2c04679ed4c..938062d977d 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -107,8 +107,9 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, } else { - if (nextflag & SEARCH_FIND && (!(keyinfo->flag & HA_NOSAME) - || key_len) && nod_flag) + if ((nextflag & SEARCH_FIND) && nod_flag && + ((keyinfo->flag & (HA_NOSAME | HA_NULL_PART)) != HA_NOSAME || + key_len)) { if ((error=_mi_search(info,keyinfo,key,key_len,SEARCH_FIND, _mi_kpos(nod_flag,keypos))) >= 0 || diff --git a/myisam/mi_write.c b/myisam/mi_write.c index f31e43e52ab..7b468395166 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -263,7 +263,11 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, if (keyinfo->flag & HA_SORT_ALLOWS_SAME) comp_flag=SEARCH_BIGGER; /* Put after same key */ else if (keyinfo->flag & HA_NOSAME) + { comp_flag=SEARCH_FIND | SEARCH_UPDATE; /* No dupplicates */ + if (keyinfo->flag & HA_NULL_ARE_EQUAL) + comp_flag|= SEARCH_NULL_ARE_EQUAL; + } else comp_flag=SEARCH_SAME; /* Keys in rec-pos order */ diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index aafeb64ee2a..200cbc29b08 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -68,3 +68,19 @@ One Two sum(Four) 1 1 16 1 2 16 1 3 16 +xID xID1 +1 1 +2 2 +2 2 +3 134 +3 134 +3 134 +4 185 +4 185 +4 185 +4 185 +xID xID1 Level +1 1 * +2 2 ** +3 134 *** +4 185 **** diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 11408511e99..dfbb2f325a9 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -259,3 +259,14 @@ insert into t1 values (1,3,3,4); insert into t1 values (1,3,4,4); select One, Two, sum(Four) from t1 group by One,Two; drop table if exists t1; + +# +# The GROUP BY returned rows in wrong order in 3.23.51 +# + +CREATE TABLE t1 (ID1 int, ID2 int, ID int NOT NULL AUTO_INCREMENT,PRIMARY KEY(ID +)); +insert into t1 values (1,244,NULL),(2,243,NULL),(134,223,NULL),(185,186,NULL); +select S.ID as xID, S.ID1 as xID1 from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2; +select S.ID as xID, S.ID1 as xID1, repeat('*',count(distinct yS.ID)) as Level from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2 group by xID order by xID1; +drop table t1; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index ee8c1097fb2..a40587bb8c9 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2222,18 +2222,18 @@ int setup_ftfuncs(THD *thd) return 0; } + int init_ftfuncs(THD *thd, bool no_order) { - List_iterator li(thd->lex.ftfunc_list); - Item_func_match *ifm; - DBUG_PRINT("info",("Performing FULLTEXT search")); - thd->proc_info="FULLTEXT initialization"; - - while ((ifm=li++)) + if (thd->lex.ftfunc_list.elements) { - ifm->init_search(no_order); - } + List_iterator li(thd->lex.ftfunc_list); + Item_func_match *ifm; + DBUG_PRINT("info",("Performing FULLTEXT search")); + thd->proc_info="FULLTEXT initialization"; + while ((ifm=li++)) + ifm->init_search(no_order); + } return 0; } - diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 939ec003aca..04368c016d1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -153,7 +153,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, uint select_options,select_result *result) { TABLE *tmp_table; - int error,tmp; + int error, tmp_error; bool need_tmp,hidden_group_fields; bool simple_order,simple_group,no_order; Item::cond_result cond_value; @@ -380,9 +380,9 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, thd->fatal_error) goto err; thd->proc_info="preparing"; - if ((tmp=join_read_const_tables(&join)) > 0) + if ((tmp_error=join_read_const_tables(&join)) > 0) goto err; - if (tmp && !(select_options & SELECT_DESCRIBE)) + if (tmp_error && !(select_options & SELECT_DESCRIBE)) { error=return_zero_rows(result,tables,fields, join.tmp_table_param.sum_func_count != 0 && @@ -701,9 +701,11 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, group=0; } thd->proc_info="Copying to group table"; + tmp_error= -1; if (make_sum_func_list(&join,all_fields) || - do_select(&join,(List *) 0,tmp_table2,0)) + (tmp_error=do_select(&join,(List *) 0,tmp_table2,0))) { + error=tmp_error; free_tmp_table(thd,tmp_table2); goto err; /* purecov: inspected */ } @@ -3347,7 +3349,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, if (!param->quick_group) group=0; // Can't use group key else for (ORDER *tmp=group ; tmp ; tmp=tmp->next) + { (*tmp->item)->marker=4; // Store null in key + if ((*tmp->item)->max_length >= MAX_CHAR_WIDTH) + using_unique_constraint=1; + } if (param->group_length >= MAX_BLOB_WIDTH) using_unique_constraint=1; if (group) @@ -3477,7 +3483,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, field_count= (uint) (reg_field - table->field); /* If result table is small; use a heap */ - if (blob_count || using_unique_constraint || + if (blob_count || using_unique_constraint || group_null_items || (select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) == OPTION_BIG_TABLES) { @@ -3499,7 +3505,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, if (blob_count == 0) { /* We need to ensure that first byte is not 0 for the delete link */ - if (hidden_null_count) + if (param->hidden_field_count) hidden_null_count++; else null_count++; @@ -3633,14 +3639,17 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, if (maybe_null) { /* - To be able to group on NULL, we move the null bit to be - just before the column and extend the key to cover the null bit + To be able to group on NULL, we reserve place in group_buff + for the NULL flag just before the column. + The field data is after this flag. + The NULL flag is updated by 'end_update()' and 'end_write()' */ - *group_buff= 0; // Init null byte - key_part_info->offset--; - key_part_info->length++; - group->field->move_field((char*) group_buff+1, (uchar*) group_buff, - 1); + keyinfo->flags|= HA_NULL_ARE_EQUAL; // def. that NULL == NULL + key_part_info->null_bit=field->null_bit; + key_part_info->null_offset= (uint) (field->null_ptr - + (uchar*) table->record[0]); + group->field->move_field((char*) ++group->buff); + group_buff++; } else group->field->move_field((char*) group_buff); @@ -3820,11 +3829,17 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, keyinfo->key_part[i].length > 4) seg->flag|=HA_SPACE_PACK; } - if (using_unique_constraint && - !(field->flags & NOT_NULL_FLAG)) + if (!(field->flags & NOT_NULL_FLAG)) { seg->null_bit= field->null_bit; seg->null_pos= (uint) (field->null_ptr - (uchar*) table->record[0]); + /* + We are using a GROUP BY on something that contains NULL + In this case we have to tell MyISAM that two NULL should + on INSERT be compared as equal + */ + if (!using_unique_constraint) + keydef.flag|= HA_NULL_ARE_EQUAL; } } } @@ -4797,8 +4812,9 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { Item *item= *group->item; item->save_org_in_field(group->field); + /* Store in the used key if the field was 0 */ if (item->maybe_null) - group->buff[0]=item->null_value ? 0: 1; // Save reversed value + group->buff[-1]=item->null_value ? 1 : 0; } // table->file->index_init(0); if (!table->file->index_read(table->record[1], From 7952914415e351973d1a572827bb1679e5b7b89e Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Aug 2002 18:50:38 +0300 Subject: [PATCH 21/30] Added some missing mutex_locks() when manipulating the table cache. This should fix some possible table cache corruptions when doing OPTIMIZE or REPAIR table when other threads are opening new tables. sql/sql_base.cc: Added missing mutex unlock on error condition sql/sql_insert.cc: Added TODO item sql/sql_show.cc: Added missing pthread_mutex_lock(&LOCK_open) when calling query_table_status(). sql/sql_table.cc: Added missing pthread_mutex_lock(&LOCK_open) when calling hash_delete(), unlock_table_name() and remove_table_from_cache(). BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted --- BitKeeper/etc/logging_ok | 1 + sql/sql_base.cc | 16 ++++++++++++++-- sql/sql_insert.cc | 5 +++++ sql/sql_show.cc | 7 ++++++- sql/sql_table.cc | 21 +++++++++++++++++---- 5 files changed, 43 insertions(+), 7 deletions(-) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 16db163b051..b79219cdded 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -25,3 +25,4 @@ zak@balfor.local monty@narttu. monty@mashka.mysql.fi bar@bar.udmsearch.izhnet.ru +monty@narttu.mysql.fi diff --git a/sql/sql_base.cc b/sql/sql_base.cc index ee8c1097fb2..bd8a570ccea 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -279,6 +279,16 @@ void intern_close_table(TABLE *table) VOID(closefrm(table)); // close file } +/* + Remove table from the open table cache + + SYNOPSIS + free_cache_entry() + table Table to remove + + NOTE + We need to have a lock on LOCK_open when calling this +*/ static void free_cache_entry(TABLE *table) { @@ -833,7 +843,10 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, /* make a new table */ if (!(table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME)))) + { + VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_RETURN(NULL); + } if (open_unireg_entry(thd, table,db,table_name,alias,1) || !(table->table_cache_key=memdup_root(&table->mem_root,(char*) key, key_length))) @@ -1181,7 +1194,6 @@ bool wait_for_tables(THD *thd) /* Now we can open all tables without any interference */ thd->proc_info="Reopen tables"; result=reopen_tables(thd,0,0); - } pthread_mutex_unlock(&LOCK_open); thd->proc_info=0; @@ -1372,9 +1384,9 @@ int open_tables(THD *thd,TABLE_LIST *start) } } *prev_table=0; + pthread_mutex_unlock(&LOCK_open); if (found) VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh - pthread_mutex_unlock(&LOCK_open); goto restart; } result= -1; // Fatal error diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 18100996f52..d1ec53d6590 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1419,6 +1419,11 @@ bool select_create::send_eof() table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); VOID(pthread_mutex_lock(&LOCK_open)); mysql_unlock_tables(thd, lock); + /* + TODO: + Check if we can remove the following two rows. + We should be able to just keep the table in the table cache. + */ if (!table->tmp_table) hash_delete(&open_cache,(byte*) table); lock=0; table=0; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5db2df85fbf..c64a1a3d6ed 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -117,6 +117,7 @@ int mysqld_show_open_tables(THD *thd,const char *db,const char *wild) if (list_open_tables(thd,&tables,db,wild)) DBUG_RETURN(-1); + pthread_mutex_lock(&LOCK_open); List_iterator it(tables); while ((table_name=it++)) { @@ -124,13 +125,17 @@ int mysqld_show_open_tables(THD *thd,const char *db,const char *wild) net_store_data(&thd->packet,table_name); net_store_data(&thd->packet,query_table_status(thd,db,table_name)); if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length())) + { + pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(-1); + } } - + pthread_mutex_unlock(&LOCK_open); send_eof(&thd->net); DBUG_RETURN(0); } + /*************************************************************************** ** List all tables in a database (fast version) ** A table is a .frm file in the current databasedir diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ce3415f10fb..9a5056a1f35 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -147,8 +147,8 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) error = 0; err: - VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh pthread_mutex_unlock(&LOCK_open); + VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh pthread_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; @@ -160,7 +160,7 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) my_error(ER_BAD_TABLE_ERROR,MYF(0),wrong_tables.c_ptr()); error=1; } - if(error) + if (error) DBUG_RETURN(-1); send_ok(&thd->net); DBUG_RETURN(0); @@ -711,7 +711,9 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, table->reginfo.lock_type=TL_WRITE; if (!((*lock)=mysql_lock_tables(thd,&table,1))) { + VOID(pthread_mutex_lock(&LOCK_open)); hash_delete(&open_cache,(byte*) table); + VOID(pthread_mutex_unlock(&LOCK_open)); quick_rm_table(create_info->db_type,db,name); DBUG_RETURN(0); } @@ -859,7 +861,9 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table) reg_ext, 4), MYF(MY_WME))) { + pthread_mutex_lock(&LOCK_open); unlock_table_name(thd, table); + pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(send_check_errmsg(thd, table, "restore", "Failed copying .frm file")); } @@ -870,7 +874,9 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table) if (generate_table(thd, table, 0)) { + pthread_mutex_lock(&LOCK_open); unlock_table_name(thd, table); + pthread_mutex_unlock(&LOCK_open); thd->net.no_send_ok = save_no_send_ok; DBUG_RETURN(send_check_errmsg(thd, table, "restore", "Failed generating table from .frm file")); @@ -930,9 +936,12 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, // now we should be able to open the partially restored table // to finish the restore in the handler later on if (!(table->table = reopen_name_locked_table(thd, table))) + { + pthread_mutex_lock(&LOCK_open); unlock_table_name(thd, table); + pthread_mutex_unlock(&LOCK_open); + } } - if (!table->table) { const char *err_msg; @@ -1031,8 +1040,12 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, if (fatal_error) table->table->version=0; // Force close of table else if (open_for_modify) + { + pthread_mutex_lock(&LOCK_open); remove_table_from_cache(thd, table->table->table_cache_key, table->table->real_name); + pthread_mutex_unlock(&LOCK_open); + } close_thread_tables(thd); if (my_net_write(&thd->net, (char*) packet->ptr(), packet->length())) @@ -1648,8 +1661,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, error=1; if (error) { - VOID(pthread_cond_broadcast(&COND_refresh)); VOID(pthread_mutex_unlock(&LOCK_open)); + VOID(pthread_cond_broadcast(&COND_refresh)); goto err; } #ifdef HAVE_BERKELEY_DB From ccf728776349a95fbeaeac58a825949040f20a55 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Aug 2002 18:53:49 +0300 Subject: [PATCH 22/30] Changelog --- Docs/manual.texi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Docs/manual.texi b/Docs/manual.texi index 11140681ceb..15da4959b70 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -46928,6 +46928,9 @@ not yet 100% confident in this code. @appendixsubsec Changes in release 3.23.52 @itemize @bullet @item +Fixed possible thread related key-cache-corruption problem with +@code{OPTIMIZE TABLE} and @code{REPAIR TABLE}. +@item Added name of 'administrator command' logs. @item Fixed bug with creating an auto-increment value on second part of a From 4c1712e40171e2861359878ea885e14936298acf Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Aug 2002 03:21:12 +0300 Subject: [PATCH 23/30] Changed initialization of RND() to be less predictable. Use MYSQL_CONFIG_NAME instead of "my" as the configuration file name. Docs/manual.texi: Changelog include/mysql_version.h.in: Use MYSQL_CONFIG_NAME instead of "my" as the configuration file name. --- Docs/manual.texi | 2 ++ include/mysql_version.h.in | 1 + sql/mysqld.cc | 14 +++++++++++--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Docs/manual.texi b/Docs/manual.texi index bc571c4bcb6..a9eef29f11a 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -46928,6 +46928,8 @@ not yet 100% confident in this code. @appendixsubsec Changes in release 3.23.52 @itemize @bullet @item +Changed initialisation of @code{RND()} to make it less predicatable. +@item Fixed problem with @code{GROUP BY} on result with expression that created a @code{BLOB} field. @item diff --git a/include/mysql_version.h.in b/include/mysql_version.h.in index 44fd00f806a..989b1a95494 100644 --- a/include/mysql_version.h.in +++ b/include/mysql_version.h.in @@ -13,6 +13,7 @@ #define MYSQL_VERSION_ID @MYSQL_VERSION_ID@ #define MYSQL_PORT @MYSQL_TCP_PORT@ #define MYSQL_UNIX_ADDR "@MYSQL_UNIX_ADDR@" +#define MYSQL_CONFIG_NAME "my" /* mysqld compile time options */ #ifndef MYSQL_CHARSET diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 251dda77d34..d73ec9fc0d6 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1690,7 +1690,7 @@ int main(int argc, char **argv) exit( 1 ); } #endif - load_defaults("my",load_default_groups,&argc,&argv); + load_defaults(MYSQL_CONFIG_NAME,load_default_groups,&argc,&argv); defaults_argv=argv; mysql_tmpdir=getenv("TMPDIR"); /* Use this if possible */ #if defined( __WIN__) || defined(OS2) @@ -2250,7 +2250,15 @@ static void create_new_thread(THD *thd) for (uint i=0; i < 8 ; i++) // Generate password teststring thd->scramble[i]= (char) (rnd(&sql_rand)*94+33); thd->scramble[8]=0; - thd->rand=sql_rand; + /* + We need good random number initialization for new thread + Just coping global one will not work + */ + { + ulong tmp=(ulong) (rnd(&sql_rand) * 3000000); + randominit(&(thd->rand), tmp + (ulong) start_time, + tmp + (ulong) thread_id); + } thd->real_id=pthread_self(); // Keep purify happy /* Start a new thread to handle connection */ @@ -3386,7 +3394,7 @@ Starts the MySQL server\n"); --skip-innodb Don't use Innodb (will save memory)\n\ "); #endif /* HAVE_INNOBASE_DB */ - print_defaults("my",load_default_groups); + print_defaults(MYSQL_CONFIG_NAME,load_default_groups); puts(""); #include "sslopt-usage.h" From 72e8833beae176f61763702947dfe83f7c23c737 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Aug 2002 12:32:56 +0300 Subject: [PATCH 24/30] my_pthread.h, configure.in: In HP-UX-10.20, but not in HP-UX-11.0, the return value of pthread_mutex_trylock is inverted configure.in: In HP-UX-10.20, but not in HP-UX-11.0, the return value of pthread_mutex_trylock is inverted include/my_pthread.h: In HP-UX-10.20, but not in HP-UX-11.0, the return value of pthread_mutex_trylock is inverted --- configure.in | 4 ++-- include/my_pthread.h | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 460c5e73abe..4719cdda44e 100644 --- a/configure.in +++ b/configure.in @@ -849,8 +849,8 @@ case $SYSTEM_TYPE in ;; *hpux10.20*) echo "Enabling workarounds for hpux 10.20" - CFLAGS="$CFLAGS -DHAVE_BROKEN_SNPRINTF -DSIGNALS_DONT_BREAK_READ -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHPUX -DSIGNAL_WITH_VIO_CLOSE -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT" - CXXFLAGS="$CXXFLAGS -DHAVE_BROKEN_SNPRINTF -D_INCLUDE_LONGLONG -DSIGNALS_DONT_BREAK_READ -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHPUX -DSIGNAL_WITH_VIO_CLOSE -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT" + CFLAGS="$CFLAGS -DHAVE_BROKEN_SNPRINTF -DSIGNALS_DONT_BREAK_READ -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHPUX -DSIGNAL_WITH_VIO_CLOSE -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT -DPTHREAD_MUTEX_TRYLOCK_INVERTED_RET_VAL" + CXXFLAGS="$CXXFLAGS -DHAVE_BROKEN_SNPRINTF -D_INCLUDE_LONGLONG -DSIGNALS_DONT_BREAK_READ -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHPUX -DSIGNAL_WITH_VIO_CLOSE -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT -DPTHREAD_MUTEX_TRYLOCK_INVERTED_RET_VAL" if test "$with_named_thread" = "no" then echo "Using --with-named-thread=-lpthread" diff --git a/include/my_pthread.h b/include/my_pthread.h index bcad292ecc9..004c908e08e 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -464,7 +464,14 @@ int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp, #define pthread_mutex_destroy(A) safe_mutex_destroy((A),__FILE__,__LINE__) #define pthread_cond_wait(A,B) safe_cond_wait((A),(B),__FILE__,__LINE__) #define pthread_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__) +#ifdef PTHREAD_MUTEX_TRYLOCK_INVERTED_RET_VAL + /* In HP-UX-10.20 and other old Posix 1003.4a Draft 4 implementations + pthread_mutex_trylock returns 1 on success, not 0 like + pthread_mutex_lock */ +#define pthread_mutex_trylock(A) (1 - pthread_mutex_lock(A)) +#else #define pthread_mutex_trylock(A) pthread_mutex_lock(A) +#endif #define pthread_mutex_t safe_mutex_t #endif /* SAFE_MUTEX */ From 72345f2b474310bc72af7fb4e3b25c7051dfd6cd Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Aug 2002 16:12:52 +0300 Subject: [PATCH 25/30] Better error messages for mysql-test-run Added option --host to mysqlhotcopy mysql-test/mysql-test-run.sh: Added error message if the server doesn't start. Increase connect timeout a bit (for running under purify). mysql-test/t/rpl000001.test: Longer sleep time (for running under purify) scripts/mysqlhotcopy.sh: Added option --host for usage with TCP/IP connections sql/gen_lex_hash.cc: Fixed typo --- mysql-test/mysql-test-run.sh | 10 +++++++--- mysql-test/t/rpl000001.test | 2 +- scripts/mysqlhotcopy.sh | 15 +++++++++++---- sql/gen_lex_hash.cc | 6 +++--- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 4898d9c5464..566702a7330 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -344,7 +344,11 @@ SLAVE_MYSQLD=$MYSQLD #this can be changed later if we are doing gcov #-- wait_for_server_start () { - $MYSQLADMIN --no-defaults -u $DBUSER --silent -O connect_timeout=10 -w2 --host=$hostname --port=$1 ping >/dev/null 2>&1 + $MYSQLADMIN --no-defaults -u $DBUSER --silent -O connect_timeout=10 -w3 --host=$hostname --port=$1 ping >/dev/null 2>&1 + exit_code=$? + if [ $exit_code != 0 ]; then + echo "Error: Could not start $2, exit code $exit_code"; + fi } prompt_user () @@ -553,7 +557,7 @@ start_master() else $MYSQLD $master_args >> $MASTER_MYERR 2>&1 & fi - wait_for_server_start $MASTER_MYPORT + wait_for_server_start $MASTER_MYPORT master MASTER_RUNNING=1 } @@ -610,7 +614,7 @@ start_slave() else $SLAVE_MYSQLD $slave_args >> $SLAVE_MYERR 2>&1 & fi - wait_for_server_start $SLAVE_MYPORT + wait_for_server_start $SLAVE_MYPORT slave SLAVE_RUNNING=1 } diff --git a/mysql-test/t/rpl000001.test b/mysql-test/t/rpl000001.test index 113a9637dac..6a827368fa4 100644 --- a/mysql-test/t/rpl000001.test +++ b/mysql-test/t/rpl000001.test @@ -57,7 +57,7 @@ reap; connection slave; sync_with_master ; #give the slave a chance to exit -sleep 0.5; +sleep 2; # The following test can't be done because the result of Pos will differ # on different computers diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index 707b4fc481c..1aad5c95c25 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -50,7 +50,8 @@ Usage: $0 db_name[./table_regex/] [new_db_name | directory] -?, --help display this helpscreen and exit -u, --user=# user for database login if not current user -p, --password=# password to use when connecting to server - -P, --port=# port to use when connecting to local server + -h, --host=# Hostname for local server when connecting over TCP/IP + -P, --port=# port to use when connecting to local server with TCP/IP -S, --socket=# socket to use when connecting to local server --allowold don\'t abort if target already exists (rename it _old) @@ -155,8 +156,8 @@ $opt{quiet} = 0 if $opt{debug}; $opt{allowold} = 1 if $opt{keepold}; # --- connect to the database --- -my $dsn = ";host=localhost"; -$dsn = ";host=127.0.0.1" if $opt{port}; # use TCP/IP if port was given +my $dsn; +$dsn = ";host=" . (defined($opt{host}) ? $opt{host} : "localhost"); $dsn .= ";port=$opt{port}" if $opt{port}; $dsn .= ";mysql_socket=$opt{socket}" if $opt{socket}; @@ -891,9 +892,15 @@ user for database login if not current user password to use when connecting to server +=item -h, -h, --host=# + +Hostname for local server when connecting over TCP/IP. By specifying this +different from 'localhost' will trigger mysqlhotcopy to use TCP/IP connection. + =item -P, --port=# -port to use when connecting to local server +port to use when connecting to MySQL server with TCP/IP. This is only used +when using the --host option. =item -S, --socket=# diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc index 22e40ff2830..f94d8dddb59 100644 --- a/sql/gen_lex_hash.cc +++ b/sql/gen_lex_hash.cc @@ -26,7 +26,8 @@ #include "mysql_version.h" #include "lex.h" -bool opt_search=0,opt_verbose=0; +bool opt_search=0; +uint opt_verbose=0; ulong opt_count=100000; #define max_allowed_array 8000 // Don't generate bigger arrays than this @@ -526,8 +527,7 @@ int main(int argc,char **argv) best_functype); } if (opt_verbose && (i % 20000) == 0) - printf("\nstart_value=%ldL; best_t1=%ldL; best_t2=%ldL; best_type=%d; -/* mode=%d add=%d type: %d */\n", + printf("\nstart_value=%ldL; best_t1=%ldL; best_t2=%ldL; best_type=%d; /* mode=%d add=%d type: %d */\n", best_start_value,best_t1,best_t2,best_type,best_mod,best_add, best_functype); } From 95417c335edf9c5aec9d85e0693ee7012ae001d1 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Aug 2002 17:15:51 +0300 Subject: [PATCH 26/30] Backported pthread_mutex_trylock code from MySQL 4.0 to fix problem on HPUX. Removed Heikki's patch for handling this. --- configure.in | 4 ++-- include/my_pthread.h | 17 ++++++++++------- mysys/my_pthread.c | 23 +++++++++++++++++++++-- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/configure.in b/configure.in index 4719cdda44e..460c5e73abe 100644 --- a/configure.in +++ b/configure.in @@ -849,8 +849,8 @@ case $SYSTEM_TYPE in ;; *hpux10.20*) echo "Enabling workarounds for hpux 10.20" - CFLAGS="$CFLAGS -DHAVE_BROKEN_SNPRINTF -DSIGNALS_DONT_BREAK_READ -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHPUX -DSIGNAL_WITH_VIO_CLOSE -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT -DPTHREAD_MUTEX_TRYLOCK_INVERTED_RET_VAL" - CXXFLAGS="$CXXFLAGS -DHAVE_BROKEN_SNPRINTF -D_INCLUDE_LONGLONG -DSIGNALS_DONT_BREAK_READ -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHPUX -DSIGNAL_WITH_VIO_CLOSE -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT -DPTHREAD_MUTEX_TRYLOCK_INVERTED_RET_VAL" + CFLAGS="$CFLAGS -DHAVE_BROKEN_SNPRINTF -DSIGNALS_DONT_BREAK_READ -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHPUX -DSIGNAL_WITH_VIO_CLOSE -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT" + CXXFLAGS="$CXXFLAGS -DHAVE_BROKEN_SNPRINTF -D_INCLUDE_LONGLONG -DSIGNALS_DONT_BREAK_READ -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHPUX -DSIGNAL_WITH_VIO_CLOSE -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT" if test "$with_named_thread" = "no" then echo "Using --with-named-thread=-lpthread" diff --git a/include/my_pthread.h b/include/my_pthread.h index 004c908e08e..bfb33c38013 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -428,6 +428,16 @@ struct tm *localtime_r(const time_t *clock, struct tm *res); #endif /* defined(__WIN__) */ +#if defined(HPUX) && !defined(DONT_REMAP_PTHREAD_FUNCTIONS) +#undef pthread_cond_timedwait +#undef pthread_mutex_trylock +#define pthread_cond_timedwait(a,b,c) my_pthread_cond_timedwait((a),(b),(c)) +#define pthread_mutex_trylock(a) my_pthread_mutex_trylock((a)) +int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + struct timespec *abstime); +int my_pthread_mutex_trylock(pthread_mutex_t *mutex); +#endif + /* safe_mutex adds checking to mutex for easier debugging */ typedef struct st_safe_mutex_t @@ -464,14 +474,7 @@ int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp, #define pthread_mutex_destroy(A) safe_mutex_destroy((A),__FILE__,__LINE__) #define pthread_cond_wait(A,B) safe_cond_wait((A),(B),__FILE__,__LINE__) #define pthread_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__) -#ifdef PTHREAD_MUTEX_TRYLOCK_INVERTED_RET_VAL - /* In HP-UX-10.20 and other old Posix 1003.4a Draft 4 implementations - pthread_mutex_trylock returns 1 on success, not 0 like - pthread_mutex_lock */ -#define pthread_mutex_trylock(A) (1 - pthread_mutex_lock(A)) -#else #define pthread_mutex_trylock(A) pthread_mutex_lock(A) -#endif #define pthread_mutex_t safe_mutex_t #endif /* SAFE_MUTEX */ diff --git a/mysys/my_pthread.c b/mysys/my_pthread.c index 696b62f8b0e..e4e0eff95e6 100644 --- a/mysys/my_pthread.c +++ b/mysys/my_pthread.c @@ -409,7 +409,7 @@ int my_pthread_cond_init(pthread_cond_t *mp, const pthread_condattr_t *attr) /* Change functions on HP to work according to POSIX */ -#ifdef HAVE_BROKEN_PTHREAD_COND_TIMEDWAIT +#if defined(HPUX) || defined(HAVE_BROKEN_PTHREAD_COND_TIMEDWAIT) #undef pthread_cond_timedwait int my_pthread_cond_timedwait(pthread_cond_t *cond, @@ -426,7 +426,26 @@ int my_pthread_cond_timedwait(pthread_cond_t *cond, error= ETIMEDOUT; return error; } -#endif /* HAVE_BROKEN_PTHREAD_COND_TIMEDWAIT */ +#endif + + +#ifdef HPUX +/* + In HP-UX-10.20 and other old Posix 1003.4a Draft 4 implementations + pthread_mutex_trylock returns 1 on success, not 0 like + pthread_mutex_lock +*/ + +int my_pthread_mutex_trylock(pthread_mutex_t *mutex) +{ + int error=pthread_mutex_trylock(mutex); + if (error == 1) /* Safety if the lib is fixed */ + return 0; /* Mutex was locked */ + if (error == -1) /* Safety if the lib is fixed */ + error=errno; + return error; +} +#endif /* Some help functions */ From cbb0dc14ccd3ff932edf5a29aa6af0ac210be4b9 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Aug 2002 22:20:11 +0300 Subject: [PATCH 27/30] Fixed problem with make distcheck Fixed bug in automatic repair of MyISAM tables where table cache was not locked properly Docs/manual.texi: Changelog libmysql/Makefile.am: Fixed problem with make distcheck libmysql/Makefile.shared: Fixed problem with make distcheck sql/sql_base.cc: Fixed bug in automatic repair where table cache was not locked properly. strings/Makefile.am: Fixed problem with make distcheck --- Docs/manual.texi | 3 ++- libmysql/Makefile.am | 4 ++++ libmysql/Makefile.shared | 7 ++++--- sql/sql_base.cc | 21 +++++++-------------- strings/Makefile.am | 3 +-- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/Docs/manual.texi b/Docs/manual.texi index a9eef29f11a..52c1887a13e 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -46935,7 +46935,8 @@ Fixed problem with @code{GROUP BY} on result with expression that created a @item Fixed problem with privilege tables when downgrading from 4.0.2 to 3.23. @item -Fixed thread bug in @code{SLAVE START} and @code{SLAVE STOP}. +Fixed thread bug in @code{SLAVE START}, @code{SLAVE STOP} and automatic repair +of MyISAM tables that could cause table cache to be corrupted. @item Fixed possible thread related key-cache-corruption problem with @code{OPTIMIZE TABLE} and @code{REPAIR TABLE}. diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am index 68c2022223e..85bca62d19c 100644 --- a/libmysql/Makefile.am +++ b/libmysql/Makefile.am @@ -44,6 +44,10 @@ link_sources: rm -f $(srcdir)/$$f; \ @LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \ done; \ + for f in $(mystringsgen); do \ + rm -f $(srcdir)/$$f; \ + @LN_CP_F@ ../strings/$$f $(srcdir)/$$f; \ + done; \ for f in $$ds; do \ rm -f $(srcdir)/$$f; \ @LN_CP_F@ $(srcdir)/../dbug/$$f $(srcdir)/$$f; \ diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index 76d37c149c9..d1271173b24 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -41,7 +41,8 @@ mystringsobjects = strmov.lo strxmov.lo strnmov.lo strmake.lo strend.lo \ bchange.lo bmove.lo bmove_upp.lo longlong2str.lo \ strtoull.lo strtoll.lo llstr.lo \ ctype.lo $(LTCHARSET_OBJS) -mystringsextra= strto.c ctype_autoconf.c +mystringsextra= strto.c +mystringsgen= ctype_autoconf.c dbugobjects = dbug.lo # IT IS IN SAFEMALLOC.C sanity.lo mysysheaders = mysys_priv.h my_static.h mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \ @@ -76,8 +77,8 @@ clean-local: rm -f `echo $(mystringsobjects) | sed "s;\.lo;.c;g"` \ `echo $(dbugobjects) | sed "s;\.lo;.c;g"` \ `echo $(mysysobjects) | sed "s;\.lo;.c;g"` \ - $(mystringsextra) $(mysysheaders) ctype_extra_sources.c \ - ../linked_client_sources + $(mystringsextra) $(mystringsgen) $(mysysheaders) \ + ctype_extra_sources.c ../linked_client_sources ctype_extra_sources.c: conf_to_src ./conf_to_src $(top_srcdir) @CHARSETS_NEED_SOURCE@ > \ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index cba64418355..31d6f16ef72 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -33,7 +33,7 @@ TABLE *unused_tables; /* Used by mysql_test */ HASH open_cache; /* Used by mysql_test */ static int open_unireg_entry(THD *thd,TABLE *entry,const char *db, - const char *name, const char *alias, bool locked); + const char *name, const char *alias); static bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, const char *table_name, List_iterator *it); static void free_cache_entry(TABLE *entry); @@ -711,7 +711,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1; pthread_mutex_lock(&LOCK_open); - if (open_unireg_entry(thd, table, db, table_name, table_name, 1) || + if (open_unireg_entry(thd, table, db, table_name, table_name) || !(table->table_cache_key =memdup_root(&table->mem_root,(char*) key, key_length))) { @@ -847,7 +847,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_RETURN(NULL); } - if (open_unireg_entry(thd, table,db,table_name,alias,1) || + if (open_unireg_entry(thd, table,db,table_name,alias) || !(table->table_cache_key=memdup_root(&table->mem_root,(char*) key, key_length))) { @@ -955,8 +955,7 @@ bool reopen_table(TABLE *table,bool locked) if (!locked) VOID(pthread_mutex_lock(&LOCK_open)); - if (open_unireg_entry(current_thd,&tmp,db,table_name,table->table_name, - locked)) + if (open_unireg_entry(current_thd,&tmp,db,table_name,table->table_name)) goto end; free_io_cache(table); @@ -1258,7 +1257,7 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name) */ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, - const char *name, const char *alias, bool locked) + const char *name, const char *alias) { char path[FN_REFLEN]; int error; @@ -1278,21 +1277,15 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, table_list.db=(char*) db; table_list.name=(char*) name; table_list.next=0; - if (!locked) - pthread_mutex_lock(&LOCK_open); if ((error=lock_table_name(thd,&table_list))) { if (error < 0) { - if (!locked) - pthread_mutex_unlock(&LOCK_open); goto err; } if (wait_for_locked_table_names(thd,&table_list)) { unlock_table_name(thd,&table_list); - if (!locked) - pthread_mutex_unlock(&LOCK_open); goto err; } } @@ -1322,9 +1315,9 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, thd->net.last_error[0]=0; // Clear error message thd->net.last_errno=0; } - if (locked) - pthread_mutex_lock(&LOCK_open); // Get back original lock + pthread_mutex_lock(&LOCK_open); unlock_table_name(thd,&table_list); + if (error) goto err; } diff --git a/strings/Makefile.am b/strings/Makefile.am index d3bb4b54dcf..ca3188db1a4 100644 --- a/strings/Makefile.am +++ b/strings/Makefile.am @@ -44,7 +44,6 @@ noinst_PROGRAMS = conf_to_src EXTRA_DIST = ctype-big5.c ctype-czech.c ctype-euc_kr.c \ ctype-gb2312.c ctype-gbk.c ctype-sjis.c \ ctype-tis620.c ctype-ujis.c \ - ctype_autoconf.c \ strto.c strings-x86.s \ longlong2str.c longlong2str-x86.s \ strxmov.c bmove_upp.c strappend.c strcont.c strend.c \ @@ -80,7 +79,7 @@ conf_to_src_LDFLAGS= @NOINST_LDFLAGS@ strtoull.o: @CHARSET_OBJS@ clean-local: - rm -f ctype_extra_sources.c + rm -f ctype_extra_sources.c ctype_autoconf.c if ASSEMBLER # On Linux gcc can compile the assembly files From a3edc742b94a94ff455ff549d7e2a9f5faa346a0 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Aug 2002 22:59:13 +0300 Subject: [PATCH 28/30] Many files: Merge InnoDB-3.23.52d innobase/btr/btr0sea.c: Merge InnoDB-3.23.52d innobase/buf/buf0buf.c: Merge InnoDB-3.23.52d innobase/buf/buf0lru.c: Merge InnoDB-3.23.52d innobase/include/buf0buf.h: Merge InnoDB-3.23.52d innobase/include/ha0ha.h: Merge InnoDB-3.23.52d innobase/include/log0log.h: Merge InnoDB-3.23.52d innobase/include/os0file.h: Merge InnoDB-3.23.52d innobase/include/os0thread.h: Merge InnoDB-3.23.52d innobase/include/ha0ha.ic: Merge InnoDB-3.23.52d innobase/include/os0sync.ic: Merge InnoDB-3.23.52d innobase/include/srv0start.h: Merge InnoDB-3.23.52d innobase/include/sync0rw.ic: Merge InnoDB-3.23.52d innobase/include/sync0sync.ic: Merge InnoDB-3.23.52d innobase/include/ut0dbg.h: Merge InnoDB-3.23.52d innobase/include/univ.i: Merge InnoDB-3.23.52d innobase/lock/lock0lock.c: Merge InnoDB-3.23.52d innobase/log/log0log.c: Merge InnoDB-3.23.52d innobase/mem/mem0pool.c: Merge InnoDB-3.23.52d innobase/os/os0file.c: Merge InnoDB-3.23.52d innobase/os/os0thread.c: Merge InnoDB-3.23.52d innobase/srv/srv0srv.c: Merge InnoDB-3.23.52d innobase/srv/srv0start.c: Merge InnoDB-3.23.52d innobase/sync/sync0arr.c: Merge InnoDB-3.23.52d innobase/sync/sync0rw.c: Merge InnoDB-3.23.52d innobase/sync/sync0sync.c: Merge InnoDB-3.23.52d innobase/thr/thr0loc.c: Merge InnoDB-3.23.52d innobase/trx/trx0trx.c: Merge InnoDB-3.23.52d innobase/configure.in: Merge InnoDB-3.23.52d sql/ha_innobase.cc: Merge InnoDB-3.23.52d --- innobase/btr/btr0sea.c | 1 + innobase/buf/buf0buf.c | 18 +++++- innobase/buf/buf0lru.c | 7 ++- innobase/configure.in | 2 + innobase/include/buf0buf.h | 6 ++ innobase/include/ha0ha.h | 8 +++ innobase/include/ha0ha.ic | 10 ---- innobase/include/log0log.h | 6 ++ innobase/include/os0file.h | 6 ++ innobase/include/os0sync.ic | 14 +++++ innobase/include/os0thread.h | 28 +++++++--- innobase/include/srv0start.h | 2 +- innobase/include/sync0rw.ic | 3 +- innobase/include/sync0sync.ic | 4 ++ innobase/include/univ.i | 2 +- innobase/include/ut0dbg.h | 13 +++-- innobase/lock/lock0lock.c | 102 ++++++++++++++++++++++++++++++++-- innobase/log/log0log.c | 15 ++++- innobase/mem/mem0pool.c | 53 +++++++++++++++++- innobase/os/os0file.c | 17 +++++- innobase/os/os0thread.c | 87 +++++++++++++++++------------ innobase/srv/srv0srv.c | 57 +++++++++++++++---- innobase/srv/srv0start.c | 22 ++++++++ innobase/sync/sync0arr.c | 23 ++++---- innobase/sync/sync0rw.c | 23 ++++---- innobase/sync/sync0sync.c | 22 ++++---- innobase/thr/thr0loc.c | 12 ++-- innobase/trx/trx0trx.c | 2 +- sql/ha_innobase.cc | 1 + 29 files changed, 437 insertions(+), 129 deletions(-) diff --git a/innobase/btr/btr0sea.c b/innobase/btr/btr0sea.c index 5db737561aa..a798f28b4ab 100644 --- a/innobase/btr/btr0sea.c +++ b/innobase/btr/btr0sea.c @@ -17,6 +17,7 @@ Created 2/17/1996 Heikki Tuuri #include "btr0cur.h" #include "btr0pcur.h" #include "btr0btr.h" +#include "ha0ha.h" ulint btr_search_n_succ = 0; ulint btr_search_n_hash_fail = 0; diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index a447f9692a7..ee8e8b91f8d 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -1844,8 +1844,8 @@ buf_print_io( buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]); current_time = time(NULL); - time_elapsed = difftime(current_time, buf_pool->last_printout_time); - + time_elapsed = 0.001 + difftime(current_time, + buf_pool->last_printout_time); buf_pool->last_printout_time = current_time; buf += sprintf(buf, "Pages read %lu, created %lu, written %lu\n", @@ -1878,6 +1878,20 @@ buf_print_io( mutex_exit(&(buf_pool->mutex)); } +/************************************************************************** +Refreshes the statistics used to print per-second averages. */ + +void +buf_refresh_io_stats(void) +/*======================*/ +{ + buf_pool->last_printout_time = time(NULL); + buf_pool->n_page_gets_old = buf_pool->n_page_gets; + buf_pool->n_pages_read_old = buf_pool->n_pages_read; + buf_pool->n_pages_created_old = buf_pool->n_pages_created; + buf_pool->n_pages_written_old = buf_pool->n_pages_written; +} + /************************************************************************* Checks that all file pages in the buffer are in a replaceable state. */ diff --git a/innobase/buf/buf0lru.c b/innobase/buf/buf0lru.c index ffdc58f2224..bd69dff740c 100644 --- a/innobase/buf/buf0lru.c +++ b/innobase/buf/buf0lru.c @@ -27,6 +27,7 @@ Created 11/5/1995 Heikki Tuuri #include "buf0rea.h" #include "btr0sea.h" #include "os0file.h" +#include "log0recv.h" /* The number of blocks from the LRU_old pointer onward, including the block pointed to, must be 3/8 of the whole LRU list length, except that the @@ -204,7 +205,7 @@ buf_LRU_get_free_block(void) loop: mutex_enter(&(buf_pool->mutex)); - if (UT_LIST_GET_LEN(buf_pool->free) + if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free) + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 10) { ut_print_timestamp(stderr); @@ -216,7 +217,7 @@ loop: ut_a(0); - } else if (UT_LIST_GET_LEN(buf_pool->free) + } else if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free) + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 5) { /* Over 80 % of the buffer pool is occupied by lock heaps @@ -232,7 +233,7 @@ loop: srv_print_innodb_monitor = TRUE; - } else if (UT_LIST_GET_LEN(buf_pool->free) + } else if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free) + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 4) { /* Switch off the InnoDB Monitor; this is a simple way diff --git a/innobase/configure.in b/innobase/configure.in index e98dc3d0f0d..48787b680b2 100644 --- a/innobase/configure.in +++ b/innobase/configure.in @@ -85,6 +85,8 @@ else fi case "$target_os" in + hpux10*) + CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE -DUNIV_HPUX -DUNIV_HPUX10";; hp*) CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE -DUNIV_HPUX";; irix*) diff --git a/innobase/include/buf0buf.h b/innobase/include/buf0buf.h index b80ed96f54c..591c0ec54ab 100644 --- a/innobase/include/buf0buf.h +++ b/innobase/include/buf0buf.h @@ -463,6 +463,12 @@ buf_print_io( /*=========*/ char* buf, /* in/out: buffer where to print */ char* buf_end);/* in: buffer end */ +/************************************************************************** +Refreshes the statistics used to print per-second averages. */ + +void +buf_refresh_io_stats(void); +/*======================*/ /************************************************************************* Checks that all file pages in the buffer are in a replaceable state. */ diff --git a/innobase/include/ha0ha.h b/innobase/include/ha0ha.h index 945b1198a41..0beac928b7e 100644 --- a/innobase/include/ha0ha.h +++ b/innobase/include/ha0ha.h @@ -131,6 +131,14 @@ ha_print_info( char* buf_end,/* in: buffer end */ hash_table_t* table); /* in: hash table */ +/* The hash table external chain node */ + +typedef struct ha_node_struct ha_node_t; +struct ha_node_struct { + ha_node_t* next; /* next chain node or NULL if none */ + void* data; /* pointer to the data */ + ulint fold; /* fold value for the data */ +}; #ifndef UNIV_NONINL #include "ha0ha.ic" diff --git a/innobase/include/ha0ha.ic b/innobase/include/ha0ha.ic index 7b4c624c653..1aad7d5a36f 100644 --- a/innobase/include/ha0ha.ic +++ b/innobase/include/ha0ha.ic @@ -9,16 +9,6 @@ Created 8/18/1994 Heikki Tuuri #include "ut0rnd.h" #include "mem0mem.h" -/* The hash table external chain node */ - -typedef struct ha_node_struct ha_node_t; - -struct ha_node_struct { - ha_node_t* next; /* next chain node or NULL if none */ - void* data; /* pointer to the data */ - ulint fold; /* fold value for the data */ -}; - /*************************************************************** Deletes a hash node. */ diff --git a/innobase/include/log0log.h b/innobase/include/log0log.h index 4358577c59c..f200371de9d 100644 --- a/innobase/include/log0log.h +++ b/innobase/include/log0log.h @@ -512,6 +512,12 @@ log_print( /*======*/ char* buf, /* in/out: buffer where to print */ char* buf_end);/* in: buffer end */ +/************************************************************************** +Refreshes the statistics used to print per-second averages. */ + +void +log_refresh_stats(void); +/*===================*/ extern log_t* log_sys; diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index b7911c5014a..d65c7fd47e3 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -408,6 +408,12 @@ os_aio_print( char* buf, /* in/out: buffer where to print */ char* buf_end);/* in: buffer end */ /************************************************************************** +Refreshes the statistics used to print per-second averages. */ + +void +os_aio_refresh_stats(void); +/*======================*/ +/************************************************************************** Checks that all slots in the system have been freed, that is, there are no pending io operations. */ diff --git a/innobase/include/os0sync.ic b/innobase/include/os0sync.ic index 6bff75d8ec6..10b85c435e3 100644 --- a/innobase/include/os0sync.ic +++ b/innobase/include/os0sync.ic @@ -27,7 +27,21 @@ os_fast_mutex_trylock( return(0); #else +#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10) + /* Since the hot backup version is standalone, MySQL does not redefine + pthread_mutex_trylock for HP-UX-10.20, and consequently we must invert + the return value here */ + + return((ulint) (1 - pthread_mutex_trylock(fast_mutex))); +#else + /* NOTE that the MySQL my_pthread.h redefines pthread_mutex_trylock + so that it returns 0 on success. In the operating system + libraries, HP-UX-10.20 follows the old Posix 1003.4a Draft 4 and + returns 1 on success (but MySQL remaps that to 0), while Linux, + FreeBSD, Solaris, AIX, Tru64 Unix, HP-UX-11.0 return 0 on success. */ + return((ulint) pthread_mutex_trylock(fast_mutex)); #endif +#endif } diff --git a/innobase/include/os0thread.h b/innobase/include/os0thread.h index 0d6fa5a8f37..636cfd79e50 100644 --- a/innobase/include/os0thread.h +++ b/innobase/include/os0thread.h @@ -28,12 +28,30 @@ typedef void* os_thread_t; #else typedef pthread_t os_thread_t; #endif -typedef unsigned long int os_thread_id_t; + +#define os_thread_id_t os_thread_t /* Define a function pointer type to use in a typecast */ typedef void* (*os_posix_f_t) (void*); +/******************************************************************* +Compares two threads or thread ids for equality */ +ibool +os_thread_eq( +/*=========*/ + /* out: TRUE if equal */ + os_thread_t a, /* in: OS thread or thread id */ + os_thread_t b); /* in: OS thread or thread id */ +/******************************************************************** +Converts an OS thread or thread id to a ulint. It is NOT guaranteed that +the ulint is unique for the thread though! */ + +ulint +os_thread_pf( +/*=========*/ + /* out: unsigned long int */ + os_thread_t a); /* in: thread or thread id */ /******************************************************************** Creates a new thread of execution. The execution starts from the function given. The start function takes a void* parameter @@ -73,14 +91,6 @@ os_thread_t os_thread_get_curr(void); /*====================*/ /********************************************************************* -Converts a thread id to a ulint. */ - -ulint -os_thread_conv_id_to_ulint( -/*=======================*/ - /* out: converted to ulint */ - os_thread_id_t id); /* in: thread id */ -/********************************************************************* Waits for a thread to terminate. */ void diff --git a/innobase/include/srv0start.h b/innobase/include/srv0start.h index 01ac063e1c9..646d2c1bb06 100644 --- a/innobase/include/srv0start.h +++ b/innobase/include/srv0start.h @@ -85,7 +85,7 @@ extern ibool srv_is_being_shut_down; /* At a shutdown the value first climbs from 0 to SRV_SHUTDOWN_CLEANUP and then to SRV_SHUTDOWN_LAST_PHASE */ -extern ulint srv_shutdown_state; +extern ulint srv_shutdown_state; #define SRV_SHUTDOWN_CLEANUP 1 #define SRV_SHUTDOWN_LAST_PHASE 2 diff --git a/innobase/include/sync0rw.ic b/innobase/include/sync0rw.ic index af5c4576da6..7015ff34b99 100644 --- a/innobase/include/sync0rw.ic +++ b/innobase/include/sync0rw.ic @@ -311,7 +311,8 @@ rw_lock_x_lock_func_nowait( && ((rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) || ((rw_lock_get_writer(lock) == RW_LOCK_EX) && (lock->pass == 0) - && (lock->writer_thread == os_thread_get_curr_id())))) { + && os_thread_eq(lock->writer_thread, + os_thread_get_curr_id())))) { rw_lock_set_writer(lock, RW_LOCK_EX); lock->writer_thread = os_thread_get_curr_id(); diff --git a/innobase/include/sync0sync.ic b/innobase/include/sync0sync.ic index 9014eb5fb54..c11cc0d196e 100644 --- a/innobase/include/sync0sync.ic +++ b/innobase/include/sync0sync.ic @@ -104,6 +104,10 @@ mutex_test_and_set( ret = os_fast_mutex_trylock(&(mutex->os_fast_mutex)); if (ret == 0) { + /* We check that os_fast_mutex_trylock does not leak + and allow race conditions */ + ut_a(mutex->lock_word == 0); + mutex->lock_word = 1; } diff --git a/innobase/include/univ.i b/innobase/include/univ.i index 15a6115c37e..f5d083766bc 100644 --- a/innobase/include/univ.i +++ b/innobase/include/univ.i @@ -80,8 +80,8 @@ memory is read outside the allocated blocks. */ /* #define UNIV_DEBUG -#define UNIV_MEM_DEBUG #define UNIV_SYNC_DEBUG +#define UNIV_MEM_DEBUG #define UNIV_IBUF_DEBUG #define UNIV_SEARCH_DEBUG diff --git a/innobase/include/ut0dbg.h b/innobase/include/ut0dbg.h index fc5d493ca5e..3407483696c 100644 --- a/innobase/include/ut0dbg.h +++ b/innobase/include/ut0dbg.h @@ -26,9 +26,11 @@ extern ulint* ut_dbg_null_ptr; ulint dbg_i;\ \ if (!((ulint)(EXPR) + ut_dbg_zero)) {\ + ut_print_timestamp(stderr);\ fprintf(stderr,\ - "InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\ - os_thread_get_curr_id(), IB__FILE__, (ulint)__LINE__);\ + " InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\ + os_thread_pf(os_thread_get_curr_id()), IB__FILE__,\ + (ulint)__LINE__);\ fprintf(stderr,\ "InnoDB: We intentionally generate a memory trap.\n");\ fprintf(stderr,\ @@ -42,16 +44,17 @@ extern ulint* ut_dbg_null_ptr; if (ut_dbg_stop_threads) {\ fprintf(stderr,\ "InnoDB: Thread %lu stopped in file %s line %lu\n",\ - os_thread_get_curr_id(), IB__FILE__, (ulint)__LINE__);\ + os_thread_pf(os_thread_get_curr_id()), IB__FILE__, (ulint)__LINE__);\ os_thread_sleep(1000000000);\ }\ } #define ut_error {\ ulint dbg_i;\ + ut_print_timestamp(stderr);\ fprintf(stderr,\ - "InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\ - os_thread_get_curr_id(), IB__FILE__, (ulint)__LINE__);\ + " InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\ + os_thread_pf(os_thread_get_curr_id()), IB__FILE__, (ulint)__LINE__);\ fprintf(stderr,\ "InnoDB: We intentionally generate a memory trap.\n");\ fprintf(stderr,\ diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index ea035dbdeb0..2f5ade656d9 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -301,6 +301,11 @@ struct lock_struct{ } un_member; }; +/* We store info on the latest deadlock error to this buffer. InnoDB +Monitor will then fetch it and print */ +ibool lock_deadlock_found = FALSE; +char* lock_latest_err_buf; /* We allocate 5000 bytes for this */ + /************************************************************************ Checks if a lock request results in a deadlock. */ static @@ -575,6 +580,8 @@ lock_sys_create( lock_sys->rec_hash = hash_create(n_cells); /* hash_create_mutexes(lock_sys->rec_hash, 2, SYNC_REC_LOCK); */ + + lock_latest_err_buf = mem_alloc(5000); } /************************************************************************* @@ -2698,6 +2705,7 @@ lock_deadlock_occurs( trx_t* mark_trx; ibool ret; ulint cost = 0; + char* err_buf; ut_ad(trx && lock); ut_ad(mutex_own(&kernel_mutex)); @@ -2723,6 +2731,29 @@ lock_deadlock_occurs( index = lock->index; table = index->table; } + + lock_deadlock_found = TRUE; + + err_buf = lock_latest_err_buf + strlen(lock_latest_err_buf); + + err_buf += sprintf(err_buf, + "*** (2) WAITING FOR THIS LOCK TO BE GRANTED:\n"); + + ut_a(err_buf <= lock_latest_err_buf + 4000); + + if (lock_get_type(lock) == LOCK_REC) { + lock_rec_print(err_buf, lock); + err_buf += strlen(err_buf); + } else { + lock_table_print(err_buf, lock); + err_buf += strlen(err_buf); + } + + ut_a(err_buf <= lock_latest_err_buf + 4000); + + err_buf += sprintf(err_buf, + "*** WE ROLL BACK TRANSACTION (2)\n"); + /* sess_raise_error_low(trx, DB_DEADLOCK, lock->type_mode, table, index, NULL, NULL, NULL); @@ -2750,6 +2781,7 @@ lock_deadlock_recursive( lock_t* lock; ulint bit_no; trx_t* lock_trx; + char* err_buf; ut_a(trx && start && wait_lock); ut_ad(mutex_own(&kernel_mutex)); @@ -2801,6 +2833,53 @@ lock_deadlock_recursive( lock_trx = lock->trx; if (lock_trx == start) { + err_buf = lock_latest_err_buf; + + ut_sprintf_timestamp(err_buf); + err_buf += strlen(err_buf); + + err_buf += sprintf(err_buf, + " LATEST DETECTED DEADLOCK:\n" + "*** (1) TRANSACTION:\n"); + + trx_print(err_buf, wait_lock->trx); + err_buf += strlen(err_buf); + + err_buf += sprintf(err_buf, + "*** (1) WAITING FOR THIS LOCK TO BE GRANTED:\n"); + + ut_a(err_buf <= lock_latest_err_buf + 4000); + + if (lock_get_type(wait_lock) == LOCK_REC) { + lock_rec_print(err_buf, wait_lock); + err_buf += strlen(err_buf); + } else { + lock_table_print(err_buf, wait_lock); + err_buf += strlen(err_buf); + } + + ut_a(err_buf <= lock_latest_err_buf + 4000); + err_buf += sprintf(err_buf, + "*** (2) TRANSACTION:\n"); + + trx_print(err_buf, lock->trx); + err_buf += strlen(err_buf); + + err_buf += sprintf(err_buf, + "*** (2) HOLDS THE LOCK(S):\n"); + + ut_a(err_buf <= lock_latest_err_buf + 4000); + + if (lock_get_type(lock) == LOCK_REC) { + lock_rec_print(err_buf, lock); + err_buf += strlen(err_buf); + } else { + lock_table_print(err_buf, lock); + err_buf += strlen(err_buf); + } + + ut_a(err_buf <= lock_latest_err_buf + 4000); + if (lock_print_waits) { printf("Deadlock detected\n"); } @@ -3433,6 +3512,9 @@ lock_rec_print( buf += sprintf(buf, "Suppressing further record lock prints for this page\n"); + + mtr_commit(&mtr); + return; } @@ -3505,10 +3587,6 @@ lock_print_info( return; } - buf += sprintf(buf, "Number of sessions %lu\n", - UT_LIST_GET_LEN(trx_sys->mysql_trx_list) - + UT_LIST_GET_LEN(trx_sys->trx_list)); - buf += sprintf(buf, "Trx id counter %lu %lu\n", ut_dulint_get_high(trx_sys->max_trx_id), ut_dulint_get_low(trx_sys->max_trx_id)); @@ -3525,6 +3603,22 @@ lock_print_info( buf += sprintf(buf, "Total number of lock structs in row lock hash table %lu\n", lock_get_n_rec_locks()); + if (lock_deadlock_found) { + + if ((ulint)(buf_end - buf) + < 100 + strlen(lock_latest_err_buf)) { + + return; + } + + buf += sprintf(buf, "%s", lock_latest_err_buf); + } + + if (buf_end - buf < 600) { + return; + } + + buf += sprintf(buf, "LIST OF TRANSACTIONS FOR EACH SESSION:\n"); /* First print info on non-active transactions */ diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c index 644d53ac273..cb85e9d3ba6 100644 --- a/innobase/log/log0log.c +++ b/innobase/log/log0log.c @@ -3096,8 +3096,8 @@ log_print( current_time = time(NULL); - time_elapsed = difftime(current_time, log_sys->last_printout_time); - + time_elapsed = 0.001 + difftime(current_time, + log_sys->last_printout_time); buf += sprintf(buf, "%lu pending log writes, %lu pending chkp writes\n" "%lu log i/o's done, %.2f log i/o's/second\n", @@ -3111,3 +3111,14 @@ log_print( mutex_exit(&(log_sys->mutex)); } + +/************************************************************************** +Refreshes the statistics used to print per-second averages. */ + +void +log_refresh_stats(void) +/*===================*/ +{ + log_sys->n_log_ios_old = log_sys->n_log_ios; + log_sys->last_printout_time = time(NULL); +} diff --git a/innobase/mem/mem0pool.c b/innobase/mem/mem0pool.c index 3681c8ef779..61cf1e50ce9 100644 --- a/innobase/mem/mem0pool.c +++ b/innobase/mem/mem0pool.c @@ -251,6 +251,7 @@ mem_pool_fill_free_list( mem_area_t* area; mem_area_t* area2; ibool ret; + char err_buf[500]; ut_ad(mutex_own(&(pool->mutex))); @@ -279,15 +280,34 @@ mem_pool_fill_free_list( area = UT_LIST_GET_FIRST(pool->free_list[i + 1]); if (area == NULL) { + if (UT_LIST_GET_LEN(pool->free_list[i + 1]) > 0) { + ut_print_timestamp(stderr); + + fprintf(stderr, +" InnoDB: Error: mem pool free list %lu length is %lu\n" +"InnoDB: though the list is empty!\n", + i + 1, UT_LIST_GET_LEN(pool->free_list[i + 1])); + } + ret = mem_pool_fill_free_list(i + 1, pool); if (ret == FALSE) { + return(FALSE); } area = UT_LIST_GET_FIRST(pool->free_list[i + 1]); } - + + if (UT_LIST_GET_LEN(pool->free_list[i + 1]) == 0) { + ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100); + fprintf(stderr, +"InnoDB: Error: Removing element from mem pool free list %lu\n" +"InnoDB: though the list length is 0! Dump of 100 bytes around element:\n%s\n", + i + 1, err_buf); + ut_a(0); + } + UT_LIST_REMOVE(free_list, pool->free_list[i + 1], area); area2 = (mem_area_t*)(((byte*)area) + ut_2_exp(i)); @@ -320,6 +340,7 @@ mem_area_alloc( mem_area_t* area; ulint n; ibool ret; + char err_buf[500]; n = ut_2_log(ut_max(size + MEM_AREA_EXTRA_SIZE, MEM_AREA_MIN_SIZE)); @@ -342,7 +363,24 @@ mem_area_alloc( area = UT_LIST_GET_FIRST(pool->free_list[n]); } - ut_a(mem_area_get_free(area)); + if (!mem_area_get_free(area)) { + ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100); + fprintf(stderr, +"InnoDB: Error: Removing element from mem pool free list %lu though the\n" +"InnoDB: element is not marked free! Dump of 100 bytes around element:\n%s\n", + n, err_buf); + ut_a(0); + } + + if (UT_LIST_GET_LEN(pool->free_list[n]) == 0) { + ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100); + fprintf(stderr, +"InnoDB: Error: Removing element from mem pool free list %lu\n" +"InnoDB: though the list length is 0! Dump of 100 bytes around element:\n%s\n", + n, err_buf); + ut_a(0); + } + ut_ad(mem_area_get_size(area) == ut_2_exp(n)); mem_area_set_free(area, FALSE); @@ -413,6 +451,7 @@ mem_area_free( void* new_ptr; ulint size; ulint n; + char err_buf[500]; if (mem_out_of_mem_err_msg_count > 0) { /* It may be that the area was really allocated from the @@ -429,10 +468,18 @@ mem_area_free( area = (mem_area_t*) (((byte*)ptr) - MEM_AREA_EXTRA_SIZE); + if (mem_area_get_free(area)) { + ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100); + fprintf(stderr, +"InnoDB: Error: Freeing element to mem pool free list though the\n" +"InnoDB: element is marked free! Dump of 100 bytes around element:\n%s\n", + err_buf); + ut_a(0); + } + size = mem_area_get_size(area); ut_ad(size != 0); - ut_a(!mem_area_get_free(area)); #ifdef UNIV_LIGHT_MEM_DEBUG if (((byte*)area) + size < pool->buf + pool->size) { diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index e40de2198c1..10bb9bb66d7 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -2486,7 +2486,7 @@ loop: buf += sprintf(buf, "\n"); current_time = time(NULL); - time_elapsed = difftime(current_time, os_last_printout); + time_elapsed = 0.001 + difftime(current_time, os_last_printout); buf += sprintf(buf, "Pending flushes (fsync) log: %lu; buffer pool: %lu\n", @@ -2520,6 +2520,21 @@ loop: os_last_printout = current_time; } +/************************************************************************** +Refreshes the statistics used to print per-second averages. */ + +void +os_aio_refresh_stats(void) +/*======================*/ +{ + os_n_file_reads_old = os_n_file_reads; + os_n_file_writes_old = os_n_file_writes; + os_n_fsyncs_old = os_n_fsyncs; + os_bytes_read_since_printout = 0; + + os_last_printout = time(NULL); +} + /************************************************************************** Checks that all slots in the system have been freed, that is, there are no pending io operations. */ diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index 44817302340..75f19f6d175 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -18,37 +18,63 @@ Created 9/8/1995 Heikki Tuuri #include "srv0srv.h" +/******************************************************************* +Compares two threads or thread ids for equality */ + +ibool +os_thread_eq( +/*=========*/ + /* out: TRUE if equal */ + os_thread_t a, /* in: OS thread or thread id */ + os_thread_t b) /* in: OS thread or thread id */ +{ +#ifdef __WIN__ + if (a == b) { + return(TRUE); + } + + return(FALSE); +#else + if (pthread_equal(a, b)) { + return(TRUE); + } + + return(FALSE); +#endif +} + +/******************************************************************** +Converts an OS thread or thread id to a ulint. It is NOT guaranteed that +the ulint is unique for the thread though! */ + +ulint +os_thread_pf( +/*=========*/ + os_thread_t a) +{ +#ifdef UNIV_HPUX + /* In HP-UX a pthread_t is a struct of 3 fields: field1, field2, + field3. We do not know if field1 determines the thread uniquely. */ + + return((ulint)(a.field1)); +#else + return((ulint)a); +#endif +} + /********************************************************************* -Returns the thread identifier of current thread. */ +Returns the thread identifier of current thread. Currently the thread +identifier is the thread handle itself. Note that in HP-UX pthread_t is +a struct of 3 fields. */ os_thread_id_t os_thread_get_curr_id(void) /*=======================*/ { #ifdef __WIN__ - return(GetCurrentThreadId()); + return(GetCurrentThread()); #else - pthread_t pthr; - - pthr = pthread_self(); - -#ifdef HPUX - /* TODO: in the future we have to change os_thread_id - to pthread_t! */ - - /* In HP-UX a pthread_t seems to be a struct of three fields: - field1, field2, field3, and the first probably determines (?) - the thread identity. */ - - return((os_thread_id_t)(pthr.field1)); -#else - /* TODO: define os_thread_id_t in Unix as the same as pthread_t - and compare them with appropriate Posix pthread functions! - The following typecast will not work if pthread_t is not - an integer or a pointer to a unique object for the thread! */ - - return((os_thread_id_t)pthr); -#endif + return(pthread_self()); #endif } @@ -81,7 +107,6 @@ os_thread_create( arg, 0, /* thread runs immediately */ thread_id); - ut_a(thread); if (srv_set_thread_priorities) { @@ -118,7 +143,7 @@ Returns handle to the current thread. */ os_thread_t os_thread_get_curr(void) -/*=======================*/ +/*====================*/ { #ifdef __WIN__ return(GetCurrentThread()); @@ -126,18 +151,6 @@ os_thread_get_curr(void) return(pthread_self()); #endif } - -/********************************************************************* -Converts a thread id to a ulint. */ - -ulint -os_thread_conv_id_to_ulint( -/*=======================*/ - /* out: converted to ulint */ - os_thread_id_t id) /* in: thread id */ -{ - return((ulint)id); -} /********************************************************************* Advises the os to give up remainder of the thread's time slice. */ diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index 3af2d96d921..2ce97c34e06 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -2018,7 +2018,7 @@ srv_table_reserve_slot_for_mysql(void) fprintf(stderr, "Slot %lu: thread id %lu, type %lu, in use %lu, susp %lu, time %lu\n", - i, (ulint)(slot->id), + i, os_thread_pf(slot->id), slot->type, slot->in_use, slot->suspended, (ulint)difftime(ut_time(), slot->suspend_time)); @@ -2162,6 +2162,34 @@ srv_release_mysql_thread_if_suspended( /* not found */ } +/********************************************************************** +Refreshes the values used to calculate per-second averages. */ +static +void +srv_refresh_innodb_monitor_stats(void) +/*==================================*/ +{ + mutex_enter(&srv_innodb_monitor_mutex); + + srv_last_monitor_time = time(NULL); + + os_aio_refresh_stats(); + + btr_cur_n_sea_old = btr_cur_n_sea; + btr_cur_n_non_sea_old = btr_cur_n_non_sea; + + log_refresh_stats(); + + buf_refresh_io_stats(); + + 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; + + mutex_exit(&srv_innodb_monitor_mutex); +} + /********************************************************************** Sprintfs to a buffer the output of the InnoDB Monitor. */ @@ -2199,7 +2227,7 @@ srv_sprintf_innodb_monitor( "=====================================\n"); buf += sprintf(buf, -"Per second values calculated from the last %lu seconds\n", +"Per second averages calculated from the last %lu seconds\n", (ulint)time_elapsed); buf += sprintf(buf, "----------\n" @@ -2236,8 +2264,8 @@ srv_sprintf_innodb_monitor( / 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; + 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" @@ -2279,10 +2307,10 @@ srv_sprintf_innodb_monitor( (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; + 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" @@ -2325,7 +2353,7 @@ loop: /* When someone is waiting for a lock, we wake up every second and check if a timeout has passed for a lock wait */ - os_thread_sleep(1000000); + os_thread_sleep(1000000); /* In case mutex_exit is not a memory barrier, it is theoretically possible some threads are left waiting though @@ -2342,9 +2370,9 @@ loop: if (srv_print_innodb_monitor) { - buf = mem_alloc(100000); + buf = mem_alloc(100000); - srv_sprintf_innodb_monitor(buf, 100000); + srv_sprintf_innodb_monitor(buf, 100000); printf("%s", buf); @@ -2485,6 +2513,13 @@ loop: os_thread_sleep(2000000); + if (difftime(time(NULL), srv_last_monitor_time) > 60) { + /* We referesh InnoDB Monitor values so that averages are + printed from at most 60 last seconds */ + + srv_refresh_innodb_monitor_stats(); + } + /* mem_print_new_info(); if (cnt % 10 == 0) { diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index b35bca1ea8e..ea0ed7c961e 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -74,6 +74,12 @@ ulint ios; ulint n[SRV_MAX_N_IO_THREADS + 5]; os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 5]; +/* We use this mutex to test the return value of pthread_mutex_trylock + on successful locking. HP-UX does NOT return 0, though Linux et al do. */ +os_fast_mutex_t srv_os_test_mutex; + +ibool srv_os_test_mutex_is_locked = FALSE; + #define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD #define SRV_MAX_N_PENDING_SYNC_IOS 100 @@ -1353,6 +1359,22 @@ innobase_start_or_create_for_mysql(void) tablespace_size_in_header, sum_of_data_file_sizes); } + /* Check that os_fast_mutexes work as exptected */ + os_fast_mutex_init(&srv_os_test_mutex); + + if (0 != os_fast_mutex_trylock(&srv_os_test_mutex)) { + fprintf(stderr, +"InnoDB: Error: pthread_mutex_trylock returns an unexpected value on\n" + "InnoDB: success! Cannot continue.\n"); + exit(1); + } + + os_fast_mutex_unlock(&srv_os_test_mutex); + + os_fast_mutex_lock(&srv_os_test_mutex); + + os_fast_mutex_unlock(&srv_os_test_mutex); + ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Started\n"); diff --git a/innobase/sync/sync0arr.c b/innobase/sync/sync0arr.c index 81b5b7de195..ad3ac84b6eb 100644 --- a/innobase/sync/sync0arr.c +++ b/innobase/sync/sync0arr.c @@ -454,7 +454,7 @@ sync_array_cell_print( buf += sprintf(buf, "--Thread %lu has waited at %s line %lu for %.2f seconds the semaphore:\n", - (ulint)cell->thread, cell->file, cell->line, + os_thread_pf(cell->thread), cell->file, cell->line, difftime(time(NULL), cell->reservation_time)); if (type == SYNC_MUTEX) { @@ -486,7 +486,7 @@ sync_array_cell_print( if (rwlock->writer != RW_LOCK_NOT_LOCKED) { buf += sprintf(buf, "a writer (thread id %lu) has reserved it in mode", - (ulint)rwlock->writer_thread); + os_thread_pf(rwlock->writer_thread)); if (rwlock->writer == RW_LOCK_EX) { buf += sprintf(buf, " exclusive\n"); } else { @@ -535,8 +535,8 @@ sync_array_find_thread( cell = sync_array_get_nth_cell(arr, i); - if ((cell->wait_object != NULL) - && (cell->thread == thread)) { + if (cell->wait_object != NULL + && os_thread_eq(cell->thread, thread)) { return(cell); /* Found */ } @@ -651,9 +651,9 @@ sync_array_detect_deadlock( sync_array_cell_print(buf, cell); printf( "Mutex %lx owned by thread %lu file %s line %lu\n%s", - (ulint)mutex, mutex->thread_id, - mutex->file_name, mutex->line, - buf); + (ulint)mutex, os_thread_pf(mutex->thread_id), + mutex->file_name, mutex->line, buf); + return(TRUE); } } @@ -671,9 +671,9 @@ sync_array_detect_deadlock( thread = debug->thread_id; if (((debug->lock_type == RW_LOCK_EX) - && (thread != cell->thread)) + && !os_thread_eq(thread, cell->thread)) || ((debug->lock_type == RW_LOCK_WAIT_EX) - && (thread != cell->thread)) + && !os_thread_eq(thread, cell->thread)) || (debug->lock_type == RW_LOCK_SHARED)) { /* The (wait) x-lock request can block infinitely @@ -771,7 +771,7 @@ sync_arr_cell_can_wake_up( if (rw_lock_get_reader_count(lock) == 0 && rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX - && lock->writer_thread == cell->thread) { + && os_thread_eq(lock->writer_thread, cell->thread)) { return(TRUE); } @@ -927,7 +927,7 @@ sync_array_print_long_waits(void) && difftime(time(NULL), cell->reservation_time) > 420) { fprintf(stderr, -"InnoDB: Error: semaphore wait has lasted > 420 seconds\n" +"InnoDB: Error: semaphore wait has lasted > 600 seconds\n" "InnoDB: We intentionally crash the server, because it appears to be hung.\n" ); @@ -1011,3 +1011,4 @@ sync_array_print_info( sync_array_exit(arr); } + diff --git a/innobase/sync/sync0rw.c b/innobase/sync/sync0rw.c index 1ef2920618f..93db9b9d507 100644 --- a/innobase/sync/sync0rw.c +++ b/innobase/sync/sync0rw.c @@ -223,7 +223,7 @@ lock_loop: if (srv_print_latch_waits) { printf( "Thread %lu spin wait rw-s-lock at %lx cfile %s cline %lu rnds %lu\n", - os_thread_get_curr_id(), (ulint)lock, + os_thread_pf(os_thread_get_curr_id()), (ulint)lock, lock->cfile_name, lock->cline, i); } @@ -253,7 +253,7 @@ lock_loop: if (srv_print_latch_waits) { printf( "Thread %lu OS wait rw-s-lock at %lx cfile %s cline %lu\n", - os_thread_get_curr_id(), (ulint)lock, + os_thread_pf(os_thread_get_curr_id()), (ulint)lock, lock->cfile_name, lock->cline); } @@ -343,7 +343,8 @@ rw_lock_x_lock_low( } } else if ((rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX) - && (lock->writer_thread == os_thread_get_curr_id())) { + && os_thread_eq(lock->writer_thread, + os_thread_get_curr_id())) { if (rw_lock_get_reader_count(lock) == 0) { @@ -368,7 +369,8 @@ rw_lock_x_lock_low( return(RW_LOCK_WAIT_EX); } else if ((rw_lock_get_writer(lock) == RW_LOCK_EX) - && (lock->writer_thread == os_thread_get_curr_id()) + && os_thread_eq(lock->writer_thread, + os_thread_get_curr_id()) && (lock->pass == 0) && (pass == 0)) { @@ -469,7 +471,7 @@ lock_loop: if (srv_print_latch_waits) { printf( "Thread %lu spin wait rw-x-lock at %lx cfile %s cline %lu rnds %lu\n", - os_thread_get_curr_id(), (ulint)lock, + os_thread_pf(os_thread_get_curr_id()), (ulint)lock, lock->cfile_name, lock->cline, i); } @@ -502,8 +504,8 @@ lock_loop: if (srv_print_latch_waits) { printf( "Thread %lu OS wait for rw-x-lock at %lx cfile %s cline %lu\n", - os_thread_get_curr_id(), (ulint)lock, lock->cfile_name, - lock->cline); + os_thread_pf(os_thread_get_curr_id()), (ulint)lock, + lock->cfile_name, lock->cline); } rw_x_system_call_count++; @@ -621,7 +623,8 @@ rw_lock_remove_debug_info( while (info != NULL) { if ((pass == info->pass) && ((pass != 0) - || (info->thread_id == os_thread_get_curr_id())) + || os_thread_eq(info->thread_id, + os_thread_get_curr_id())) && (info->lock_type == lock_type)) { /* Found! */ @@ -676,7 +679,7 @@ rw_lock_own( while (info != NULL) { - if ((info->thread_id == os_thread_get_curr_id()) + if (os_thread_eq(info->thread_id, os_thread_get_curr_id()) && (info->pass == 0) && (info->lock_type == lock_type)) { @@ -834,7 +837,7 @@ rw_lock_debug_print( rwt = info->lock_type; printf("Locked: thread %ld file %s line %ld ", - info->thread_id, info->file_name, info->line); + os_thread_pf(info->thread_id), info->file_name, info->line); if (rwt == RW_LOCK_SHARED) { printf("S-LOCK"); } else if (rwt == RW_LOCK_EX) { diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c index c070e97f692..61bd8e587e6 100644 --- a/innobase/sync/sync0sync.c +++ b/innobase/sync/sync0sync.c @@ -230,7 +230,6 @@ mutex_create_func( mutex->magic_n = MUTEX_MAGIC_N; mutex->line = 0; mutex->file_name = "not yet reserved"; - mutex->thread_id = ULINT_UNDEFINED; mutex->level = SYNC_LEVEL_NONE; mutex->cfile_name = cfile_name; mutex->cline = cline; @@ -392,8 +391,8 @@ spin_loop: if (srv_print_latch_waits) { printf( "Thread %lu spin wait mutex at %lx cfile %s cline %lu rnds %lu\n", - os_thread_get_curr_id(), (ulint)mutex, mutex->cfile_name, - mutex->cline, i); + os_thread_pf(os_thread_get_curr_id()), (ulint)mutex, + mutex->cfile_name, mutex->cline, i); } mutex_spin_round_count += i; @@ -458,7 +457,7 @@ spin_loop: if (srv_print_latch_waits) { printf( "Thread %lu spin wait succeeds at 2: mutex at %lx\n", - os_thread_get_curr_id(), (ulint)mutex); + os_thread_pf(os_thread_get_curr_id()), (ulint)mutex); } return; @@ -476,8 +475,8 @@ spin_loop: if (srv_print_latch_waits) { printf( "Thread %lu OS wait mutex at %lx cfile %s cline %lu rnds %lu\n", - os_thread_get_curr_id(), (ulint)mutex, mutex->cfile_name, - mutex->cline, i); + os_thread_pf(os_thread_get_curr_id()), (ulint)mutex, + mutex->cfile_name, mutex->cline, i); } mutex_system_call_count++; @@ -572,7 +571,7 @@ mutex_own( return(FALSE); } - if (mutex->thread_id != os_thread_get_curr_id()) { + if (!os_thread_eq(mutex->thread_id, os_thread_get_curr_id())) { return(FALSE); } @@ -611,7 +610,8 @@ mutex_list_print_info(void) &thread_id); printf( "Locked mutex: addr %lx thread %ld file %s line %ld\n", - (ulint)mutex, thread_id, file_name, line); + (ulint)mutex, os_thread_pf(thread_id), + file_name, line); } mutex = UT_LIST_GET_NEXT(list, mutex); @@ -716,7 +716,7 @@ sync_thread_level_arrays_find_slot(void) slot = sync_thread_level_arrays_get_nth(i); - if (slot->levels && (slot->id == id)) { + if (slot->levels && os_thread_eq(slot->id, id)) { return(slot); } @@ -780,7 +780,7 @@ sync_thread_levels_g( { char* file_name; ulint line; - ulint thread_id; + os_thread_id_t thread_id; sync_level_t* slot; rw_lock_t* lock; mutex_t* mutex; @@ -810,7 +810,7 @@ sync_thread_levels_g( &file_name, &line, &thread_id); printf("InnoDB: Locked mutex: addr %lx thread %ld file %s line %ld\n", - (ulint)mutex, thread_id, + (ulint)mutex, os_thread_pf(thread_id), file_name, line); } else { printf("Not locked\n"); diff --git a/innobase/thr/thr0loc.c b/innobase/thr/thr0loc.c index d3d7a58d313..fbf3e3a1dad 100644 --- a/innobase/thr/thr0loc.c +++ b/innobase/thr/thr0loc.c @@ -69,8 +69,8 @@ try_again: local = NULL; - HASH_SEARCH(hash, thr_local_hash, os_thread_conv_id_to_ulint(id), - local, local->id == id); + HASH_SEARCH(hash, thr_local_hash, os_thread_pf(id), + local, os_thread_eq(local->id, id)); if (local == NULL) { mutex_exit(&thr_local_mutex); @@ -173,7 +173,7 @@ thr_local_create(void) mutex_enter(&thr_local_mutex); HASH_INSERT(thr_local_t, hash, thr_local_hash, - os_thread_conv_id_to_ulint(os_thread_get_curr_id()), + os_thread_pf(os_thread_get_curr_id()), local); mutex_exit(&thr_local_mutex); @@ -193,8 +193,8 @@ thr_local_free( /* Look for the local struct in the hash table */ - HASH_SEARCH(hash, thr_local_hash, os_thread_conv_id_to_ulint(id), - local, local->id == id); + HASH_SEARCH(hash, thr_local_hash, os_thread_pf(id), + local, os_thread_eq(local->id, id)); if (local == NULL) { mutex_exit(&thr_local_mutex); @@ -202,7 +202,7 @@ thr_local_free( } HASH_DELETE(thr_local_t, hash, thr_local_hash, - os_thread_conv_id_to_ulint(id), local); + os_thread_pf(id), local); mutex_exit(&thr_local_mutex); diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index 9c8bfc9f4db..48b1ecc59f2 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -1487,7 +1487,7 @@ trx_print( } buf += sprintf(buf, ", OS thread id %lu", - (ulint)trx->mysql_thread_id); + os_thread_pf(trx->mysql_thread_id)); if (ut_strlen(trx->op_info) > 0) { buf += sprintf(buf, " %s", trx->op_info); diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc index 81af4636ff2..07d3c814c1c 100644 --- a/sql/ha_innobase.cc +++ b/sql/ha_innobase.cc @@ -55,6 +55,7 @@ typedef byte mysql_byte; extern "C" { #include "../innobase/include/univ.i" #include "../innobase/include/os0file.h" +#include "../innobase/include/os0thread.h" #include "../innobase/include/srv0start.h" #include "../innobase/include/srv0srv.h" #include "../innobase/include/trx0roll.h" From d96d2e566570aa2852651618e89d3fbf36909f2f Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Aug 2002 21:57:32 +0300 Subject: [PATCH 29/30] Fix for a security flaw in database hash --- Docs/manual.texi | 2 ++ sql/sql_acl.cc | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Docs/manual.texi b/Docs/manual.texi index 52c1887a13e..806c5d34fe0 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -46928,6 +46928,8 @@ not yet 100% confident in this code. @appendixsubsec Changes in release 3.23.52 @itemize @bullet @item +Fixed a security bug with empty db column in db table +@item Changed initialisation of @code{RND()} to make it less predicatable. @item Fixed problem with @code{GROUP BY} on result with expression that created a diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index f0131023157..49baad63d4d 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -242,6 +242,8 @@ int acl_init(bool dont_read_acl_tables) ACL_DB db; update_hostname(&db.host,get_field(&mem, table,0)); db.db=get_field(&mem, table,1); + if (!db.db || !db.db[0]) + continue; db.user=get_field(&mem, table,2); db.access=get_access(table,3); db.access=fix_rights_for_db(db.access); From 40d3c3901b0427eba76119730f46784f946990b3 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Aug 2002 00:53:00 +0300 Subject: [PATCH 30/30] Better fix for problem with empty database names in the mysql.db table --- sql/sql_acl.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 49baad63d4d..233645d41e2 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -242,8 +242,11 @@ int acl_init(bool dont_read_acl_tables) ACL_DB db; update_hostname(&db.host,get_field(&mem, table,0)); db.db=get_field(&mem, table,1); - if (!db.db || !db.db[0]) + if (!db.db) + { + sql_print_error("Found an entry in the 'db' table with empty database name; Skipped"); continue; + } db.user=get_field(&mem, table,2); db.access=get_access(table,3); db.access=fix_rights_for_db(db.access);