Merge mysql.com:/home/pz/mysql/mysql-4.0-root

into mysql.com:/home/pz/mysql/mysql-4.0
This commit is contained in:
peter@mysql.com 2002-08-08 18:21:13 +04:00
commit 2440182b1e
79 changed files with 1631 additions and 542 deletions

View file

@ -3554,10 +3554,13 @@ string) in it instead. (This behaviour can, however, be changed with the
-DDONT_USE_DEFAULT_FIELDS compile option.)
@item
MySQL allows you to store some wrong date values into
@code{DATE} and @code{DATETIME} columns (like 2000-02-31 or 2000-02-00).
If the date is totally wrong, MySQL Server will store the special
0000-00-00 date value in the column.
MySQL allows you to store some wrong date values into @code{DATE} and
@code{DATETIME} columns (like 2000-02-31 or 2000-02-00). The idea is
that it's not the SQL server job to vaildate date. If MySQL can store a
date and retrieve exactly the same date, then MySQL will store the
date. If the date is totally wrong (outside of MySQL abilty to store
it), MySQL Server will store the special 0000-00-00 date value in the
column.
@item
If you set an @code{ENUM} column to an unsupported value, it will be set to
@ -8170,6 +8173,9 @@ Renamed mysqld startup options @code{--skip-locking} to
@code{--skip-external-locking} and @code{--enable-locking} to
@code{--external-locking}.
@item
mysqld now has the option @code{--temp-pool} enabled by default as this
gives better performance with some OS.
@item
@code{DOUBLE} and @code{FLOAT} columns now honour the
@code{UNSIGNED} flag on storage (before, @code{UNSIGNED} was ignored for
these columns).
@ -32555,6 +32561,31 @@ mysql> SELECT WEEK('1998-12-31',1);
Note: in Version 4.0, @code{WEEK(#,0)} was changed to match the
calendar in the USA.
Note that if a week is the last week of the previous year, MySQL will
return 0:
@example
mysql> SELECT YEAR('2000-01-01'), WEEK('2000-01-01',0);
-> 2000, 0
@end example
One could argue that MySQL should return @code{52} for the @code{WEEK()}
function as the given date is actually the 52 second week of 1999. We
decided to return 0 instead as we want the function to return 'the week
number in the given year'. This makes the usage of the @code{WEEK()}
function reliable when combined with other functions that extracts a
date part from a date.
If you would prefer to know the correct year-week, then you should use
the @code{YEARWEEK()} function instead:
@example
mysql> SELECT YEARWEEK('2000-01-01');
-> 199952
mysql> SELECT MID(YEARWEEK('2000-01-01'),5,2);
-> 52
@end example
@findex YEAR()
@item YEAR(date)
Returns the year for @code{date}, in the range @code{1000} to @code{9999}:
@ -32576,6 +32607,10 @@ mysql> SELECT YEARWEEK('1987-01-01');
-> 198653
@end example
Note that the week number is different from what the @code{WEEK()} function
would return (@code{0}) as the week function returns the week in the
context of the given year.
@findex HOUR()
@item HOUR(time)
Returns the hour for @code{time}, in the range @code{0} to @code{23}:
@ -48180,13 +48215,33 @@ mysql> SELECT idate FROM tbl_name WHERE STRCMP(idate,'19970505')=0;
a string and performs a string comparison. It does not convert
@code{'19970505'} to a date and perform a date comparison.
Note that MySQL does no checking whether the date is
Note that MySQL does very limited checking whether the date is
correct. If you store an incorrect date, such as @code{'1998-2-31'}, the
wrong date will be stored. If the date cannot be converted to any reasonable
value, a @code{0} is stored in the @code{DATE} field. This is mainly a speed
issue and we think it is up to the application to check the dates, and not
the server.
wrong date will be stored.
Because MySQL packs dates for storage, it can't store any given date as
it would not fit onto the result buffer. The rules for accepting a date
are:
@itemize @bullet
@item
If MySQL can store it and retrieve a date, the wrong date is accepted
for @code{DATE} and @code{DATETIME} columns.
@item
All days values between 0-31 are accepted for any date. This makes it
very convenient for web applications where you ask year, month and day
in 3 different fields.
@item
The day or month field may be zero. This is convenient if you want
to store a birthdate in a @code{DATE} column and you only know part
of the date.
@end itemize
If the date cannot be converted to any reasonable value, a @code{0} is
stored in the @code{DATE} field, which will be retrieved as
@code{0000-00-00}. This is both a speed and convinient issue as we
belive that the databases responsiblity etrive the same date you stored
(even if the data was not logicall correct in all cases). We think it is
up to the application to check the dates, and not the server.
@node Problems with NULL, Problems with alias, Using DATE, Query Issues
@appendixsubsec Problems with @code{NULL} Values
@ -50167,6 +50222,9 @@ each individual 4.0.x release.
@itemize @bullet
@item
mysqld now has the option @code{--temp-pool} enabled by default as this
gives better performance with some OS.
@item
Big code cleanup in replication code.
@item
If one specifies @code{--code-file}, call @code{setrlmit()} to change allowed
@ -50804,6 +50862,23 @@ 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
@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}, @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}.
@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
@ -50811,7 +50886,9 @@ Don't write slave-timeout reconnects to the error log.
@item
Fixed bug with slave net read timeouting
@item
Fixed bug in ALTERing TABLE of BDB type.
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.

View file

@ -1554,6 +1554,17 @@ AC_SUBST(TERMCAP_LIB)
#########################################################################
dnl Checks for library functions.
#
# The following code disables intrinsic function support while we test for
# library functions. This is to avoid configure problems with Intel ecc
# compiler
ORG_CFLAGS="$CFLAGS"
if test "$GCC" != "yes"; then
AC_SYS_COMPILER_FLAG(-nolib_inline,nolib_inline,CFLAGS,[],[])
fi
AC_FUNC_MMAP
AC_TYPE_SIGNAL
MYSQL_TYPE_QSORT
@ -1576,6 +1587,8 @@ AC_CHECK_FUNCS(alarm bmove \
pthread_condattr_create rwlock_init pthread_rwlock_rdlock \
fchmod getpass getpassphrase initgroups mlockall)
CFLAGS="$ORG_CFLAGS"
# Sanity check: We chould not have any fseeko symbol unless
# large_file_support=yes
AC_CHECK_FUNCS(fseeko,

View file

@ -121,14 +121,6 @@
/* #define _AIX32_CURSES */ /* XXX: this breaks AIX 4.3.3 (others?). */
#endif
#ifdef __QNXNTO__
#define HAVE_ERRNO_AS_DEFINE
#define HAVE_FCNTL_LOCK
#undef HAVE_SYS_UN_H
#undef HAVE_FINITE
#undef HAVE_RINT
#endif
#ifdef HAVE_BROKEN_SNPRINTF /* HPUX 10.20 don't have this defined */
#undef HAVE_SNPRINTF
#endif
@ -253,6 +245,17 @@
#define setrlimit cma_setrlimit64
#endif
#ifdef __QNXNTO__
/* This has to be after include limits.h */
#define HAVE_ERRNO_AS_DEFINE
#define HAVE_FCNTL_LOCK
#undef HAVE_SYS_UN_H
#undef HAVE_FINITE
#undef HAVE_RINT
#undef LONGLONG_MIN /* These get wrongly defined in QNX 6.2 */
#undef LONGLONG_MAX /* standard system library 'limits.h' */
#endif
/* We can not live without the following defines */
#define USE_MYFUNC 1 /* Must use syscall indirection */
@ -548,11 +551,6 @@ extern double my_atof(const char*);
#define HAVE_LONG_LONG 1
#endif
#ifdef __QNXNTO__
#undef LONGLONG_MIN /* These get wrongly defined in QNX 6.2 */
#undef LONGLONG_MAX /* standard system library 'limits.h' */
#endif
#if defined(HAVE_LONG_LONG) && !defined(LONGLONG_MIN)
#define LONGLONG_MIN ((long long) 0x8000000000000000LL)
#define LONGLONG_MAX ((long long) 0x7FFFFFFFFFFFFFFFLL)

View file

@ -430,8 +430,9 @@ struct tm *localtime_r(const time_t *clock, struct tm *res);
#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))
#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);

View file

@ -35,8 +35,6 @@ C_MODE_START
#ifdef HAVE_SEMAPHORE_H
#include <semaphore.h>
#elif defined(__bsdi__)
#include <sys/errno.h>
#else
#ifdef __WIN__
typedef HANDLE sem_t;
#else
@ -45,7 +43,7 @@ typedef struct {
pthread_cond_t cond;
uint count;
} sem_t;
#endif
#endif /* __WIN__ */
int sem_init(sem_t * sem, int pshared, unsigned int value);
int sem_destroy(sem_t * sem);
@ -55,7 +53,7 @@ int sem_post(sem_t * sem);
int sem_post_multiple(sem_t * sem, unsigned int count);
int sem_getvalue(sem_t * sem, unsigned int * sval);
#endif
#endif /* !__bsdi__ */
C_MODE_END
#endif /* !_my_semaphore_h_ */

View file

@ -15,6 +15,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

View file

@ -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 %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;

View file

@ -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;

View file

@ -286,7 +286,7 @@ buf_page_print(
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Page dump in ascii and hex (%u bytes):\n%s",
UNIV_PAGE_SIZE, buf);
(ulint)UNIV_PAGE_SIZE, buf);
fprintf(stderr, "InnoDB: End of page dump\n");
mem_free(buf);
@ -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);
@ -1836,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",
@ -1870,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. */

View file

@ -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
@ -205,6 +206,44 @@ buf_LRU_get_free_block(void)
loop:
mutex_enter(&(buf_pool->mutex));
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);
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 (!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
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 (!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
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));

View file

@ -86,8 +86,10 @@ else
fi
case "$target_os" in
hpux10*)
CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE -DUNIV_HPUX -DUNIV_HPUX10";;
hp*)
CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;
CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE -DUNIV_HPUX";;
irix*)
CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;
osf*)

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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
@ -2629,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"

View file

@ -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) {
@ -335,6 +336,20 @@ 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) {
/* 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);
}
}

View file

@ -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. */
UNIV_INLINE
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. */

View file

@ -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. */

View file

@ -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);
}

View file

@ -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 */
/**************************************************************************

View file

@ -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

View file

@ -17,7 +17,8 @@ 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
/*************************************************************************
@ -123,14 +124,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. */
UNIV_INLINE
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

View file

@ -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

View file

@ -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"

View file

@ -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. */

View file

@ -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
@ -497,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;
@ -544,10 +565,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 */

View file

@ -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) + (ulint)(*(block + i));
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);
}

View file

@ -313,6 +313,11 @@ 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, or there is a log parsing
buffer overflow */
log_group_t* archive_group;
/* in archive recovery: the log group whose
archive is read */
@ -328,6 +333,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)

View file

@ -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. */

View file

@ -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
}

View file

@ -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

View file

@ -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

View file

@ -312,7 +312,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();

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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
@ -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 static inline
#endif
#endif
@ -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

View file

@ -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,\

View file

@ -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
@ -576,6 +581,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);
}
/*************************************************************************
@ -1566,6 +1573,7 @@ index->table_name);
}
trx->que_state = TRX_QUE_LOCK_WAIT;
trx->wait_started = time(NULL);
ut_a(que_thr_stop(thr));
@ -2698,6 +2706,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 +2732,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 +2782,7 @@ lock_deadlock_recursive(
lock_t* lock;
ulint bit_no = 0; /* remove warning */
trx_t* lock_trx;
char* err_buf;
ut_a(trx && start && wait_lock);
ut_ad(mutex_own(&kernel_mutex));
@ -2801,6 +2834,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");
}
@ -2962,6 +3042,7 @@ table->name);
}
trx->que_state = TRX_QUE_LOCK_WAIT;
trx->wait_started = time(NULL);
ut_a(que_thr_stop(thr));
@ -3432,6 +3513,9 @@ lock_rec_print(
buf += sprintf(buf,
"Suppressing further record lock prints for this page\n");
mtr_commit(&mtr);
return;
}
@ -3520,6 +3604,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 */
@ -3588,7 +3688,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);

View file

@ -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));
}
/**********************************************************
@ -3113,8 +3101,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",
@ -3128,3 +3116,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);
}

View file

@ -58,12 +58,16 @@ 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. */
@ -124,6 +128,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 +575,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 +586,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 +638,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;
}
@ -788,14 +774,8 @@ 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",
(ulint)type);
recv_sys->found_corrupt_log = TRUE;
}
ut_ad(!page || new_ptr);
@ -1399,18 +1379,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 +1417,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
@ -1679,29 +1678,16 @@ 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);
}
/* 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",
(ulint)(*type), *space, *page_no);
recv_sys->found_corrupt_log = TRUE;
return(0);
}
@ -1765,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. */
@ -1772,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 */
@ -1812,8 +1854,13 @@ 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) {
recv_report_corrupt_log(ptr,
type, space, page_no);
}
return(FALSE);
}
@ -1828,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;
@ -1851,9 +1902,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
@ -1865,19 +1917,32 @@ 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) {
return(FALSE);
if (recv_sys->found_corrupt_log) {
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 */
#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) {
@ -1919,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));
@ -1941,7 +2012,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 +2166,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 */
@ -2192,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);
@ -2213,7 +2274,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)) {
@ -2225,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);
@ -2602,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;

View file

@ -668,7 +668,7 @@ mem_print_info_low(
mem_pool_print_info(outfile, mem_comm_pool);
mem_validate();
/* mem_validate(); */
/* fclose(outfile); */
#endif

View file

@ -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) {

View file

@ -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;

View file

@ -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 */
@ -2483,7 +2483,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",
@ -2517,6 +2517,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. */

View file

@ -18,26 +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();
/* 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 */
return(*(os_thread_id_t*)((void*) (&pthr)));
return(pthread_self());
#endif
}
@ -71,7 +108,6 @@ os_thread_create(
arg,
0, /* thread runs immediately */
thread_id);
ut_a(thread);
if (srv_set_thread_priorities) {
@ -108,7 +144,7 @@ Returns handle to the current thread. */
os_thread_t
os_thread_get_curr(void)
/*=======================*/
/*====================*/
{
#ifdef __WIN__
return(GetCurrentThread());
@ -116,18 +152,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. */

View file

@ -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);
@ -1010,6 +1030,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);

View file

@ -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 = (char *) "setting auto-inc lock";
if (node == NULL) {

View file

@ -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);

View file

@ -2024,7 +2024,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));
@ -2168,6 +2168,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. */
@ -2205,7 +2233,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"
@ -2242,8 +2270,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"
@ -2285,10 +2313,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"
@ -2331,7 +2359,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
@ -2348,9 +2376,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);
@ -2481,12 +2509,30 @@ 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);
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) {
mem_print_info();
}
*/
sync_array_print_long_waits();
/* Flush stdout and stderr so that a database user gets their output

View file

@ -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
@ -927,6 +933,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 +1332,49 @@ 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);
}
/* 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);
if (srv_print_verbose_log)
{
ut_print_timestamp(stderr);

View file

@ -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);
}

View file

@ -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) {

View file

@ -230,7 +230,6 @@ mutex_create_func(
mutex->magic_n = MUTEX_MAGIC_N;
mutex->line = 0;
mutex->file_name = (char *) "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");

View file

@ -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);

View file

@ -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. */

View file

@ -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",
os_thread_pf(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);

View file

@ -49,6 +49,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 $$qs; do \
rm -f $(srcdir)/$$f; \
@LN_CP_F@ $(srcdir)/../sql/$$f $(srcdir)/$$f; \

View file

@ -42,7 +42,8 @@ mystringsobjects = strmov.lo strxmov.lo strxnmov.lo strnmov.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 \
@ -83,9 +84,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"` \
`echo $(vio_objects) | sed "s;\.lo;.c;g"` \
$(mystringsextra) $(mysysheaders) ctype_extra_sources.c \
net.c ../linked_client_sources
$(mystringsextra) $(mystringsgen) $(mysysheaders) \
ctype_extra_sources.c net.c ../linked_client_sources
ctype_extra_sources.c: conf_to_src
./conf_to_src $(top_srcdir) @CHARSETS_NEED_SOURCE@ > \

View file

@ -151,7 +151,7 @@ int vio_write(Vio * vio, const gptr buf, int size)
DBUG_RETURN(size);
}
int vio_blocking(Vio * vio, my_bool set_blocking_mode)
int vio_blocking(Vio * vio, my_bool set_blocking_mode, my_bool *old_mode)
{
return (0);
}

View file

@ -395,3 +395,25 @@ gender dist_count percentage
M 1 20.00
F 3 60.00
drop table t1,t2;
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;
xID xID1
1 1
2 2
2 2
3 134
3 134
3 134
4 185
4 185
4 185
4 185
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;
xID xID1 Level
1 1 *
2 2 **
3 134 ***
4 185 ****
drop table t1;

View file

@ -301,3 +301,14 @@ insert into t2 values (1, '2002-06-09'),(2, '2002-06-09'),(1, '2002-06-09'),(3,
select u.gender as gender, count(distinct u.id) as dist_count, (count(distinct u.id)/5*100) as percentage from t1 u, t2 l where l.user_id = u.id group by u.gender;
select u.gender as gender, count(distinct u.id) as dist_count, (count(distinct u.id)/5*100) as percentage from t1 u, t2 l where l.user_id = u.id group by u.gender order by percentage;
drop table t1,t2;
#
# 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;

View file

@ -438,6 +438,12 @@ int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
#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);
@ -447,9 +453,9 @@ int my_pthread_mutex_trylock(pthread_mutex_t *mutex)
error=errno;
return error;
}
#endif
/* Some help functions */
int pthread_no_free(void *not_used __attribute__((unused)))

View file

@ -21,6 +21,7 @@
#include <my_global.h>
#include <my_semaphore.h>
#include <errno.h>
#if !defined(__WIN__) && !defined(HAVE_SEMAPHORE_H)

View file

@ -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=#

View file

@ -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
@ -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"
@ -110,8 +111,6 @@ my_bool innobase_fast_shutdown = TRUE;
specify any startup options.
*/
/* innobase_data_file_path=ibdata:15,idata2:1,... */
char *innobase_data_file_path= (char*) "ibdata1:10M:autoextend";
static char *internal_innobase_data_file_path=0;
@ -138,8 +137,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(
@ -150,16 +150,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 */
@ -646,6 +636,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);
}
@ -714,6 +714,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) {
@ -842,7 +852,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
@ -913,13 +923,13 @@ have moved .frm files to another database?",
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;
@ -928,13 +938,13 @@ have moved .frm files to another database?",
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 {
((row_prebuilt_t*)innobase_prebuilt)
@ -942,6 +952,15 @@ have moved .frm files to another database?",
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);
}
@ -1188,7 +1207,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(
@ -1196,7 +1216,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;
@ -1225,8 +1246,9 @@ ha_innobase::store_key_val_for_row(
}
/*
We have to zero-fill the buffer to be able to compare two
keys to see if they are equal
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);
@ -1404,6 +1426,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");
@ -1426,7 +1449,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 */
@ -1459,10 +1506,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
@ -1502,46 +1548,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) {
@ -1901,6 +1919,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. */
@ -1914,7 +1981,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 */
{
@ -1941,10 +2011,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,
@ -1952,6 +2020,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,
@ -2313,8 +2384,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(
@ -2322,13 +2392,17 @@ 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;
uint keynr = active_index;
DBUG_ENTER("rnd_pos");
DBUG_DUMP("key", (char*) pos, ref_stored_len);
DBUG_DUMP("key", (char*) pos, ref_length);
statistic_increment(ha_read_rnd_count, &LOCK_status);
@ -2339,7 +2413,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 {
@ -2351,7 +2425,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);
if (error)
{
DBUG_PRINT("error",("Got error: %ld",error));
@ -2363,8 +2440,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'
is the current 'position' of the handle, because if row ref is actually
that in the case where we have generated the clustered index for the
table, the function parameter is illogical: we MUST ASSUME that 'record'
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
was positioned the last time. */
@ -2384,7 +2461,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;
@ -2393,8 +2470,11 @@ ha_innobase::position(
len = store_key_val_for_row(primary_key, (char*) ref, record);
}
DBUG_ASSERT(len == ref_length);
ref_stored_len = len;
/* 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. */
ut_a(len == ref_length);
}
@ -2612,7 +2692,7 @@ ha_innobase::create(
/* Our function row_get_mysql_key_number_for_index assumes
the primary key is always number 0, if it exists */
assert(primary_key_no == -1 || primary_key_no == 0);
DBUG_ASSERT(primary_key_no == -1 || primary_key_no == 0);
/* Create the keys */
@ -2693,7 +2773,7 @@ ha_innobase::create(
innobase_table = dict_table_get(norm_name, NULL);
assert(innobase_table != 0);
DBUG_ASSERT(innobase_table != 0);
/* Tell the InnoDB server that there might be work for
utility threads: */
@ -3519,37 +3599,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);
@ -3569,22 +3665,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 */

View file

@ -52,8 +52,6 @@ class ha_innobase: public handler
byte* key_val_buff; /* buffer used in converting
search key values from MySQL format
to Innodb format */
uint ref_stored_len; /* length of the key value stored to
'ref' buffer of the handle, if any */
ulong int_table_flags;
uint primary_key;
uint last_dup_key;
@ -71,6 +69,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:

View file

@ -251,7 +251,6 @@ static SYMBOL symbols[] = {
{ "NEW", SYM(NEW_SYM),0,0},
{ "NCHAR", SYM(NCHAR_SYM),0,0},
{ "NO", SYM(NO_SYM),0,0},
{ "NO_FOREIGN_KEY_CHECKS", SYM(NO_FOREIGN_KEY_CHECKS), 0, 0},
{ "NOT", SYM(NOT),0,0},
{ "NULL", SYM(NULL_SYM),0,0},
{ "NUMERIC", SYM(NUMERIC_SYM),0,0},
@ -285,7 +284,6 @@ static SYMBOL symbols[] = {
{ "RELAY_LOG_POS", SYM(RELAY_LOG_POS_SYM),0,0},
{ "RELOAD", SYM(RELOAD),0,0},
{ "REGEXP", SYM(REGEXP),0,0},
{ "RELAXED_UNIQUE_CHECKS", SYM(RELAXED_UNIQUE_CHECKS), 0, 0},
{ "RENAME", SYM(RENAME),0,0},
{ "REPAIR", SYM(REPAIR),0,0},
{ "REPLACE", SYM(REPLACE),0,0},

View file

@ -1320,16 +1320,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) ||

View file

@ -1809,7 +1809,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;
/* Get default temporary directory */
@ -2373,7 +2373,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 */
@ -3260,8 +3268,8 @@ struct my_option my_long_options[] =
#endif
{"temp-pool", OPT_TEMP_POOL,
"Using this option will cause most temporary files created to use a small set of names, rather than a unique name for each new file.",
(gptr*) &use_temp_pool, (gptr*) &use_temp_pool, 0, GET_BOOL, NO_ARG, 0, 0,
0, 0, 0, 0},
(gptr*) &use_temp_pool, (gptr*) &use_temp_pool, 0, GET_BOOL, NO_ARG, 1,
0, 0, 0, 0, 0},
{"tmpdir", 't', "Path for temporary files", (gptr*) &opt_mysql_tmpdir,
(gptr*) &opt_mysql_tmpdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"transaction-isolation", OPT_TX_ISOLATION,
@ -3805,7 +3813,7 @@ Starts the MySQL server\n");
");
puts("");
#endif
print_defaults("my",load_default_groups);
print_defaults(MYSQL_CONFIG_NAME,load_default_groups);
puts("");
fix_paths();
set_ports();

View file

@ -23,6 +23,7 @@
#include "sql_repl.h"
#include "repl_failsafe.h"
#include <thr_alarm.h>
#include <my_dir.h>
#include <assert.h>
bool use_slave_mask = 0;
@ -1029,7 +1030,6 @@ void end_master_info(MASTER_INFO* mi)
int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
{
MY_STAT stat_area;
char fname[FN_REFLEN+128];
int info_fd;
const char* msg = 0;
@ -1069,7 +1069,7 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
DBUG_RETURN(1);
/* if file does not exist */
if (!my_stat(fname, &stat_area, MYF(0)))
if (access(fname,F_OK))
{
/*
If someone removed the file from underneath our feet, just close

View file

@ -253,7 +253,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);
@ -321,6 +321,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)
{
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);

View file

@ -32,7 +32,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 void free_cache_entry(TABLE *entry);
static void mysql_rm_tmp_tables(void);
static key_map get_key_map_from_key_list(TABLE *table,
@ -108,6 +108,24 @@ static void check_unused(void)
#define check_unused()
#endif
/*
Create a list for all open tables matching SQL expression
SYNOPSIS
list_open_tables()
thd Thread THD
wild SQL like expression
NOTES
One gets only a list of tables for which one has any kind of privilege.
db and table names are allocated in result struct, so one doesn't need
a lock on LOCK_open when traversing the return list.
RETURN VALUES
NULL Error (Probably OOM)
# Pointer to list of names of open tables.
*/
OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
{
int result = 0;
@ -275,6 +293,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)
{
@ -709,7 +737,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)))
{
@ -842,8 +870,11 @@ 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) ||
}
if (open_unireg_entry(thd, table,db,table_name,alias) ||
!(table->table_cache_key=memdup_root(&table->mem_root,(char*) key,
key_length)))
{
@ -934,8 +965,7 @@ bool reopen_table(TABLE *table,bool locked)
VOID(pthread_mutex_lock(&LOCK_open));
safe_mutex_assert_owner(&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);
@ -1176,7 +1206,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;
@ -1241,7 +1270,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;
@ -1261,23 +1290,17 @@ 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);
safe_mutex_assert_owner(&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;
}
}
@ -1307,9 +1330,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;
}
@ -1368,9 +1391,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
@ -2207,6 +2230,7 @@ int setup_ftfuncs(THD *thd)
return 0;
}
int init_ftfuncs(THD *thd, bool no_order)
{
if (thd->lex.select->ftfunc_list.elements)
@ -2217,9 +2241,7 @@ int init_ftfuncs(THD *thd, bool no_order)
thd->proc_info="FULLTEXT initialization";
while ((ifm=li++))
{
ifm->init_search(no_order);
}
}
return 0;
}

View file

@ -1454,6 +1454,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;

View file

@ -1493,7 +1493,7 @@ mysql_execute_command(void)
/* Check that the first table has CREATE privilege */
TABLE_LIST *tmp_table_list=tables->next;
tables->next=0;
bool error=check_grant(thd,CREATE_ACL,tables);
bool error=check_grant(thd, want_priv, tables);
tables->next=tmp_table_list;
if (error)
goto error;

View file

@ -3674,7 +3674,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &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)
{

View file

@ -124,13 +124,15 @@ int mysqld_show_open_tables(THD *thd,const char *wild)
net_store_data(&thd->packet,open_list->in_use);
net_store_data(&thd->packet,open_list->locked);
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
{
DBUG_RETURN(-1);
}
}
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

View file

@ -782,7 +782,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);
}
@ -977,19 +979,25 @@ static int prepare_for_repair(THD* thd, TABLE_LIST* table,
if (my_rename(from, tmp, 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, "repair",
"Failed renaming .MYD file"));
}
if (mysql_truncate(thd, table, 1))
{
pthread_mutex_lock(&LOCK_open);
unlock_table_name(thd, table);
pthread_mutex_unlock(&LOCK_open);
DBUG_RETURN(send_check_errmsg(thd, table, "repair",
"Failed generating table from .frm file"));
}
if (my_rename(tmp, from, 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, "repair",
"Failed restoring .MYD file"));
}
@ -1000,7 +1008,11 @@ static int prepare_for_repair(THD* thd, TABLE_LIST* table,
to finish the repair in the handler later on.
*/
if (!(table->table = reopen_name_locked_table(thd, table)))
unlock_table_name(thd, table);
{
pthread_mutex_lock(&LOCK_open);
unlock_table_name(thd, table);
pthread_mutex_unlock(&LOCK_open);
}
DBUG_RETURN(0);
}
@ -1855,8 +1867,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

View file

@ -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-latin1_de.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

View file

@ -59,6 +59,7 @@ main( int argc,
char* ca_file = 0, *ca_path = 0;
char* cipher=0;
int child_pid,sv[2];
my_bool unused;
struct st_VioSSLAcceptorFd* ssl_acceptor=0;
struct st_VioSSLConnectorFd* ssl_connector=0;
Vio* client_vio=0, *server_vio=0;
@ -96,11 +97,11 @@ main( int argc,
client_vio = (struct st_vio*)my_malloc(sizeof(struct st_vio),MYF(0));
client_vio->sd = sv[0];
client_vio->vioblocking(client_vio,0);
client_vio->vioblocking(client_vio, 0, &unused);
sslconnect(ssl_connector,client_vio,60L);
server_vio = (struct st_vio*)my_malloc(sizeof(struct st_vio),MYF(0));
server_vio->sd = sv[1];
server_vio->vioblocking(client_vio,0);
server_vio->vioblocking(client_vio, 0, &unused);
sslaccept(ssl_acceptor,server_vio,60L);
printf("Socketpair: %d , %d\n", client_vio->sd, server_vio->sd);