Commit ab8ff0d6 authored by unknown's avatar unknown

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
parent 912911fe
...@@ -1707,10 +1707,11 @@ buf_print(void) ...@@ -1707,10 +1707,11 @@ buf_print(void)
mutex_enter(&(buf_pool->mutex)); 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("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); printf("n pending reads %lu \n", buf_pool->n_pend_reads);
...@@ -1819,13 +1820,20 @@ buf_print_io( ...@@ -1819,13 +1820,20 @@ buf_print_io(
mutex_enter(&(buf_pool->mutex)); mutex_enter(&(buf_pool->mutex));
buf += sprintf(buf, buf += sprintf(buf,
"Free list length %lu \n", UT_LIST_GET_LEN(buf_pool->free)); "Buffer pool size %lu\n", size);
buf += sprintf(buf,
"Free buffers %lu\n", UT_LIST_GET_LEN(buf_pool->free));
buf += sprintf(buf,
"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, buf += sprintf(buf,
"LRU list length %lu \n", UT_LIST_GET_LEN(buf_pool->LRU)); "Hash index buffers %lu\n", buf_pool->n_adaptive_hash_pages);
*/
buf += sprintf(buf, buf += sprintf(buf,
"Flush list length %lu \n", "Modified db pages %lu\n",
UT_LIST_GET_LEN(buf_pool->flush_list)); 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); buf += sprintf(buf, "Pending reads %lu \n", buf_pool->n_pend_reads);
......
...@@ -270,7 +270,7 @@ void ...@@ -270,7 +270,7 @@ void
dict_table_autoinc_initialize( dict_table_autoinc_initialize(
/*==========================*/ /*==========================*/
dict_table_t* table, /* in: table */ 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)); mutex_enter(&(table->autoinc_mutex));
...@@ -281,8 +281,8 @@ dict_table_autoinc_initialize( ...@@ -281,8 +281,8 @@ dict_table_autoinc_initialize(
} }
/************************************************************************ /************************************************************************
Gets the next autoinc value, 0 if not yet initialized. If initialized, Gets the next autoinc value (== autoinc counter value), 0 if not yet
increments the counter by 1. */ initialized. If initialized, increments the counter by 1. */
ib_longlong ib_longlong
dict_table_autoinc_get( dict_table_autoinc_get(
...@@ -298,8 +298,8 @@ dict_table_autoinc_get( ...@@ -298,8 +298,8 @@ dict_table_autoinc_get(
value = 0; value = 0;
} else { } else {
table->autoinc = table->autoinc + 1;
value = table->autoinc; value = table->autoinc;
table->autoinc = table->autoinc + 1;
} }
mutex_exit(&(table->autoinc_mutex)); mutex_exit(&(table->autoinc_mutex));
...@@ -334,20 +334,43 @@ dict_table_autoinc_read( ...@@ -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. */ current value. If not inited, does nothing. */
void void
dict_table_autoinc_update( dict_table_autoinc_update(
/*======================*/ /*======================*/
dict_table_t* table, /* in: table */ dict_table_t* table, /* in: table */
ib_longlong value) /* in: value which was assigned to a row */ ib_longlong value) /* in: value which was assigned to a row */
{ {
mutex_enter(&(table->autoinc_mutex)); mutex_enter(&(table->autoinc_mutex));
if (table->autoinc_inited) { if (table->autoinc_inited) {
if (value > table->autoinc) { if (value >= table->autoinc) {
table->autoinc = value; table->autoinc = value + 1;
} }
} }
......
...@@ -578,7 +578,7 @@ fil_read_flushed_lsn_and_arch_log_no( ...@@ -578,7 +578,7 @@ fil_read_flushed_lsn_and_arch_log_no(
ulint arch_log_no; ulint arch_log_no;
buf2 = ut_malloc(2 * UNIV_PAGE_SIZE); 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); buf = ut_align(buf2, UNIV_PAGE_SIZE);
os_file_read(data_file, buf, 0, 0, UNIV_PAGE_SIZE); os_file_read(data_file, buf, 0, 0, UNIV_PAGE_SIZE);
......
...@@ -933,6 +933,36 @@ fsp_header_get_free_limit( ...@@ -933,6 +933,36 @@ fsp_header_get_free_limit(
return(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. */ Tries to extend the last data file file if it is defined as auto-extending. */
static static
......
...@@ -335,6 +335,11 @@ ha_print_info( ...@@ -335,6 +335,11 @@ ha_print_info(
} }
} }
buf += sprintf(buf, "Hash table size %lu, used cells %lu\n", buf += sprintf(buf,
hash_get_n_cells(table), cells); "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));
}
} }
...@@ -96,17 +96,17 @@ dict_col_get_clust_pos( ...@@ -96,17 +96,17 @@ dict_col_get_clust_pos(
/*===================*/ /*===================*/
dict_col_t* col); 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. */ initialized counter. */
void void
dict_table_autoinc_initialize( dict_table_autoinc_initialize(
/*==========================*/ /*==========================*/
dict_table_t* table, /* in: table */ 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, Gets the next autoinc value (== autoinc counter value), 0 if not yet
increments the counter by 1. */ initialized. If initialized, increments the counter by 1. */
ib_longlong ib_longlong
dict_table_autoinc_get( dict_table_autoinc_get(
...@@ -123,12 +123,22 @@ dict_table_autoinc_read( ...@@ -123,12 +123,22 @@ dict_table_autoinc_read(
/* out: value of the counter */ /* out: value of the counter */
dict_table_t* table); /* in: table */ 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. */ current value. If not inited, does nothing. */
void void
dict_table_autoinc_update( dict_table_autoinc_update(
/*======================*/ /*======================*/
dict_table_t* table, /* in: table */ dict_table_t* table, /* in: table */
ib_longlong value); /* in: value which was assigned to a row */ ib_longlong value); /* in: value which was assigned to a row */
/************************************************************************** /**************************************************************************
......
...@@ -388,8 +388,8 @@ struct dict_table_struct{ ...@@ -388,8 +388,8 @@ struct dict_table_struct{
/* TRUE if the autoinc counter has been /* TRUE if the autoinc counter has been
inited; MySQL gets the init value by executing inited; MySQL gets the init value by executing
SELECT MAX(auto inc column) */ SELECT MAX(auto inc column) */
ib_longlong autoinc;/* autoinc counter value already given to ib_longlong autoinc;/* autoinc counter value to give to the
a row */ next inserted row */
ulint magic_n;/* magic number */ ulint magic_n;/* magic number */
}; };
#define DICT_TABLE_MAGIC_N 76333786 #define DICT_TABLE_MAGIC_N 76333786
......
...@@ -17,7 +17,9 @@ typedef struct dyn_block_struct dyn_block_t; ...@@ -17,7 +17,9 @@ typedef struct dyn_block_struct dyn_block_t;
typedef dyn_block_t dyn_array_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 #define DYN_ARRAY_DATA_SIZE 512
/************************************************************************* /*************************************************************************
......
...@@ -57,6 +57,16 @@ fsp_header_get_free_limit( ...@@ -57,6 +57,16 @@ fsp_header_get_free_limit(
/* out: free limit in megabytes */ /* out: free limit in megabytes */
ulint space); /* in: space id */ 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. */ Initializes the space header of a new created space. */
void void
......
...@@ -431,15 +431,30 @@ log_block_set_data_len( ...@@ -431,15 +431,30 @@ log_block_set_data_len(
byte* log_block, /* in: log block */ byte* log_block, /* in: log block */
ulint len); /* in: data length */ ulint len); /* in: data length */
/**************************************************************** /****************************************************************
Gets a log block number stored in the trailer. */ Calculates the checksum for a log block. */
UNIV_INLINE UNIV_INLINE
ulint ulint
log_block_get_trl_no( log_block_calc_checksum(
/*=================*/ /*====================*/
/* out: log block number stored in the block /* out: checksum */
trailer */ 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 */ 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. */ Gets a log block first mtr log record group offset. */
UNIV_INLINE UNIV_INLINE
ulint ulint
...@@ -544,10 +559,11 @@ extern log_t* log_sys; ...@@ -544,10 +559,11 @@ extern log_t* log_sys;
bytes */ bytes */
/* Offsets of a log block trailer from the end of the block */ /* Offsets of a log block trailer from the end of the block */
#define LOG_BLOCK_TRL_CHECKSUM 4 /* 1 byte checksum of the log block #define LOG_BLOCK_CHECKSUM 4 /* 4 byte checksum of the log block
contents */ contents; in InnoDB versions
#define LOG_BLOCK_TRL_NO 3 /* 3 lowest bytes of the log block < 3.23.52 this did not contain the
number */ checksum but the same value as
.._HDR_NO */
#define LOG_BLOCK_TRL_SIZE 4 /* trailer size in bytes */ #define LOG_BLOCK_TRL_SIZE 4 /* trailer size in bytes */
/* Offsets for a checkpoint field */ /* Offsets for a checkpoint field */
......
...@@ -169,33 +169,6 @@ log_block_set_checkpoint_no( ...@@ -169,33 +169,6 @@ log_block_set_checkpoint_no(
ut_dulint_get_low(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. */ Converts a lsn to a log block number. */
UNIV_INLINE UNIV_INLINE
...@@ -216,6 +189,61 @@ log_block_convert_lsn_to_no( ...@@ -216,6 +189,61 @@ log_block_convert_lsn_to_no(
return(no + 1); 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. */ Initializes a log block in the log buffer. */
UNIV_INLINE UNIV_INLINE
...@@ -232,7 +260,6 @@ log_block_init( ...@@ -232,7 +260,6 @@ log_block_init(
no = log_block_convert_lsn_to_no(lsn); no = log_block_convert_lsn_to_no(lsn);
log_block_set_hdr_no(log_block, no); 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_data_len(log_block, LOG_BLOCK_HDR_SIZE);
log_block_set_first_rec_group(log_block, 0); log_block_set_first_rec_group(log_block, 0);
...@@ -256,7 +283,7 @@ log_block_init_in_old_format( ...@@ -256,7 +283,7 @@ log_block_init_in_old_format(
log_block_set_hdr_no(log_block, no); log_block_set_hdr_no(log_block, no);
mach_write_to_4(log_block + OS_FILE_LOG_BLOCK_SIZE 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_data_len(log_block, LOG_BLOCK_HDR_SIZE);
log_block_set_first_rec_group(log_block, 0); log_block_set_first_rec_group(log_block, 0);
} }
......
...@@ -313,6 +313,10 @@ struct recv_sys_struct{ ...@@ -313,6 +313,10 @@ struct recv_sys_struct{
this lsn */ this lsn */
dulint limit_lsn;/* recovery should be made at most up to this dulint limit_lsn;/* recovery should be made at most up to this
lsn */ 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; log_group_t* archive_group;
/* in archive recovery: the log group whose /* in archive recovery: the log group whose
archive is read */ archive is read */
...@@ -328,6 +332,8 @@ extern ibool recv_recovery_on; ...@@ -328,6 +332,8 @@ extern ibool recv_recovery_on;
extern ibool recv_no_ibuf_operations; extern ibool recv_no_ibuf_operations;
extern ibool recv_needed_recovery; extern ibool recv_needed_recovery;
extern ibool recv_is_making_a_backup;
/* Size of the parsing buffer; it must accommodate RECV_SCAN_SIZE many /* Size of the parsing buffer; it must accommodate RECV_SCAN_SIZE many
times! */ times! */
#define RECV_PARSING_BUF_SIZE (2 * 1024 * 1024) #define RECV_PARSING_BUF_SIZE (2 * 1024 * 1024)
......
...@@ -257,6 +257,15 @@ void ...@@ -257,6 +257,15 @@ void
trx_sys_print_mysql_binlog_offset(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 Prints to stderr the MySQL master log offset info in the trx system header if
the magic number shows it valid. */ the magic number shows it valid. */
...@@ -300,11 +309,11 @@ therefore 256; each slot is currently 8 bytes in size */ ...@@ -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_NAME_LEN 512
#define TRX_SYS_MYSQL_LOG_MAGIC_N 873422344 #define TRX_SYS_MYSQL_LOG_MAGIC_N 873422344
/* The offset of the MySQL replication info on the trx system header page; /* The offset of the MySQL replication info in the trx system header;
this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */ this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */
#define TRX_SYS_MYSQL_MASTER_LOG_INFO (UNIV_PAGE_SIZE - 2000) #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_INFO (UNIV_PAGE_SIZE - 1000)
#define TRX_SYS_MYSQL_LOG_MAGIC_N_FLD 0 /* magic number which shows #define TRX_SYS_MYSQL_LOG_MAGIC_N_FLD 0 /* magic number which shows
if we have valid data in the if we have valid data in the
......
...@@ -309,6 +309,9 @@ struct trx_struct{ ...@@ -309,6 +309,9 @@ struct trx_struct{
of view of concurrency control: of view of concurrency control:
TRX_ACTIVE, TRX_COMMITTED_IN_MEMORY, 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 ibool check_foreigns; /* normally TRUE, but if the user
wants to suppress foreign key checks, wants to suppress foreign key checks,
(in table imports, for example) we (in table imports, for example) we
...@@ -468,6 +471,7 @@ struct trx_struct{ ...@@ -468,6 +471,7 @@ struct trx_struct{
TRX_QUE_LOCK_WAIT, this points to TRX_QUE_LOCK_WAIT, this points to
the lock request, otherwise this is the lock request, otherwise this is
NULL */ NULL */
time_t wait_started; /* lock wait started at this time */
UT_LIST_BASE_NODE_T(que_thr_t) UT_LIST_BASE_NODE_T(que_thr_t)
wait_thrs; /* query threads belonging to this wait_thrs; /* query threads belonging to this
trx that are in the QUE_THR_LOCK_WAIT trx that are in the QUE_THR_LOCK_WAIT
......
...@@ -1565,6 +1565,7 @@ index->table_name); ...@@ -1565,6 +1565,7 @@ index->table_name);
} }
trx->que_state = TRX_QUE_LOCK_WAIT; trx->que_state = TRX_QUE_LOCK_WAIT;
trx->wait_started = time(NULL);
ut_a(que_thr_stop(thr)); ut_a(que_thr_stop(thr));
...@@ -2961,6 +2962,7 @@ table->name); ...@@ -2961,6 +2962,7 @@ table->name);
} }
trx->que_state = TRX_QUE_LOCK_WAIT; trx->que_state = TRX_QUE_LOCK_WAIT;
trx->wait_started = time(NULL);
ut_a(que_thr_stop(thr)); ut_a(que_thr_stop(thr));
...@@ -3503,6 +3505,10 @@ lock_print_info( ...@@ -3503,6 +3505,10 @@ lock_print_info(
return; 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", buf += sprintf(buf, "Trx id counter %lu %lu\n",
ut_dulint_get_high(trx_sys->max_trx_id), ut_dulint_get_high(trx_sys->max_trx_id),
ut_dulint_get_low(trx_sys->max_trx_id)); ut_dulint_get_low(trx_sys->max_trx_id));
...@@ -3587,7 +3593,8 @@ lock_print_info( ...@@ -3587,7 +3593,8 @@ lock_print_info(
if (trx->que_state == TRX_QUE_LOCK_WAIT) { if (trx->que_state == TRX_QUE_LOCK_WAIT) {
buf += sprintf(buf, 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) { if (lock_get_type(trx->wait_lock) == LOCK_REC) {
lock_rec_print(buf, trx->wait_lock); lock_rec_print(buf, trx->wait_lock);
......
...@@ -270,7 +270,7 @@ log_write_low( ...@@ -270,7 +270,7 @@ log_write_low(
log->lsn = ut_dulint_add(log->lsn, len); 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); log_block_init(log_block + OS_FILE_LOG_BLOCK_SIZE, log->lsn);
} else { } else {
log->lsn = ut_dulint_add(log->lsn, len); log->lsn = ut_dulint_add(log->lsn, len);
...@@ -1070,28 +1070,16 @@ log_group_file_header_flush( ...@@ -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 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 check the consistency of a log block. */
bits of 1 + the sum of the bytes in the log block except the trailer bytes. */
static static
void void
log_block_store_checksum( log_block_store_checksum(
/*=====================*/ /*=====================*/
byte* block) /* in/out: pointer to a log block */ byte* block) /* in/out: pointer to a log block */
{ {
ulint i; log_block_set_checksum(block, log_block_calc_checksum(block));
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);
} }
/********************************************************** /**********************************************************
......
...@@ -63,7 +63,7 @@ log scan */ ...@@ -63,7 +63,7 @@ log scan */
ulint recv_scan_print_counter = 0; ulint recv_scan_print_counter = 0;
ibool recv_is_from_backup = FALSE; ibool recv_is_from_backup = FALSE;
ibool recv_is_making_a_backup = FALSE;
/************************************************************ /************************************************************
Creates the recovery system. */ Creates the recovery system. */
...@@ -124,6 +124,8 @@ recv_sys_init( ...@@ -124,6 +124,8 @@ recv_sys_init(
recv_sys->last_block = ut_align(recv_sys->last_block_buf_start, recv_sys->last_block = ut_align(recv_sys->last_block_buf_start,
OS_FILE_LOG_BLOCK_SIZE); OS_FILE_LOG_BLOCK_SIZE);
recv_sys->found_corrupt_log = FALSE;
mutex_exit(&(recv_sys->mutex)); mutex_exit(&(recv_sys->mutex));
} }
...@@ -569,9 +571,9 @@ recv_read_cp_info_for_backup( ...@@ -569,9 +571,9 @@ recv_read_cp_info_for_backup(
} }
/********************************************************** /**********************************************************
Checks the 1-byte checksum to the trailer checksum field of a log block. Checks the 4-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 We also accept a log block in the old format < InnoDB-3.23.52 where the
contained the highest byte of the log block number. */ checksum field contains the log block number. */
static static
ibool ibool
log_block_checksum_is_ok_or_old_format( log_block_checksum_is_ok_or_old_format(
...@@ -580,29 +582,12 @@ 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 */ format of InnoDB version < 3.23.52 */
byte* block) /* in: pointer to a log block */ byte* block) /* in: pointer to a log block */
{ {
ulint i; if (log_block_calc_checksum(block) == log_block_get_checksum(block)) {
ulint sum;
sum = 1;
for (i = 0; i < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE; i++) {
sum += (ulint)(*(block + i));
}
/* printf("Checksum %lu, byte %lu\n", 0xFF & sum,
mach_read_from_1(block + OS_FILE_LOG_BLOCK_SIZE
- LOG_BLOCK_TRL_CHECKSUM));
*/
if (mach_read_from_1(block + OS_FILE_LOG_BLOCK_SIZE
- LOG_BLOCK_TRL_CHECKSUM)
== (0xFF & sum)) {
return(TRUE); return(TRUE);
} }
if (((0xFF000000 & log_block_get_hdr_no(block)) >> 24) if (log_block_get_hdr_no(block) == log_block_get_checksum(block)) {
== mach_read_from_1(block + OS_FILE_LOG_BLOCK_SIZE
- LOG_BLOCK_TRL_CHECKSUM)) {
/* We assume the log block is in the format of /* We assume the log block is in the format of
InnoDB version < 3.23.52 and the block is ok */ InnoDB version < 3.23.52 and the block is ok */
...@@ -649,23 +634,20 @@ recv_scan_log_seg_for_backup( ...@@ -649,23 +634,20 @@ recv_scan_log_seg_for_backup(
/* fprintf(stderr, "Log block header no %lu\n", no); */ /* fprintf(stderr, "Log block header no %lu\n", no); */
if ((no & 0xFFFFFF) != log_block_get_trl_no(log_block) if (no != log_block_convert_lsn_to_no(*scanned_lsn)
|| no != log_block_convert_lsn_to_no(*scanned_lsn)
|| !log_block_checksum_is_ok_or_old_format(log_block)) { || !log_block_checksum_is_ok_or_old_format(log_block)) {
/* /*
printf( printf(
"Log block n:o %lu, trailer n:o %lu, scanned lsn n:o %lu\n", "Log block n:o %lu, scanned lsn n:o %lu\n",
no, log_block_get_trl_no(log_block), no, log_block_convert_lsn_to_no(*scanned_lsn));
log_block_convert_lsn_to_no(*scanned_lsn));
*/ */
/* Garbage or an incompletely written log block */ /* Garbage or an incompletely written log block */
log_block += OS_FILE_LOG_BLOCK_SIZE; log_block += OS_FILE_LOG_BLOCK_SIZE;
/* /*
printf( printf(
"Next log block n:o %lu, trailer n:o %lu\n", "Next log block n:o %lu\n",
log_block_get_hdr_no(log_block), log_block_get_hdr_no(log_block));
log_block_get_trl_no(log_block));
*/ */
break; break;
} }
...@@ -713,7 +695,7 @@ byte* ...@@ -713,7 +695,7 @@ byte*
recv_parse_or_apply_log_rec_body( recv_parse_or_apply_log_rec_body(
/*=============================*/ /*=============================*/
/* out: log record end, NULL if not a complete /* out: log record end, NULL if not a complete
record */ record, or a corrupt record */
byte type, /* in: type */ byte type, /* in: type */
byte* ptr, /* in: pointer to a buffer */ byte* ptr, /* in: pointer to a buffer */
byte* end_ptr,/* in: pointer to the buffer end */ byte* end_ptr,/* in: pointer to the buffer end */
...@@ -794,8 +776,11 @@ recv_parse_or_apply_log_rec_body( ...@@ -794,8 +776,11 @@ recv_parse_or_apply_log_rec_body(
"InnoDB: is possible that the log scan did not proceed\n" "InnoDB: is possible that the log scan did not proceed\n"
"InnoDB: far enough in recovery. Please run CHECK TABLE\n" "InnoDB: far enough in recovery. Please run CHECK TABLE\n"
"InnoDB: on your InnoDB tables to check that they are ok!\n" "InnoDB: on your InnoDB tables to check that they are ok!\n"
"InnoDB: Corrupt log record type %lu\n", "InnoDB: Corrupt log record type %lu\n, lsn %lu %lu\n",
(ulint)type); (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); ut_ad(!page || new_ptr);
...@@ -1399,17 +1384,29 @@ recv_apply_log_recs_for_backup( ...@@ -1399,17 +1384,29 @@ recv_apply_log_recs_for_backup(
OS_FILE_OPEN, OS_FILE_OPEN,
OS_FILE_READ_WRITE, OS_FILE_READ_WRITE,
&success); &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); recv_addr = recv_get_fil_addr_struct(0, i);
if (recv_addr != NULL) { 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) (nth_page_in_file << UNIV_PAGE_SIZE_SHIFT)
& 0xFFFFFFFF, & 0xFFFFFFFF,
nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT), nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT),
UNIV_PAGE_SIZE); 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, /* We simulate a page read made by the buffer pool,
to make sure recovery works ok. We must init the to make sure recovery works ok. We must init the
...@@ -1425,12 +1422,19 @@ recv_apply_log_recs_for_backup( ...@@ -1425,12 +1422,19 @@ recv_apply_log_recs_for_backup(
mach_read_from_8(page + FIL_PAGE_LSN), mach_read_from_8(page + FIL_PAGE_LSN),
0, i); 0, i);
os_file_write(data_files[nth_file], success = os_file_write(data_files[nth_file],
data_file, page, data_file, page,
(nth_page_in_file << UNIV_PAGE_SIZE_SHIFT) (nth_page_in_file << UNIV_PAGE_SIZE_SHIFT)
& 0xFFFFFFFF, & 0xFFFFFFFF,
nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT), nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT),
UNIV_PAGE_SIZE); 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 if ((100 * i) / n_pages_total
...@@ -1647,7 +1651,7 @@ ulint ...@@ -1647,7 +1651,7 @@ ulint
recv_parse_log_rec( recv_parse_log_rec(
/*===============*/ /*===============*/
/* out: length of the record, or 0 if the record was /* 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* ptr, /* in: pointer to a buffer */
byte* end_ptr,/* in: pointer to the buffer end */ byte* end_ptr,/* in: pointer to the buffer end */
byte* type, /* out: type */ byte* type, /* out: type */
...@@ -1679,16 +1683,8 @@ recv_parse_log_rec( ...@@ -1679,16 +1683,8 @@ recv_parse_log_rec(
new_ptr = mlog_parse_initial_log_record(ptr, end_ptr, type, space, new_ptr = mlog_parse_initial_log_record(ptr, end_ptr, type, space,
page_no); 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) { if (!new_ptr) {
return(0); return(0);
} }
...@@ -1701,7 +1697,12 @@ recv_parse_log_rec( ...@@ -1701,7 +1697,12 @@ recv_parse_log_rec(
"InnoDB: far enough in recovery. Please run CHECK TABLE\n" "InnoDB: far enough in recovery. Please run CHECK TABLE\n"
"InnoDB: on your InnoDB tables to check that they are ok!\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: Corrupt log record type %lu, space id %lu, page no %lu\n",
(ulint)(*type), *space, *page_no); "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); return(0);
} }
...@@ -1790,6 +1791,7 @@ recv_parse_log_recs( ...@@ -1790,6 +1791,7 @@ recv_parse_log_recs(
ulint page_no; ulint page_no;
byte* body; byte* body;
ulint n_recs; ulint n_recs;
char err_buf[2500];
ut_ad(mutex_own(&(log_sys->mutex))); ut_ad(mutex_own(&(log_sys->mutex)));
ut_ad(!ut_dulint_is_zero(recv_sys->parse_start_lsn)); ut_ad(!ut_dulint_is_zero(recv_sys->parse_start_lsn));
...@@ -1813,6 +1815,17 @@ recv_parse_log_recs( ...@@ -1813,6 +1815,17 @@ recv_parse_log_recs(
len = recv_parse_log_rec(ptr, end_ptr, &type, &space, len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
&page_no, &body); &page_no, &body);
if (len == 0) { 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); return(FALSE);
} }
...@@ -1851,9 +1864,10 @@ recv_parse_log_recs( ...@@ -1851,9 +1864,10 @@ recv_parse_log_recs(
#ifdef UNIV_LOG_DEBUG #ifdef UNIV_LOG_DEBUG
recv_check_incomplete_log_recs(ptr, len); recv_check_incomplete_log_recs(ptr, len);
#endif #endif
recv_update_replicate(type, space, page_no, body, /* recv_update_replicate(type, space, page_no, body,
ptr + len); ptr + len);
recv_compare_replicate(space, page_no); recv_compare_replicate(space, page_no);
*/
} }
} else { } else {
/* Check that all the records associated with the single mtr /* Check that all the records associated with the single mtr
...@@ -1867,6 +1881,17 @@ recv_parse_log_recs( ...@@ -1867,6 +1881,17 @@ recv_parse_log_recs(
&page_no, &body); &page_no, &body);
if (len == 0) { 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); return(FALSE);
} }
...@@ -1876,8 +1901,10 @@ recv_parse_log_recs( ...@@ -1876,8 +1901,10 @@ recv_parse_log_recs(
#ifdef UNIV_LOG_DEBUG #ifdef UNIV_LOG_DEBUG
recv_check_incomplete_log_recs(ptr, len); recv_check_incomplete_log_recs(ptr, len);
#endif #endif
/*
recv_update_replicate(type, space, page_no, recv_update_replicate(type, space, page_no,
body, ptr + len); body, ptr + len);
*/
} }
if (log_debug_writes) { if (log_debug_writes) {
...@@ -1941,7 +1968,7 @@ recv_parse_log_recs( ...@@ -1941,7 +1968,7 @@ recv_parse_log_recs(
page has become identical with the original page has become identical with the original
page */ page */
recv_compare_replicate(space, page_no); /* recv_compare_replicate(space, page_no); */
} }
ptr += len; ptr += len;
...@@ -2095,32 +2122,19 @@ recv_scan_log_recs( ...@@ -2095,32 +2122,19 @@ recv_scan_log_recs(
/* fprintf(stderr, "Log block header no %lu\n", no); */ /* fprintf(stderr, "Log block header no %lu\n", no); */
if ((no & 0xFFFFFF) != log_block_get_trl_no(log_block) if (no != log_block_convert_lsn_to_no(scanned_lsn)
|| no != log_block_convert_lsn_to_no(scanned_lsn)
|| !log_block_checksum_is_ok_or_old_format(log_block)) { || !log_block_checksum_is_ok_or_old_format(log_block)) {
if ((no & 0xFFFFFF) == log_block_get_trl_no(log_block) if (no == log_block_convert_lsn_to_no(scanned_lsn)
&& no == log_block_convert_lsn_to_no(scanned_lsn)
&& !log_block_checksum_is_ok_or_old_format( && !log_block_checksum_is_ok_or_old_format(
log_block)) { log_block)) {
fprintf(stderr, fprintf(stderr,
"InnoDB: Log block no %lu at lsn %lu %lu has\n" "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), no, ut_dulint_get_high(scanned_lsn),
ut_dulint_get_low(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 */ /* Garbage or an incompletely written log block */
...@@ -2213,7 +2227,8 @@ recv_scan_log_recs( ...@@ -2213,7 +2227,8 @@ recv_scan_log_recs(
*group_scanned_lsn = scanned_lsn; *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++; recv_scan_print_counter++;
if (finished || (recv_scan_print_counter % 80 == 0)) { if (finished || (recv_scan_print_counter % 80 == 0)) {
......
...@@ -666,7 +666,7 @@ mem_print_info_low( ...@@ -666,7 +666,7 @@ mem_print_info_low(
mem_pool_print_info(outfile, mem_comm_pool); mem_pool_print_info(outfile, mem_comm_pool);
mem_validate(); /* mem_validate(); */
/* fclose(outfile); */ /* fclose(outfile); */
#endif #endif
......
...@@ -595,6 +595,11 @@ row_lock_table_autoinc_for_mysql( ...@@ -595,6 +595,11 @@ row_lock_table_autoinc_for_mysql(
ut_ad(trx); ut_ad(trx);
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); 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"; trx->op_info = "setting auto-inc lock";
if (node == NULL) { if (node == NULL) {
......
...@@ -2475,12 +2475,23 @@ srv_error_monitor_thread( ...@@ -2475,12 +2475,23 @@ srv_error_monitor_thread(
void* arg) /* in: a dummy parameter required by void* arg) /* in: a dummy parameter required by
os_thread_create */ os_thread_create */
{ {
ulint cnt = 0;
UT_NOT_USED(arg); UT_NOT_USED(arg);
loop: loop:
srv_error_monitor_active = TRUE; 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(); sync_array_print_long_waits();
/* Flush stdout and stderr so that a database user gets their output /* Flush stdout and stderr so that a database user gets their output
......
...@@ -927,6 +927,8 @@ innobase_start_or_create_for_mysql(void) ...@@ -927,6 +927,8 @@ innobase_start_or_create_for_mysql(void)
ulint max_arch_log_no; ulint max_arch_log_no;
ibool start_archive; ibool start_archive;
ulint sum_of_new_sizes; ulint sum_of_new_sizes;
ulint sum_of_data_file_sizes;
ulint tablespace_size_in_header;
ulint err; ulint err;
ulint i; ulint i;
ulint k; ulint k;
...@@ -1325,6 +1327,32 @@ innobase_start_or_create_for_mysql(void) ...@@ -1325,6 +1327,32 @@ innobase_start_or_create_for_mysql(void)
SRV_MAX_N_IO_THREADS); SRV_MAX_N_IO_THREADS);
/* buf_debug_prints = TRUE; */ /* 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); ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Started\n"); fprintf(stderr, " InnoDB: Started\n");
......
...@@ -493,6 +493,34 @@ trx_sys_update_mysql_binlog_offset( ...@@ -493,6 +493,34 @@ trx_sys_update_mysql_binlog_offset(
MLOG_4BYTES, mtr); 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 Prints to stderr the MySQL binlog offset info in the trx system header if
the magic number shows it valid. */ the magic number shows it valid. */
......
...@@ -72,6 +72,7 @@ trx_create( ...@@ -72,6 +72,7 @@ trx_create(
trx->type = TRX_USER; trx->type = TRX_USER;
trx->conc_state = TRX_NOT_STARTED; trx->conc_state = TRX_NOT_STARTED;
trx->start_time = time(NULL);
trx->check_foreigns = TRUE; trx->check_foreigns = TRUE;
trx->check_unique_secondary = TRUE; trx->check_unique_secondary = TRUE;
...@@ -516,6 +517,7 @@ trx_start_low( ...@@ -516,6 +517,7 @@ trx_start_low(
if (trx->type == TRX_PURGE) { if (trx->type == TRX_PURGE) {
trx->id = ut_dulint_zero; trx->id = ut_dulint_zero;
trx->conc_state = TRX_ACTIVE; trx->conc_state = TRX_ACTIVE;
trx->start_time = time(NULL);
return(TRUE); return(TRUE);
} }
...@@ -539,6 +541,7 @@ trx_start_low( ...@@ -539,6 +541,7 @@ trx_start_low(
trx->rseg = rseg; trx->rseg = rseg;
trx->conc_state = TRX_ACTIVE; trx->conc_state = TRX_ACTIVE;
trx->start_time = time(NULL);
UT_LIST_ADD_FIRST(trx_list, trx_sys->trx_list, trx); UT_LIST_ADD_FIRST(trx_list, trx_sys->trx_list, trx);
...@@ -1465,9 +1468,25 @@ trx_print( ...@@ -1465,9 +1468,25 @@ trx_print(
500 bytes */ 500 bytes */
trx_t* trx) /* in: transaction */ 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_high(trx->id),
ut_dulint_get_low(trx->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); (ulint)trx->mysql_thread_id);
if (ut_strlen(trx->op_info) > 0) { if (ut_strlen(trx->op_info) > 0) {
...@@ -1478,32 +1497,28 @@ trx_print( ...@@ -1478,32 +1497,28 @@ trx_print(
buf += sprintf(buf, " purge trx"); buf += sprintf(buf, " purge trx");
} }
switch (trx->conc_state) { buf += sprintf(buf, "\n");
case TRX_NOT_STARTED: buf += sprintf(buf,
", not started"); break; start_of_line = buf;
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);
}
switch (trx->que_state) { switch (trx->que_state) {
case TRX_QUE_RUNNING: buf += sprintf(buf, case TRX_QUE_RUNNING: break;
", runs or sleeps"); break;
case TRX_QUE_LOCK_WAIT: buf += sprintf(buf, case TRX_QUE_LOCK_WAIT: buf += sprintf(buf,
", lock wait"); break; "LOCK WAIT "); break;
case TRX_QUE_ROLLING_BACK: buf += sprintf(buf, case TRX_QUE_ROLLING_BACK: buf += sprintf(buf,
", rolling back"); break; "ROLLING BACK "); break;
case TRX_QUE_COMMITTING: buf += sprintf(buf, case TRX_QUE_COMMITTING: buf += sprintf(buf,
", committing"); break; "COMMITTING "); break;
default: buf += sprintf(buf, " que state %lu", trx->que_state); default: buf += sprintf(buf, "que state %lu", trx->que_state);
} }
if (0 < UT_LIST_GET_LEN(trx->trx_locks)) { if (0 < UT_LIST_GET_LEN(trx->trx_locks) ||
buf += sprintf(buf, ", has %lu lock struct(s)", mem_heap_get_size(trx->lock_heap) > 400) {
UT_LIST_GET_LEN(trx->trx_locks));
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) { if (trx->has_search_latch) {
...@@ -1515,7 +1530,10 @@ trx_print( ...@@ -1515,7 +1530,10 @@ trx_print(
ut_dulint_get_low(trx->undo_no)); ut_dulint_get_low(trx->undo_no));
} }
if (buf != start_of_line) {
buf += sprintf(buf, "\n"); buf += sprintf(buf, "\n");
}
if (trx->mysql_thd != NULL) { if (trx->mysql_thd != NULL) {
innobase_mysql_print_thd(buf, trx->mysql_thd); innobase_mysql_print_thd(buf, trx->mysql_thd);
......
...@@ -266,10 +266,39 @@ innobase_mysql_print_thd( ...@@ -266,10 +266,39 @@ innobase_mysql_print_thd(
thd = (THD*) input_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 */ /* We can't use value of sprintf() as this is not portable */
buf+= my_sprintf(buf, buf+= my_sprintf(buf,
(buf, "MySQL thread id %lu, query id %lu", (buf, "MySQL thread id %lu",
thd->thread_id, thd->query_id)); thd->thread_id));
if (thd->host) if (thd->host)
{ {
*buf++=' '; *buf++=' ';
...@@ -296,10 +325,11 @@ innobase_mysql_print_thd( ...@@ -296,10 +325,11 @@ innobase_mysql_print_thd(
if (thd->query) if (thd->query)
{ {
*buf++=' '; *buf++='\n';
buf=strnmov(buf, thd->query, 150); buf=strnmov(buf, thd->query, 150);
} }
*buf='\n'; *buf='\n';
#endif
} }
} }
...@@ -1414,6 +1444,7 @@ ha_innobase::write_row( ...@@ -1414,6 +1444,7 @@ ha_innobase::write_row(
row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt; row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
int error; int error;
longlong auto_inc; longlong auto_inc;
longlong dummy;
DBUG_ENTER("ha_innobase::write_row"); DBUG_ENTER("ha_innobase::write_row");
...@@ -1437,6 +1468,30 @@ ha_innobase::write_row( ...@@ -1437,6 +1468,30 @@ ha_innobase::write_row(
/* This is the case where the table has an /* This is the case where the table has an
auto-increment column */ 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 /* Fetch the value the user possibly has set in the
autoincrement field */ autoincrement field */
...@@ -1469,10 +1524,9 @@ ha_innobase::write_row( ...@@ -1469,10 +1524,9 @@ ha_innobase::write_row(
} }
if (auto_inc != 0) { if (auto_inc != 0) {
/* This call will calculate the max of the /* This call will calculate the max of the current
current value and the value supplied by the user, if value and the value supplied by the user and
the auto_inc counter is already initialized update the counter accordingly */
for the table */
/* We have to use the transactional lock mechanism /* We have to use the transactional lock mechanism
on the auto-inc counter of the table to ensure on the auto-inc counter of the table to ensure
...@@ -1512,45 +1566,17 @@ ha_innobase::write_row( ...@@ -1512,45 +1566,17 @@ ha_innobase::write_row(
auto_inc = dict_table_autoinc_get(prebuilt->table); auto_inc = dict_table_autoinc_get(prebuilt->table);
srv_conc_exit_innodb(prebuilt->trx); srv_conc_exit_innodb(prebuilt->trx);
/* If auto_inc is now != 0 the autoinc counter /* We can give the new value for MySQL to place in
was already initialized for the table: we can give the field */
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;
} }
}
update_auto_increment(); /* This call of a handler.cc function places
user_thd->next_insert_id to the column value, if the column
if (auto_inc == 0) { value was not set by the user */
/* The autoinc counter for our table was not yet
initialized, initialize it now */
auto_inc = table->next_number_field->val_int(); update_auto_increment();
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 if (prebuilt->mysql_template == NULL
...@@ -3572,37 +3598,53 @@ ha_innobase::store_lock( ...@@ -3572,37 +3598,53 @@ ha_innobase::store_lock(
} }
/*********************************************************************** /***********************************************************************
Returns the next auto-increment column value for the table. write_row This function initializes the auto-inc counter if it has not been
normally fetches the value from the cache in the data dictionary. This initialized yet. This function does not change the value of the auto-inc
function in used by SHOW TABLE STATUS and when the first insert to the table counter if it already has been initialized. In parameter ret returns
is done after database startup. */ the value of the auto-inc counter. */
longlong int
ha_innobase::get_auto_increment() ha_innobase::innobase_read_and_init_auto_inc(
/*=============================*/ /*=========================================*/
/* out: the next auto-increment column value */ /* 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; row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
longlong nr; longlong auto_inc;
int error; int error;
ut_a(prebuilt);
ut_a(prebuilt->trx == ut_a(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid); (trx_t*) current_thd->transaction.all.innobase_tid);
ut_a(prebuilt->table);
/* Also SHOW TABLE STATUS calls this function. Previously, when we did auto_inc = dict_table_autoinc_read(prebuilt->table);
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. */
assert(prebuilt->table); if (auto_inc != 0) {
/* Already initialized */
*ret = auto_inc;
nr = dict_table_autoinc_read(prebuilt->table); return(0);
}
if (nr != 0) { srv_conc_enter_innodb(prebuilt->trx);
error = row_lock_table_autoinc_for_mysql(prebuilt);
srv_conc_exit_innodb(prebuilt->trx);
return(nr + 1); if (error != DB_SUCCESS) {
error = convert_error_code_to_mysql(error, user_thd);
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); (void) extra(HA_EXTRA_KEYREAD);
...@@ -3627,16 +3669,57 @@ ha_innobase::get_auto_increment() ...@@ -3627,16 +3669,57 @@ ha_innobase::get_auto_increment()
error = index_last(table->record[1]); error = index_last(table->record[1]);
if (error) { if (error) {
nr = 1; if (error == HA_ERR_END_OF_FILE) {
/* The table was empty, initialize to 1 */
auto_inc = 1;
error = 0;
} else { } else {
nr = (longlong) table->next_number_field-> /* Deadlock or a lock wait timeout */
auto_inc = -1;
goto func_exit;
}
} else {
/* Initialize to max(col) + 1 */
auto_inc = (longlong) table->next_number_field->
val_int_offset(table->rec_buff_length) + 1; val_int_offset(table->rec_buff_length) + 1;
} }
dict_table_autoinc_initialize(prebuilt->table, auto_inc);
func_exit:
(void) extra(HA_EXTRA_NO_KEYREAD); (void) extra(HA_EXTRA_NO_KEYREAD);
index_end(); index_end();
*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); return(nr);
} }
......
...@@ -68,6 +68,7 @@ class ha_innobase: public handler ...@@ -68,6 +68,7 @@ class ha_innobase: public handler
int update_thd(THD* thd); int update_thd(THD* thd);
int change_active_index(uint keynr); int change_active_index(uint keynr);
int general_fetch(byte* buf, uint direction, uint match_mode); int general_fetch(byte* buf, uint direction, uint match_mode);
int innobase_read_and_init_auto_inc(longlong* ret);
/* Init values for the class: */ /* Init values for the class: */
public: public:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment