Commit 6841f9ee authored by unknown's avatar unknown

Merge lgrimmer@build.mysql.com:/home/bk/mysql-4.0

into mysql.com:/space/my/mysql-4.0


BitKeeper/deleted/.del-internals.texi~62b6f580a41c2a43:
  Auto merged
parents d272a9e4 3f7dfc4d
/* Copyright (C) 2000 MySQL AB /* Copyright (C) 2000-2003 MySQL AB
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -246,7 +246,7 @@ C_MODE_END ...@@ -246,7 +246,7 @@ C_MODE_END
# endif # endif
#endif /* TIME_WITH_SYS_TIME */ #endif /* TIME_WITH_SYS_TIME */
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#if defined(HAVE_OPENSSL) && !defined(__FreeBSD__) && !defined(NeXT) #if defined(HAVE_OPENSSL) && !defined(__FreeBSD__) && !defined(NeXT) && !defined(__OpenBSD__)
#define crypt unistd_crypt #define crypt unistd_crypt
#endif #endif
#include <unistd.h> #include <unistd.h>
...@@ -640,6 +640,9 @@ typedef long my_ptrdiff_t; ...@@ -640,6 +640,9 @@ typedef long my_ptrdiff_t;
typedef long long my_ptrdiff_t; typedef long long my_ptrdiff_t;
#endif #endif
/* typedef used for length of string; Should be unsigned! */
typedef ulong size_str;
#define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1)) #define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1))
#define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double)) #define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double))
/* Size to make adressable obj. */ /* Size to make adressable obj. */
......
...@@ -301,6 +301,13 @@ os_aio( ...@@ -301,6 +301,13 @@ os_aio(
are ignored */ are ignored */
void* message2); void* message2);
/**************************************************************************** /****************************************************************************
Wakes up all async i/o threads so that they know to exit themselves in
shutdown. */
void
os_aio_wake_all_threads_at_shutdown(void);
/*=====================================*/
/****************************************************************************
Waits until there are no pending writes in os_aio_write_array. There can Waits until there are no pending writes in os_aio_write_array. There can
be other, synchronous, pending writes. */ be other, synchronous, pending writes. */
......
...@@ -10,15 +10,16 @@ Created 9/6/1995 Heikki Tuuri ...@@ -10,15 +10,16 @@ Created 9/6/1995 Heikki Tuuri
#define os0sync_h #define os0sync_h
#include "univ.i" #include "univ.i"
#include "ut0lst.h"
#ifdef __WIN__ #ifdef __WIN__
#define os_fast_mutex_t CRITICAL_SECTION #define os_fast_mutex_t CRITICAL_SECTION
typedef void* os_event_t; typedef HANDLE os_event_t;
#else #else
typedef pthread_mutex_t os_fast_mutex_t; typedef pthread_mutex_t os_fast_mutex_t;
typedef struct os_event_struct os_event_struct_t;
typedef os_event_struct_t* os_event_t;
struct os_event_struct { struct os_event_struct {
os_fast_mutex_t os_mutex; /* this mutex protects the next os_fast_mutex_t os_mutex; /* this mutex protects the next
fields */ fields */
...@@ -26,9 +27,9 @@ struct os_event_struct { ...@@ -26,9 +27,9 @@ struct os_event_struct {
not reserved */ not reserved */
pthread_cond_t cond_var; /* condition variable is used in pthread_cond_t cond_var; /* condition variable is used in
waiting for the event */ waiting for the event */
UT_LIST_NODE_T(os_event_struct_t) os_event_list;
/* list of all created events */
}; };
typedef struct os_event_struct os_event_struct_t;
typedef os_event_struct_t* os_event_t;
#endif #endif
typedef struct os_mutex_struct os_mutex_str_t; typedef struct os_mutex_struct os_mutex_str_t;
...@@ -38,6 +39,29 @@ typedef os_mutex_str_t* os_mutex_t; ...@@ -38,6 +39,29 @@ typedef os_mutex_str_t* os_mutex_t;
#define OS_SYNC_TIME_EXCEEDED 1 #define OS_SYNC_TIME_EXCEEDED 1
/* Mutex protecting the thread count and event and OS 'slow' mutex lists */
extern os_mutex_t os_sync_mutex;
/* This is incremented by 1 in os_thread_create and decremented by 1 in
os_thread_exit */
extern ulint os_thread_count;
/* The following are approximate counters for debugging in Unix */
extern ulint os_event_count;
extern ulint os_mutex_count;
/*************************************************************
Initializes global event and OS 'slow' mutex lists. */
void
os_sync_init(void);
/*==============*/
/*************************************************************
Frees created events (not in Windows) and OS 'slow' mutexes. */
void
os_sync_free(void);
/*==============*/
/************************************************************* /*************************************************************
Creates an event semaphore, i.e., a semaphore which may Creates an event semaphore, i.e., a semaphore which may
just have two states: signaled and nonsignaled. just have two states: signaled and nonsignaled.
...@@ -85,7 +109,10 @@ os_event_free( ...@@ -85,7 +109,10 @@ os_event_free(
/*==========*/ /*==========*/
os_event_t event); /* in: event to free */ os_event_t event); /* in: event to free */
/************************************************************** /**************************************************************
Waits for an event object until it is in the signaled state. */ Waits for an event object until it is in the signaled state. If
srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the
waiting thread when the event becomes signaled (or immediately if the
event is already in the signaled state). */
void void
os_event_wait( os_event_wait(
......
...@@ -41,7 +41,6 @@ typedef os_thread_t os_thread_id_t; /* In Unix we use the thread ...@@ -41,7 +41,6 @@ typedef os_thread_t os_thread_id_t; /* In Unix we use the thread
the thread */ the thread */
#endif #endif
/* Define a function pointer type to use in a typecast */ /* Define a function pointer type to use in a typecast */
typedef void* (*os_posix_f_t) (void*); typedef void* (*os_posix_f_t) (void*);
...@@ -83,12 +82,13 @@ os_thread_create( ...@@ -83,12 +82,13 @@ os_thread_create(
os_thread_id_t* thread_id); /* out: id of the created os_thread_id_t* thread_id); /* out: id of the created
thread */ thread */
/********************************************************************* /*********************************************************************
A thread calling this function ends its execution. */ Exits the current thread. */
void void
os_thread_exit( os_thread_exit(
/*===========*/ /*===========*/
ulint code); /* in: exit code */ void* exit_value); /* in: exit value; in Windows this void*
is cast as a DWORD */
/********************************************************************* /*********************************************************************
Returns the thread identifier of current thread. */ Returns the thread identifier of current thread. */
...@@ -144,7 +144,6 @@ ulint ...@@ -144,7 +144,6 @@ ulint
os_thread_get_last_error(void); os_thread_get_last_error(void);
/*==========================*/ /*==========================*/
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "os0thread.ic" #include "os0thread.ic"
#endif #endif
......
...@@ -209,6 +209,12 @@ void ...@@ -209,6 +209,12 @@ void
srv_init(void); srv_init(void);
/*==========*/ /*==========*/
/************************************************************************* /*************************************************************************
Frees the OS fast mutex created in srv_init(). */
void
srv_free(void);
/*==========*/
/*************************************************************************
Initializes the synchronization primitives, memory system, and the thread Initializes the synchronization primitives, memory system, and the thread
local storage. */ local storage. */
......
...@@ -86,11 +86,12 @@ extern ibool srv_startup_is_before_trx_rollback_phase; ...@@ -86,11 +86,12 @@ extern ibool srv_startup_is_before_trx_rollback_phase;
extern ibool srv_is_being_shut_down; extern ibool srv_is_being_shut_down;
/* At a shutdown the value first climbs from 0 to SRV_SHUTDOWN_CLEANUP /* At a shutdown the value first climbs from 0 to SRV_SHUTDOWN_CLEANUP
and then to SRV_SHUTDOWN_LAST_PHASE */ and then to SRV_SHUTDOWN_LAST_PHASE, and so on */
extern ulint srv_shutdown_state; extern ulint srv_shutdown_state;
#define SRV_SHUTDOWN_CLEANUP 1 #define SRV_SHUTDOWN_CLEANUP 1
#define SRV_SHUTDOWN_LAST_PHASE 2 #define SRV_SHUTDOWN_LAST_PHASE 2
#define SRV_SHUTDOWN_EXIT_THREADS 3
#endif #endif
...@@ -375,7 +375,7 @@ log_pad_current_log_block(void) ...@@ -375,7 +375,7 @@ log_pad_current_log_block(void)
log_close(); log_close();
log_release(); log_release();
ut_a((ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE) ut_ad((ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE)
== LOG_BLOCK_HDR_SIZE); == LOG_BLOCK_HDR_SIZE);
} }
...@@ -998,6 +998,8 @@ log_group_file_header_flush( ...@@ -998,6 +998,8 @@ log_group_file_header_flush(
{ {
byte* buf; byte* buf;
ulint dest_offset; ulint dest_offset;
UT_NOT_USED(type);
ut_ad(mutex_own(&(log_sys->mutex))); ut_ad(mutex_own(&(log_sys->mutex)));
...@@ -1068,8 +1070,8 @@ log_group_write_buf( ...@@ -1068,8 +1070,8 @@ log_group_write_buf(
ulint i; ulint i;
ut_ad(mutex_own(&(log_sys->mutex))); ut_ad(mutex_own(&(log_sys->mutex)));
ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0); ut_ad(len % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_a(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); ut_ad(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0);
if (new_data_offset == 0) { if (new_data_offset == 0) {
write_header = TRUE; write_header = TRUE;
...@@ -2901,10 +2903,9 @@ logs_empty_and_mark_files_at_shutdown(void) ...@@ -2901,10 +2903,9 @@ logs_empty_and_mark_files_at_shutdown(void)
dulint lsn; dulint lsn;
ulint arch_log_no; ulint arch_log_no;
if (srv_print_verbose_log) if (srv_print_verbose_log) {
{ ut_print_timestamp(stderr);
ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Starting shutdown...\n");
fprintf(stderr, " InnoDB: Starting shutdown...\n");
} }
/* Wait until the master thread and all other operations are idle: our /* Wait until the master thread and all other operations are idle: our
algorithm only works if the server is idle at shutdown */ algorithm only works if the server is idle at shutdown */
...@@ -3006,15 +3007,17 @@ logs_empty_and_mark_files_at_shutdown(void) ...@@ -3006,15 +3007,17 @@ logs_empty_and_mark_files_at_shutdown(void)
goto loop; goto loop;
} }
/* Make some checks that the server really is quiet */
ut_a(buf_all_freed());
ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn));
fil_write_flushed_lsn_to_data_files(lsn, arch_log_no); fil_write_flushed_lsn_to_data_files(lsn, arch_log_no);
fil_flush_file_spaces(FIL_TABLESPACE); fil_flush_file_spaces(FIL_TABLESPACE);
if (srv_print_verbose_log) /* Make some checks that the server really is quiet */
{ ut_a(buf_all_freed());
ut_print_timestamp(stderr); ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn));
fprintf(stderr, " InnoDB: Shutdown completed\n");
}
} }
/********************************************************** /**********************************************************
......
...@@ -295,7 +295,8 @@ os_file_handle_error( ...@@ -295,7 +295,8 @@ os_file_handle_error(
/* out: TRUE if we should retry the /* out: TRUE if we should retry the
operation */ operation */
os_file_t file, /* in: file pointer */ os_file_t file, /* in: file pointer */
char* name) /* in: name of a file or NULL */ char* name, /* in: name of a file or NULL */
const char* operation) /* in: type of operation */
{ {
ulint err; ulint err;
...@@ -337,7 +338,8 @@ os_file_handle_error( ...@@ -337,7 +338,8 @@ os_file_handle_error(
if (name) { if (name) {
fprintf(stderr, "InnoDB: File name %s\n", name); fprintf(stderr, "InnoDB: File name %s\n", name);
} }
fprintf(stderr, "InnoDB: system call %s\n", operation);
fprintf(stderr, "InnoDB: Cannot continue operation.\n"); fprintf(stderr, "InnoDB: Cannot continue operation.\n");
fflush(stderr); fflush(stderr);
...@@ -419,7 +421,9 @@ os_file_create_simple( ...@@ -419,7 +421,9 @@ os_file_create_simple(
if (file == INVALID_HANDLE_VALUE) { if (file == INVALID_HANDLE_VALUE) {
*success = FALSE; *success = FALSE;
retry = os_file_handle_error(file, name); retry = os_file_handle_error(file, name,
create_mode == OS_FILE_OPEN ?
"open" : "create");
if (retry) { if (retry) {
goto try_again; goto try_again;
...@@ -460,7 +464,10 @@ os_file_create_simple( ...@@ -460,7 +464,10 @@ os_file_create_simple(
if (file == -1) { if (file == -1) {
*success = FALSE; *success = FALSE;
retry = os_file_handle_error(file, name); retry = os_file_handle_error(file, name,
create_mode == OS_FILE_OPEN ?
"open" : "create");
if (retry) { if (retry) {
goto try_again; goto try_again;
...@@ -568,7 +575,9 @@ os_file_create( ...@@ -568,7 +575,9 @@ os_file_create(
if (file == INVALID_HANDLE_VALUE) { if (file == INVALID_HANDLE_VALUE) {
*success = FALSE; *success = FALSE;
retry = os_file_handle_error(file, name); retry = os_file_handle_error(file, name,
create_mode == OS_FILE_OPEN ?
"open" : "create");
if (retry) { if (retry) {
goto try_again; goto try_again;
...@@ -615,7 +624,9 @@ os_file_create( ...@@ -615,7 +624,9 @@ os_file_create(
if (file == -1) { if (file == -1) {
*success = FALSE; *success = FALSE;
retry = os_file_handle_error(file, name); retry = os_file_handle_error(file, name,
create_mode == OS_FILE_OPEN ?
"open" : "create");
if (retry) { if (retry) {
goto try_again; goto try_again;
...@@ -649,7 +660,7 @@ os_file_close( ...@@ -649,7 +660,7 @@ os_file_close(
return(TRUE); return(TRUE);
} }
os_file_handle_error(file, NULL); os_file_handle_error(file, NULL, "close");
return(FALSE); return(FALSE);
#else #else
int ret; int ret;
...@@ -657,7 +668,7 @@ os_file_close( ...@@ -657,7 +668,7 @@ os_file_close(
ret = close(file); ret = close(file);
if (ret == -1) { if (ret == -1) {
os_file_handle_error(file, NULL); os_file_handle_error(file, NULL, "close");
return(FALSE); return(FALSE);
} }
...@@ -825,7 +836,7 @@ os_file_flush( ...@@ -825,7 +836,7 @@ os_file_flush(
return(TRUE); return(TRUE);
} }
os_file_handle_error(file, NULL); os_file_handle_error(file, NULL, "flush");
/* It is a fatal error if a file flush does not succeed, because then /* It is a fatal error if a file flush does not succeed, because then
the database can get corrupt on disk */ the database can get corrupt on disk */
...@@ -858,7 +869,7 @@ os_file_flush( ...@@ -858,7 +869,7 @@ os_file_flush(
fprintf(stderr, fprintf(stderr,
" InnoDB: Error: the OS said file flush did not succeed\n"); " InnoDB: Error: the OS said file flush did not succeed\n");
os_file_handle_error(file, NULL); os_file_handle_error(file, NULL, "flush");
/* It is a fatal error if a file flush does not succeed, because then /* It is a fatal error if a file flush does not succeed, because then
the database can get corrupt on disk */ the database can get corrupt on disk */
...@@ -1099,7 +1110,7 @@ os_file_read( ...@@ -1099,7 +1110,7 @@ os_file_read(
#ifdef __WIN__ #ifdef __WIN__
error_handling: error_handling:
#endif #endif
retry = os_file_handle_error(file, NULL); retry = os_file_handle_error(file, NULL, "read");
if (retry) { if (retry) {
goto try_again; goto try_again;
...@@ -1295,7 +1306,6 @@ os_aio_array_create( ...@@ -1295,7 +1306,6 @@ os_aio_array_create(
#endif #endif
ut_a(n > 0); ut_a(n > 0);
ut_a(n_segments > 0); ut_a(n_segments > 0);
ut_a(n % n_segments == 0);
array = ut_malloc(sizeof(os_aio_array_t)); array = ut_malloc(sizeof(os_aio_array_t));
...@@ -1404,6 +1414,50 @@ os_aio_init( ...@@ -1404,6 +1414,50 @@ os_aio_init(
pthread_sigmask(SIG_BLOCK, &sigset, NULL); */ pthread_sigmask(SIG_BLOCK, &sigset, NULL); */
#endif #endif
} }
#ifdef WIN_ASYNC_IO
/****************************************************************************
Wakes up all async i/o threads in the array in Windows async i/o at
shutdown. */
static
void
os_aio_array_wake_win_aio_at_shutdown(
/*==================================*/
os_aio_array_t* array) /* in: aio array */
{
ulint i;
for (i = 0; i < array->n_slots; i++) {
os_event_set(*(array->events + i));
}
}
#endif
/****************************************************************************
Wakes up all async i/o threads so that they know to exit themselves in
shutdown. */
void
os_aio_wake_all_threads_at_shutdown(void)
/*=====================================*/
{
ulint i;
#ifdef WIN_ASYNC_IO
/* This code wakes up all ai/o threads in Windows native aio */
os_aio_array_wake_win_aio_at_shutdown(os_aio_read_array);
os_aio_array_wake_win_aio_at_shutdown(os_aio_write_array);
os_aio_array_wake_win_aio_at_shutdown(os_aio_ibuf_array);
os_aio_array_wake_win_aio_at_shutdown(os_aio_log_array);
#endif
/* This loop wakes up all simulated ai/o threads */
for (i = 0; i < os_aio_n_segments; i++) {
os_event_set(os_aio_segment_wait_events[i]);
}
}
/**************************************************************************** /****************************************************************************
Waits until there are no pending writes in os_aio_write_array. There can Waits until there are no pending writes in os_aio_write_array. There can
...@@ -1971,7 +2025,7 @@ os_aio( ...@@ -1971,7 +2025,7 @@ os_aio(
os_aio_array_free_slot(array, slot); os_aio_array_free_slot(array, slot);
retry = os_file_handle_error(file, name); retry = os_file_handle_error(file, name, "aio");
if (retry) { if (retry) {
...@@ -2070,7 +2124,7 @@ os_aio_windows_handle( ...@@ -2070,7 +2124,7 @@ os_aio_windows_handle(
ut_a(TRUE == os_file_flush(slot->file)); ut_a(TRUE == os_file_flush(slot->file));
} }
} else { } else {
os_file_handle_error(slot->file, slot->name); os_file_handle_error(slot->file, slot->name, "aio");
ret_val = FALSE; ret_val = FALSE;
} }
......
...@@ -17,6 +17,7 @@ Created 9/6/1995 Heikki Tuuri ...@@ -17,6 +17,7 @@ Created 9/6/1995 Heikki Tuuri
#endif #endif
#include "ut0mem.h" #include "ut0mem.h"
#include "srv0start.h"
/* Type definition for an operating system mutex struct */ /* Type definition for an operating system mutex struct */
struct os_mutex_struct{ struct os_mutex_struct{
...@@ -26,9 +27,75 @@ struct os_mutex_struct{ ...@@ -26,9 +27,75 @@ struct os_mutex_struct{
recursively lock the mutex: we recursively lock the mutex: we
do not assume that the OS mutex do not assume that the OS mutex
supports recursive locking, though supports recursive locking, though
NT seems to do that */ NT seems to do that */
UT_LIST_NODE_T(os_mutex_str_t) os_mutex_list;
/* list of all 'slow' OS mutexes created */
}; };
/* Mutex protecting the thread count and the lists of OS mutexes
and events */
os_mutex_t os_sync_mutex;
ibool os_sync_mutex_inited = FALSE;
/* This is incremented by 1 in os_thread_create and decremented by 1 in
os_thread_exit */
ulint os_thread_count = 0;
/* The list of all events created (not in Windows) */
UT_LIST_BASE_NODE_T(os_event_struct_t) os_event_list;
/* The list of all OS 'slow' mutexes */
UT_LIST_BASE_NODE_T(os_mutex_str_t) os_mutex_list;
/* The following are approximate counters for debugging in Unix */
ulint os_event_count = 0;
ulint os_mutex_count = 0;
/*************************************************************
Initializes global event and OS 'slow' mutex lists. */
void
os_sync_init(void)
/*==============*/
{
UT_LIST_INIT(os_event_list);
UT_LIST_INIT(os_mutex_list);
os_sync_mutex = os_mutex_create(NULL);
os_sync_mutex_inited = TRUE;
}
/*************************************************************
Frees created events (not in Windows) and OS 'slow' mutexes. */
void
os_sync_free(void)
/*==============*/
{
os_event_t event;
os_mutex_t mutex;
event = UT_LIST_GET_FIRST(os_event_list);
while (event) {
os_event_free(event);
event = UT_LIST_GET_FIRST(os_event_list);
}
mutex = UT_LIST_GET_FIRST(os_mutex_list);
while (mutex) {
os_mutex_free(mutex);
mutex = UT_LIST_GET_FIRST(os_mutex_list);
}
}
/************************************************************* /*************************************************************
Creates an event semaphore, i.e., a semaphore which may Creates an event semaphore, i.e., a semaphore which may
just have two states: signaled and nonsignaled. just have two states: signaled and nonsignaled.
...@@ -43,8 +110,8 @@ os_event_create( ...@@ -43,8 +110,8 @@ os_event_create(
the event is created without a name */ the event is created without a name */
{ {
#ifdef __WIN__ #ifdef __WIN__
HANDLE event; os_event_t event;
event = CreateEvent(NULL, /* No security attributes */ event = CreateEvent(NULL, /* No security attributes */
TRUE, /* Manual reset */ TRUE, /* Manual reset */
FALSE, /* Initial state nonsignaled */ FALSE, /* Initial state nonsignaled */
...@@ -75,6 +142,14 @@ os_event_create( ...@@ -75,6 +142,14 @@ os_event_create(
#endif #endif
event->is_set = FALSE; event->is_set = FALSE;
os_mutex_enter(os_sync_mutex);
UT_LIST_ADD_FIRST(os_event_list, os_event_list, event);
os_event_count++;
os_mutex_exit(os_sync_mutex);
return(event); return(event);
#endif #endif
} }
...@@ -92,7 +167,7 @@ os_event_create_auto( ...@@ -92,7 +167,7 @@ os_event_create_auto(
the event is created without a name */ the event is created without a name */
{ {
#ifdef __WIN__ #ifdef __WIN__
HANDLE event; os_event_t event;
event = CreateEvent(NULL, /* No security attributes */ event = CreateEvent(NULL, /* No security attributes */
FALSE, /* Auto-reset */ FALSE, /* Auto-reset */
...@@ -106,6 +181,8 @@ os_event_create_auto( ...@@ -106,6 +181,8 @@ os_event_create_auto(
UT_NOT_USED(name); UT_NOT_USED(name);
ut_a(0);
return(NULL); return(NULL);
#endif #endif
} }
...@@ -185,12 +262,23 @@ os_event_free( ...@@ -185,12 +262,23 @@ os_event_free(
os_fast_mutex_free(&(event->os_mutex)); os_fast_mutex_free(&(event->os_mutex));
ut_a(0 == pthread_cond_destroy(&(event->cond_var))); ut_a(0 == pthread_cond_destroy(&(event->cond_var)));
os_mutex_enter(os_sync_mutex);
UT_LIST_REMOVE(os_event_list, os_event_list, event);
os_event_count--;
os_mutex_exit(os_sync_mutex);
ut_free(event); ut_free(event);
#endif #endif
} }
/************************************************************** /**************************************************************
Waits for an event object until it is in the signaled state. */ Waits for an event object until it is in the signaled state. If
srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the
waiting thread when the event becomes signaled (or immediately if the
event is already in the signaled state). */
void void
os_event_wait( os_event_wait(
...@@ -206,12 +294,20 @@ os_event_wait( ...@@ -206,12 +294,20 @@ os_event_wait(
err = WaitForSingleObject(event, INFINITE); err = WaitForSingleObject(event, INFINITE);
ut_a(err == WAIT_OBJECT_0); ut_a(err == WAIT_OBJECT_0);
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
os_thread_exit(NULL);
}
#else #else
os_fast_mutex_lock(&(event->os_mutex)); os_fast_mutex_lock(&(event->os_mutex));
loop: loop:
if (event->is_set == TRUE) { if (event->is_set == TRUE) {
os_fast_mutex_unlock(&(event->os_mutex)); os_fast_mutex_unlock(&(event->os_mutex));
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
os_thread_exit(NULL);
}
/* Ok, we may return */ /* Ok, we may return */
return; return;
...@@ -291,14 +387,17 @@ os_event_wait_multiple( ...@@ -291,14 +387,17 @@ os_event_wait_multiple(
ut_a(event_array); ut_a(event_array);
ut_a(n > 0); ut_a(n > 0);
index = WaitForMultipleObjects(n, index = WaitForMultipleObjects(n, event_array,
event_array,
FALSE, /* Wait for any 1 event */ FALSE, /* Wait for any 1 event */
INFINITE); /* Infinite wait time INFINITE); /* Infinite wait time
limit */ limit */
ut_a(index >= WAIT_OBJECT_0); ut_a(index >= WAIT_OBJECT_0);
ut_a(index < WAIT_OBJECT_0 + n); ut_a(index < WAIT_OBJECT_0 + n);
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
os_thread_exit(NULL);
}
return(index - WAIT_OBJECT_0); return(index - WAIT_OBJECT_0);
#else #else
ut_a(n == 0); ut_a(n == 0);
...@@ -337,6 +436,16 @@ os_mutex_create( ...@@ -337,6 +436,16 @@ os_mutex_create(
mutex_str->handle = mutex; mutex_str->handle = mutex;
mutex_str->count = 0; mutex_str->count = 0;
if (os_sync_mutex_inited) {
os_mutex_enter(os_sync_mutex);
}
UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str);
if (os_sync_mutex_inited) {
os_mutex_exit(os_sync_mutex);
}
return(mutex_str); return(mutex_str);
#else #else
os_fast_mutex_t* os_mutex; os_fast_mutex_t* os_mutex;
...@@ -353,6 +462,16 @@ os_mutex_create( ...@@ -353,6 +462,16 @@ os_mutex_create(
mutex_str->handle = os_mutex; mutex_str->handle = os_mutex;
mutex_str->count = 0; mutex_str->count = 0;
if (os_sync_mutex_inited) {
os_mutex_enter(os_sync_mutex);
}
UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str);
if (os_sync_mutex_inited) {
os_mutex_exit(os_sync_mutex);
}
return(mutex_str); return(mutex_str);
#endif #endif
} }
...@@ -424,9 +543,22 @@ os_mutex_free( ...@@ -424,9 +543,22 @@ os_mutex_free(
#ifdef __WIN__ #ifdef __WIN__
ut_a(mutex); ut_a(mutex);
os_mutex_enter(os_sync_mutex);
UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex);
os_mutex_exit(os_sync_mutex);
ut_a(CloseHandle(mutex->handle)); ut_a(CloseHandle(mutex->handle));
ut_free(mutex); ut_free(mutex);
#else #else
os_mutex_enter(os_sync_mutex);
UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex);
os_mutex_exit(os_sync_mutex);
os_fast_mutex_free(mutex->handle); os_fast_mutex_free(mutex->handle);
ut_free(mutex->handle); ut_free(mutex->handle);
ut_free(mutex); ut_free(mutex);
...@@ -451,6 +583,7 @@ os_fast_mutex_init( ...@@ -451,6 +583,7 @@ os_fast_mutex_init(
#else #else
ut_a(0 == pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST)); ut_a(0 == pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST));
#endif #endif
os_mutex_count++;
#endif #endif
} }
...@@ -498,5 +631,6 @@ os_fast_mutex_free( ...@@ -498,5 +631,6 @@ os_fast_mutex_free(
DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex); DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex);
#else #else
ut_a(0 == pthread_mutex_destroy(fast_mutex)); ut_a(0 == pthread_mutex_destroy(fast_mutex));
os_mutex_count--;
#endif #endif
} }
/****************************************************** /******************************************************
The interface to the operating system The interface to the operating system thread control primitives
process and thread control primitives
(c) 1995 Innobase Oy (c) 1995 Innobase Oy
...@@ -17,6 +16,7 @@ Created 9/8/1995 Heikki Tuuri ...@@ -17,6 +16,7 @@ Created 9/8/1995 Heikki Tuuri
#endif #endif
#include "srv0srv.h" #include "srv0srv.h"
#include "os0sync.h"
/******************************************************************* /*******************************************************************
Compares two thread ids for equality. */ Compares two thread ids for equality. */
...@@ -102,6 +102,10 @@ os_thread_create( ...@@ -102,6 +102,10 @@ os_thread_create(
os_thread_t thread; os_thread_t thread;
ulint win_thread_id; ulint win_thread_id;
os_mutex_enter(os_sync_mutex);
os_thread_count++;
os_mutex_exit(os_sync_mutex);
thread = CreateThread(NULL, /* no security attributes */ thread = CreateThread(NULL, /* no security attributes */
0, /* default size stack */ 0, /* default size stack */
(LPTHREAD_START_ROUTINE)start_f, (LPTHREAD_START_ROUTINE)start_f,
...@@ -144,6 +148,9 @@ os_thread_create( ...@@ -144,6 +148,9 @@ os_thread_create(
exit(1); exit(1);
} }
#endif #endif
os_mutex_enter(os_sync_mutex);
os_thread_count++;
os_mutex_exit(os_sync_mutex);
#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10) #if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
ret = pthread_create(&pthread, pthread_attr_default, start_f, arg); ret = pthread_create(&pthread, pthread_attr_default, start_f, arg);
...@@ -170,6 +177,26 @@ os_thread_create( ...@@ -170,6 +177,26 @@ os_thread_create(
#endif #endif
} }
/*********************************************************************
Exits the current thread. */
void
os_thread_exit(
/*===========*/
void* exit_value) /* in: exit value; in Windows this void*
is cast as a DWORD */
{
os_mutex_enter(os_sync_mutex);
os_thread_count--;
os_mutex_exit(os_sync_mutex);
#ifdef __WIN__
ExitThread((DWORD)exit_value);
#else
pthread_exit(exit_value);
#endif
}
/********************************************************************* /*********************************************************************
Returns handle to the current thread. */ Returns handle to the current thread. */
......
...@@ -1693,76 +1693,33 @@ srv_init(void) ...@@ -1693,76 +1693,33 @@ srv_init(void)
ut_a(conc_slot->event); ut_a(conc_slot->event);
} }
} }
/************************************************************************* /*************************************************************************
Initializes the synchronization primitives, memory system, and the thread Frees the OS fast mutex created in srv_init(). */
local storage. */
void void
srv_general_init(void) srv_free(void)
/*==================*/ /*==========*/
{ {
sync_init(); os_fast_mutex_free(&srv_conc_mutex);
mem_init(srv_mem_pool_size);
thr_local_init();
} }
#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY)
/* NetWare requires some cleanup of mutexes */
/************************************************************************* /*************************************************************************
Deinitializes the synchronization primitives, memory system, and the thread Initializes the synchronization primitives, memory system, and the thread
local storage. */ local storage. */
void void
srv_general_free(void) srv_general_init(void)
/*==================*/ /*==================*/
{ {
sync_close(); os_sync_init();
sync_init();
mem_init(srv_mem_pool_size);
thr_local_init();
} }
#endif /* __NETWARE__ */
/*======================= InnoDB Server FIFO queue =======================*/ /*======================= InnoDB Server FIFO queue =======================*/
#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY)
/* NetWare requires some cleanup of mutexes */
/*************************************************************************
Deinitializes the server. */
void
srv_free(void)
/*==========*/
{
srv_conc_slot_t* conc_slot;
srv_slot_t* slot;
ulint i;
for (i = 0; i < OS_THREAD_MAX_N; i++)
{
slot = srv_table_get_nth_slot(i);
os_event_free(slot->event);
}
/* TODO: free(srv_sys->threads); */
for (i = 0; i < OS_THREAD_MAX_N; i++)
{
slot = srv_mysql_table + i;
os_event_free(slot->event);
}
/* TODO: free(srv_mysql_table); */
for (i = 0; i < OS_THREAD_MAX_N; i++)
{
conc_slot = srv_conc_slots + i;
os_event_free(conc_slot->event);
}
}
#endif /* __NETWARE__ */
/************************************************************************* /*************************************************************************
Puts an OS thread to wait if there are too many concurrent threads Puts an OS thread to wait if there are too many concurrent threads
...@@ -2700,6 +2657,8 @@ srv_error_monitor_thread( ...@@ -2700,6 +2657,8 @@ srv_error_monitor_thread(
srv_error_monitor_active = FALSE; srv_error_monitor_active = FALSE;
os_thread_exit(NULL);
#ifndef __WIN__ #ifndef __WIN__
return(NULL); return(NULL);
#else #else
...@@ -3139,6 +3098,13 @@ srv_master_thread( ...@@ -3139,6 +3098,13 @@ srv_master_thread(
os_event_wait(event); os_event_wait(event);
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
/* This is only extra safety, the thread should exit
already when the event wait ends */
os_thread_exit(NULL);
}
/* When there is user activity, InnoDB will set the event and the main /* When there is user activity, InnoDB will set the event and the main
thread goes back to loop: */ thread goes back to loop: */
......
...@@ -1442,9 +1442,7 @@ innobase_start_or_create_for_mysql(void) ...@@ -1442,9 +1442,7 @@ innobase_start_or_create_for_mysql(void)
os_fast_mutex_unlock(&srv_os_test_mutex); os_fast_mutex_unlock(&srv_os_test_mutex);
#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) os_fast_mutex_free(&srv_os_test_mutex);
os_fast_mutex_free(&srv_os_test_mutex); /* all platforms? */
#endif /* __NETWARE__ */
if (srv_print_verbose_log) { if (srv_print_verbose_log) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
...@@ -1470,6 +1468,8 @@ innobase_shutdown_for_mysql(void) ...@@ -1470,6 +1468,8 @@ innobase_shutdown_for_mysql(void)
/*=============================*/ /*=============================*/
/* out: DB_SUCCESS or error code */ /* out: DB_SUCCESS or error code */
{ {
ulint i;
if (!srv_was_started) { if (!srv_was_started) {
if (srv_is_being_started) { if (srv_is_being_started) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
...@@ -1482,7 +1482,7 @@ innobase_shutdown_for_mysql(void) ...@@ -1482,7 +1482,7 @@ innobase_shutdown_for_mysql(void)
return(DB_SUCCESS); return(DB_SUCCESS);
} }
/* Flush buffer pool to disk, write the current lsn to /* 1. Flush buffer pool to disk, write the current lsn to
the tablespace header(s), and copy all log data to archive */ the tablespace header(s), and copy all log data to archive */
logs_empty_and_mark_files_at_shutdown(); logs_empty_and_mark_files_at_shutdown();
...@@ -1494,30 +1494,77 @@ innobase_shutdown_for_mysql(void) ...@@ -1494,30 +1494,77 @@ innobase_shutdown_for_mysql(void)
srv_conc_n_threads); srv_conc_n_threads);
} }
#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) /* 2. Make all threads created by InnoDB to exit */
/*
TODO: Fix this temporary solution srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS;
We are having a race condition occure with io_handler_thread threads.
When they yield in os_aio_simulated_handle during shutdown, this /* All threads end up waiting for certain events. Put those events
thread was able to free the memory early. to the signaled state. Then the threads will exit themselves in
*/ os_thread_event_wait(). */
os_thread_yield();
for (i = 0; i < 1000; i++) {
/* NOTE: IF YOU CREATE THREADS IN INNODB, YOU MUST EXIT THEM
HERE OR EARLIER */
/* 1. Let the lock timeout thread exit */
os_event_set(srv_lock_timeout_thread_event);
/* 2. srv error monitor thread exits automatically, no need
to do anything here */
/* 3. We wake the master thread so that it exits */
srv_wake_master_thread();
/* 4. Exit the i/o threads */
os_aio_wake_all_threads_at_shutdown();
os_mutex_enter(os_sync_mutex);
if (os_thread_count == 0) {
/* All the threads have exited or are just exiting;
NOTE that the threads may not have completed their
exit yet. Should we use pthread_join() to make sure
they have exited? Now we just sleep 0.1 seconds and
hope that is enough! */
os_mutex_exit(os_sync_mutex);
os_thread_sleep(100000);
break;
}
os_mutex_exit(os_sync_mutex);
os_thread_sleep(100000);
}
if (i == 1000) {
fprintf(stderr,
"InnoDB: Warning: %lu threads created by InnoDB had not exited at shutdown!\n",
os_thread_count);
}
/* 3. Free all InnoDB's own mutexes */
sync_close();
/* 4. Free all OS synchronization primitives (in Windows currently
events are not freed) */
/* TODO: Where should this be called? */
srv_free(); srv_free();
os_sync_free();
/* 5. Free all allocated memory (and the os_fast_mutex created in
ut0mem.c */
/* TODO: Where should this be called? */
srv_general_free();
#endif
/*
TODO: We should exit the i/o-handler and other utility threads
before freeing all memory. Now this can potentially cause a seg
fault!
*/
#if defined(NOT_WORKING_YET) || defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY)
/* NetWare requires this free */
ut_free_all_mem(); ut_free_all_mem();
#endif
if (srv_print_verbose_log) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Shutdown completed\n");
}
return((int) DB_SUCCESS); return((int) DB_SUCCESS);
} }
...@@ -235,8 +235,7 @@ mutex_create_func( ...@@ -235,8 +235,7 @@ mutex_create_func(
mutex->cline = cline; mutex->cline = cline;
/* Check that lock_word is aligned; this is important on Intel */ /* Check that lock_word is aligned; this is important on Intel */
ut_ad(((ulint)(&(mutex->lock_word))) % 4 == 0);
ut_a(((ulint)(&(mutex->lock_word))) % 4 == 0);
/* NOTE! The very first mutexes are not put to the mutex list */ /* NOTE! The very first mutexes are not put to the mutex list */
...@@ -266,11 +265,14 @@ mutex_free( ...@@ -266,11 +265,14 @@ mutex_free(
ut_a(mutex_get_lock_word(mutex) == 0); ut_a(mutex_get_lock_word(mutex) == 0);
ut_a(mutex_get_waiters(mutex) == 0); ut_a(mutex_get_waiters(mutex) == 0);
mutex_enter(&mutex_list_mutex); if (mutex != &mutex_list_mutex && mutex != &sync_thread_mutex) {
UT_LIST_REMOVE(list, mutex_list, mutex); mutex_enter(&mutex_list_mutex);
mutex_exit(&mutex_list_mutex); UT_LIST_REMOVE(list, mutex_list, mutex);
mutex_exit(&mutex_list_mutex);
}
#if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER) #if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER)
os_fast_mutex_free(&(mutex->os_fast_mutex)); os_fast_mutex_free(&(mutex->os_fast_mutex));
...@@ -1230,13 +1232,26 @@ sync_init(void) ...@@ -1230,13 +1232,26 @@ sync_init(void)
} }
/********************************************************************** /**********************************************************************
Frees the resources in synchronization data structures. */ Frees the resources in InnoDB's own synchronization data structures. Use
os_sync_free() after calling this. */
void void
sync_close(void) sync_close(void)
/*===========*/ /*===========*/
{ {
mutex_t* mutex;
sync_array_free(sync_primary_wait_array); sync_array_free(sync_primary_wait_array);
mutex = UT_LIST_GET_FIRST(mutex_list);
while (mutex) {
mutex_free(mutex);
mutex = UT_LIST_GET_FIRST(mutex_list);
}
mutex_free(&mutex_list_mutex);
mutex_free(&sync_thread_mutex);
} }
/*********************************************************************** /***********************************************************************
......
...@@ -190,6 +190,8 @@ ut_free_all_mem(void) ...@@ -190,6 +190,8 @@ ut_free_all_mem(void)
os_fast_mutex_unlock(&ut_list_mutex); os_fast_mutex_unlock(&ut_list_mutex);
ut_a(ut_total_allocated_memory == 0); ut_a(ut_total_allocated_memory == 0);
os_fast_mutex_free(&ut_list_mutex);
} }
/************************************************************************** /**************************************************************************
......
...@@ -436,7 +436,6 @@ int STDCALL mysql_server_init(int argc, char **argv, char **groups) ...@@ -436,7 +436,6 @@ int STDCALL mysql_server_init(int argc, char **argv, char **groups)
(void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_timezone,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST);
......
...@@ -276,3 +276,8 @@ t1 0 a 1 a A 3 NULL NULL YES BTREE ...@@ -276,3 +276,8 @@ t1 0 a 1 a A 3 NULL NULL YES BTREE
t1 0 a 2 b A 300 NULL NULL YES BTREE t1 0 a 2 b A 300 NULL NULL YES BTREE
t1 1 b 1 b A 100 NULL NULL YES BTREE t1 1 b 1 b A 100 NULL NULL YES BTREE
drop table t1; drop table t1;
CREATE TABLE t1 (i int(10), index(i) );
ALTER TABLE t1 DISABLE KEYS;
INSERT DELAYED INTO t1 VALUES(1),(2),(3);
ALTER TABLE t1 ENABLE KEYS;
drop table t1;
...@@ -13,3 +13,15 @@ show tables like 't_'; ...@@ -13,3 +13,15 @@ show tables like 't_';
Tables_in_test (t_) Tables_in_test (t_)
t3 t3
drop table t3; drop table t3;
create table t1 (a int);
select count(*) from T1;
count(*)
0
select count(*) from t1;
count(*)
0
select count(T1.a) from t1;
Unknown table 'T1' in field list
select count(bags.a) from t1 as Bags;
Unknown table 'bags' in field list
drop table t1;
...@@ -501,22 +501,62 @@ drop table t1; ...@@ -501,22 +501,62 @@ drop table t1;
show status like "Qcache_queries_in_cache"; show status like "Qcache_queries_in_cache";
Variable_name Value Variable_name Value
Qcache_queries_in_cache 0 Qcache_queries_in_cache 0
create table t1 (a int);
set GLOBAL query_cache_size=1000; set GLOBAL query_cache_size=1000;
show global variables like "query_cache_size"; show global variables like "query_cache_size";
Variable_name Value Variable_name Value
query_cache_size 0 query_cache_size 0
set GLOBAL query_cache_size=1100; select * from t1;
set GLOBAL query_cache_size=1200; a
set GLOBAL query_cache_size=1300; set GLOBAL query_cache_size=1024;
set GLOBAL query_cache_size=1400; show global variables like "query_cache_size";
set GLOBAL query_cache_size=1500; Variable_name Value
set GLOBAL query_cache_size=1600; query_cache_size 0
set GLOBAL query_cache_size=1700; select * from t1;
set GLOBAL query_cache_size=1800; a
set GLOBAL query_cache_size=1900; set GLOBAL query_cache_size=10240;
show global variables like "query_cache_size";
Variable_name Value
query_cache_size 0
select * from t1;
a
set GLOBAL query_cache_size=20480;
show global variables like "query_cache_size";
Variable_name Value
query_cache_size 0
select * from t1;
a
set GLOBAL query_cache_size=40960;
show global variables like "query_cache_size";
Variable_name Value
query_cache_size 0
select * from t1;
a
set GLOBAL query_cache_size=51200;
show global variables like "query_cache_size";
Variable_name Value
query_cache_size 51200
select * from t1;
a
set GLOBAL query_cache_size=61440;
show global variables like "query_cache_size"; show global variables like "query_cache_size";
Variable_name Value Variable_name Value
query_cache_size 1024 query_cache_size 61440
select * from t1;
a
set GLOBAL query_cache_size=81920;
show global variables like "query_cache_size";
Variable_name Value
query_cache_size 81920
select * from t1;
a
set GLOBAL query_cache_size=102400;
show global variables like "query_cache_size";
Variable_name Value
query_cache_size 102400
select * from t1;
a
drop table t1;
set GLOBAL query_cache_size=1048576; set GLOBAL query_cache_size=1048576;
create table t1 (i int not null); create table t1 (i int not null);
create table t2 (i int not null); create table t2 (i int not null);
......
...@@ -36,6 +36,8 @@ show binlog events from 79 limit 2,1; ...@@ -36,6 +36,8 @@ show binlog events from 79 limit 2,1;
Log_name Pos Event_type Server_id Orig_log_pos Info Log_name Pos Event_type Server_id Orig_log_pos Info
master-bin.001 200 Query 1 200 use test; insert into t1 values (NULL) master-bin.001 200 Query 1 200 use test; insert into t1 values (NULL)
flush logs; flush logs;
create table t5 (a int);
drop table t5;
slave start; slave start;
flush logs; flush logs;
slave stop; slave stop;
...@@ -56,9 +58,11 @@ master-bin.001 1079 Query 1 1079 use test; drop table t1 ...@@ -56,9 +58,11 @@ master-bin.001 1079 Query 1 1079 use test; drop table t1
master-bin.001 1127 Rotate 1 1127 master-bin.002;pos=4 master-bin.001 1127 Rotate 1 1127 master-bin.002;pos=4
show binlog events in 'master-bin.002'; show binlog events in 'master-bin.002';
Log_name Pos Event_type Server_id Orig_log_pos Info Log_name Pos Event_type Server_id Orig_log_pos Info
master-bin.002 4 Query 1 4 use test; create table t1 (n int) master-bin.002 4 Query 1 4 use test; create table t5 (a int)
master-bin.002 62 Query 1 62 use test; insert into t1 values (1) master-bin.002 62 Query 1 62 use test; drop table t5
master-bin.002 122 Query 1 122 use test; drop table t1 master-bin.002 110 Query 1 110 use test; create table t1 (n int)
master-bin.002 168 Query 1 168 use test; insert into t1 values (1)
master-bin.002 228 Query 1 228 use test; drop table t1
show master logs; show master logs;
Log_name Log_name
master-bin.001 master-bin.001
...@@ -79,14 +83,16 @@ slave-bin.001 311 Query 1 311 use test; create table t1 (word char(20) not null) ...@@ -79,14 +83,16 @@ slave-bin.001 311 Query 1 311 use test; create table t1 (word char(20) not null)
slave-bin.001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=581 slave-bin.001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=581
slave-bin.001 1065 Exec_load 1 1056 ;file_id=1 slave-bin.001 1065 Exec_load 1 1056 ;file_id=1
slave-bin.001 1088 Query 1 1079 use test; drop table t1 slave-bin.001 1088 Query 1 1079 use test; drop table t1
slave-bin.001 1136 Rotate 2 1136 slave-bin.002;pos=4 slave-bin.001 1136 Query 1 4 use test; create table t5 (a int)
slave-bin.001 1194 Query 1 62 use test; drop table t5
slave-bin.001 1242 Rotate 2 1242 slave-bin.002;pos=4
show binlog events in 'slave-bin.002' from 4; show binlog events in 'slave-bin.002' from 4;
Log_name Pos Event_type Server_id Orig_log_pos Info Log_name Pos Event_type Server_id Orig_log_pos Info
slave-bin.002 4 Query 1 4 use test; create table t1 (n int) slave-bin.002 4 Query 1 110 use test; create table t1 (n int)
slave-bin.002 62 Query 1 62 use test; insert into t1 values (1) slave-bin.002 62 Query 1 168 use test; insert into t1 values (1)
slave-bin.002 122 Query 1 122 use test; drop table t1 slave-bin.002 122 Query 1 228 use test; drop table t1
show slave status; show slave status;
Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space
127.0.0.1 root MASTER_PORT 1 master-bin.002 170 slave-relay-bin.002 1457 master-bin.002 Yes Yes 0 0 170 1461 127.0.0.1 root MASTER_PORT 1 master-bin.002 276 slave-relay-bin.002 1522 master-bin.002 Yes Yes 0 0 276 1526
show binlog events in 'slave-bin.005' from 4; show binlog events in 'slave-bin.005' from 4;
Error when executing command SHOW BINLOG EVENTS: Could not find target log Error when executing command SHOW BINLOG EVENTS: Could not find target log
...@@ -133,3 +133,12 @@ analyze table t1; ...@@ -133,3 +133,12 @@ analyze table t1;
show keys from t1; show keys from t1;
drop table t1; drop table t1;
#
# Test of ALTER TABLE DELAYED
#
CREATE TABLE t1 (i int(10), index(i) );
ALTER TABLE t1 DISABLE KEYS;
INSERT DELAYED INTO t1 VALUES(1),(2),(3);
ALTER TABLE t1 ENABLE KEYS;
drop table t1;
#
# Test some error conditions
#
drop table if exists t1;
!$1146 insert into t1 values(1);
!$1146 delete from t1;
!$1146 update t1 set a=1;
create table t1 (a int);
!$1054 select count(test.t1.b) from t1;
!$1109 select count(not_existing_database.t1) from t1;
!$1109 select count(not_existing_database.t1.a) from t1;
--error 1044,1146
select count(not_existing_database.t1.a) from not_existing_database.t1;
!$1054 select 1 from t1 order by 2;
!$1054 select 1 from t1 group by 2;
!$1054 select 1 from t1 order by t1.b;
!$1054 select count(*),b from t1;
drop table t1;
#
# Test some error conditions
#
drop table if exists t1;
--error 1146
insert into t1 values(1);
--error 1146
delete from t1;
--error 1146
update t1 set a=1;
#
create table t1 (a int);
--error 1054
select count(test.t1.b) from t1;
--error 1109
select count(not_existing_database.t1) from t1;
--error 1109
select count(not_existing_database.t1.a) from t1;
--error 1044,1146
select count(not_existing_database.t1.a) from not_existing_database.t1;
--error 1054
select 1 from t1 order by 2;
--error 1054
select 1 from t1 group by 2;
--error 1054
select 1 from t1 order by t1.b;
--error 1054
select count(*),b from t1;
drop table t1;
...@@ -12,3 +12,14 @@ ALTER TABLE T2 RENAME T3; ...@@ -12,3 +12,14 @@ ALTER TABLE T2 RENAME T3;
show tables like 't_'; show tables like 't_';
drop table t3; drop table t3;
#
# Test alias
#
create table t1 (a int);
select count(*) from T1;
select count(*) from t1;
--error 1109
select count(T1.a) from t1;
--error 1109
select count(bags.a) from t1 as Bags;
drop table t1;
...@@ -343,18 +343,35 @@ show status like "Qcache_queries_in_cache"; ...@@ -343,18 +343,35 @@ show status like "Qcache_queries_in_cache";
# #
# Test of query cache resizing # Test of query cache resizing
# #
create table t1 (a int);
set GLOBAL query_cache_size=1000; set GLOBAL query_cache_size=1000;
show global variables like "query_cache_size"; show global variables like "query_cache_size";
set GLOBAL query_cache_size=1100; select * from t1;
set GLOBAL query_cache_size=1200; set GLOBAL query_cache_size=1024;
set GLOBAL query_cache_size=1300; show global variables like "query_cache_size";
set GLOBAL query_cache_size=1400; select * from t1;
set GLOBAL query_cache_size=1500; set GLOBAL query_cache_size=10240;
set GLOBAL query_cache_size=1600; show global variables like "query_cache_size";
set GLOBAL query_cache_size=1700; select * from t1;
set GLOBAL query_cache_size=1800; set GLOBAL query_cache_size=20480;
set GLOBAL query_cache_size=1900; show global variables like "query_cache_size";
select * from t1;
set GLOBAL query_cache_size=40960;
show global variables like "query_cache_size";
select * from t1;
set GLOBAL query_cache_size=51200;
show global variables like "query_cache_size";
select * from t1;
set GLOBAL query_cache_size=61440;
show global variables like "query_cache_size";
select * from t1;
set GLOBAL query_cache_size=81920;
show global variables like "query_cache_size"; show global variables like "query_cache_size";
select * from t1;
set GLOBAL query_cache_size=102400;
show global variables like "query_cache_size";
select * from t1;
drop table t1;
# #
# Temporary tables # Temporary tables
......
...@@ -22,10 +22,32 @@ show binlog events from 79 limit 2; ...@@ -22,10 +22,32 @@ show binlog events from 79 limit 2;
show binlog events from 79 limit 2,1; show binlog events from 79 limit 2,1;
flush logs; flush logs;
# We need an extra update before doing save_master_pos.
# Otherwise, an unlikely scenario may occur:
# * When the master's binlog_dump thread reads the end of master-bin.001,
# it send the rotate event which is at this end, plus a fake rotate event
# because it's starting to read a new binlog.
# save_master_pos will record the position of the first of the two rotate
# (because the fake one is not in the master's binlog anyway).
# * Later the slave waits for the position of the first rotate event,
# and it may quickly stop (in 'slave stop') without having received the fake
# one.
# So, depending on a few milliseconds, we end up with 2 rotate events in the
# relay log or one, which influences the output of SHOW SLAVE STATUS, making
# it not predictable and causing random test failures.
# To make it predictable, we do a useless update now, but which has the interest
# of making the slave catch both rotate events.
create table t5 (a int);
drop table t5;
# Sync slave and force it to start on another binary log # Sync slave and force it to start on another binary log
save_master_pos; save_master_pos;
connection slave; connection slave;
# Note that the above 'slave start' will cause a 3rd rotate event (a fake one)
# to go into the relay log (the master always sends a fake one when replication
# starts).
slave start; slave start;
sync_with_master; sync_with_master;
flush logs; flush logs;
......
...@@ -38,20 +38,21 @@ ...@@ -38,20 +38,21 @@
#endif #endif
static int alarm_aborted=1; /* No alarm thread */ static int alarm_aborted=1; /* No alarm thread */
my_bool thr_alarm_inited=0; my_bool thr_alarm_inited= 0;
volatile my_bool alarm_thread_running= 0;
static sig_handler process_alarm_part2(int sig); static sig_handler process_alarm_part2(int sig);
#if !defined(__WIN__) && !defined(__EMX__) && !defined(OS2) #if !defined(__WIN__) && !defined(__EMX__) && !defined(OS2)
static pthread_mutex_t LOCK_alarm; static pthread_mutex_t LOCK_alarm;
static pthread_cond_t COND_alarm;
static sigset_t full_signal_set; static sigset_t full_signal_set;
static QUEUE alarm_queue; static QUEUE alarm_queue;
static uint max_used_alarms=0; static uint max_used_alarms=0;
pthread_t alarm_thread; pthread_t alarm_thread;
#ifdef USE_ALARM_THREAD #ifdef USE_ALARM_THREAD
static pthread_cond_t COND_alarm;
static void *alarm_handler(void *arg); static void *alarm_handler(void *arg);
#define reschedule_alarms() pthread_cond_signal(&COND_alarm) #define reschedule_alarms() pthread_cond_signal(&COND_alarm)
#else #else
...@@ -78,6 +79,7 @@ void init_thr_alarm(uint max_alarms) ...@@ -78,6 +79,7 @@ void init_thr_alarm(uint max_alarms)
compare_ulong,NullS); compare_ulong,NullS);
sigfillset(&full_signal_set); /* Neaded to block signals */ sigfillset(&full_signal_set); /* Neaded to block signals */
pthread_mutex_init(&LOCK_alarm,MY_MUTEX_INIT_FAST); pthread_mutex_init(&LOCK_alarm,MY_MUTEX_INIT_FAST);
pthread_cond_init(&COND_alarm,NULL);
#if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD) #if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD)
#if defined(HAVE_mit_thread) #if defined(HAVE_mit_thread)
sigset(THR_CLIENT_ALARM,thread_alarm); /* int. thread system calls */ sigset(THR_CLIENT_ALARM,thread_alarm); /* int. thread system calls */
...@@ -97,7 +99,6 @@ void init_thr_alarm(uint max_alarms) ...@@ -97,7 +99,6 @@ void init_thr_alarm(uint max_alarms)
{ {
pthread_attr_t thr_attr; pthread_attr_t thr_attr;
pthread_attr_init(&thr_attr); pthread_attr_init(&thr_attr);
pthread_cond_init(&COND_alarm,NULL);
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS); pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&thr_attr,8196); pthread_attr_setstacksize(&thr_attr,8196);
...@@ -383,28 +384,45 @@ static sig_handler process_alarm_part2(int sig __attribute__((unused))) ...@@ -383,28 +384,45 @@ static sig_handler process_alarm_part2(int sig __attribute__((unused)))
void end_thr_alarm(my_bool free_structures) void end_thr_alarm(my_bool free_structures)
{ {
DBUG_ENTER("end_thr_alarm"); DBUG_ENTER("end_thr_alarm");
if (alarm_aborted != 1) if (alarm_aborted != 1) /* If memory not freed */
{ {
pthread_mutex_lock(&LOCK_alarm); pthread_mutex_lock(&LOCK_alarm);
DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements)); DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements));
alarm_aborted= -1; /* mark aborted */ alarm_aborted= -1; /* mark aborted */
if (pthread_equal(pthread_self(),alarm_thread)) if (alarm_queue.elements || (alarm_thread_running && free_structures))
alarm(1); /* Shut down everything soon */ {
else if (pthread_equal(pthread_self(),alarm_thread))
reschedule_alarms(); alarm(1); /* Shut down everything soon */
else
reschedule_alarms();
}
if (free_structures) if (free_structures)
{ {
struct timespec abstime;
/* /*
The following test is just for safety, the caller should not The following test is just for safety, the caller should not
depend on this depend on this
*/ */
DBUG_ASSERT(!alarm_queue.elements); DBUG_ASSERT(!alarm_queue.elements);
/* Wait until alarm thread dies */
set_timespec(abstime, 10); /* Wait up to 10 seconds */
while (alarm_thread_running)
{
int error= pthread_cond_timedwait(&COND_alarm, &LOCK_alarm, &abstime);
if (error == ETIME || error == ETIMEDOUT)
break; /* Don't wait forever */
}
if (!alarm_queue.elements) if (!alarm_queue.elements)
{ {
delete_queue(&alarm_queue); delete_queue(&alarm_queue);
alarm_aborted= 1; alarm_aborted= 1;
pthread_mutex_unlock(&LOCK_alarm); pthread_mutex_unlock(&LOCK_alarm);
pthread_mutex_destroy(&LOCK_alarm); if (!alarm_thread_running) /* Safety */
{
pthread_mutex_destroy(&LOCK_alarm);
pthread_cond_destroy(&COND_alarm);
}
} }
} }
else else
...@@ -490,6 +508,7 @@ static void *alarm_handler(void *arg __attribute__((unused))) ...@@ -490,6 +508,7 @@ static void *alarm_handler(void *arg __attribute__((unused)))
puts("Starting alarm thread"); puts("Starting alarm thread");
#endif #endif
my_thread_init(); my_thread_init();
alarm_thread_running= 1;
pthread_mutex_lock(&LOCK_alarm); pthread_mutex_lock(&LOCK_alarm);
for (;;) for (;;)
{ {
...@@ -514,7 +533,7 @@ static void *alarm_handler(void *arg __attribute__((unused))) ...@@ -514,7 +533,7 @@ static void *alarm_handler(void *arg __attribute__((unused)))
} }
} }
} }
else if (alarm_aborted) else if (alarm_aborted == -1)
break; break;
else if ((error=pthread_cond_wait(&COND_alarm,&LOCK_alarm))) else if ((error=pthread_cond_wait(&COND_alarm,&LOCK_alarm)))
{ {
...@@ -526,6 +545,8 @@ static void *alarm_handler(void *arg __attribute__((unused))) ...@@ -526,6 +545,8 @@ static void *alarm_handler(void *arg __attribute__((unused)))
process_alarm(0); process_alarm(0);
} }
bzero((char*) &alarm_thread,sizeof(alarm_thread)); /* For easy debugging */ bzero((char*) &alarm_thread,sizeof(alarm_thread)); /* For easy debugging */
alarm_thread_running= 0;
pthread_cond_signal(&COND_alarm);
pthread_mutex_unlock(&LOCK_alarm); pthread_mutex_unlock(&LOCK_alarm);
pthread_exit(0); pthread_exit(0);
return 0; /* Impossible */ return 0; /* Impossible */
......
...@@ -1454,7 +1454,11 @@ bool Item_func_like::fix_fields(THD *thd,struct st_table_list *tlist) ...@@ -1454,7 +1454,11 @@ bool Item_func_like::fix_fields(THD *thd,struct st_table_list *tlist)
{ {
const char* tmp = first + 1; const char* tmp = first + 1;
for (; *tmp != wild_many && *tmp != wild_one && *tmp != escape; tmp++) ; for (; *tmp != wild_many && *tmp != wild_one && *tmp != escape; tmp++) ;
#ifdef USE_MB
canDoTurboBM = (tmp == last) && !use_mb(default_charset_info);
#else
canDoTurboBM = tmp == last; canDoTurboBM = tmp == last;
#endif
} }
if (canDoTurboBM) if (canDoTurboBM)
......
...@@ -422,7 +422,6 @@ bool mysql_rename_table(enum db_type base, ...@@ -422,7 +422,6 @@ bool mysql_rename_table(enum db_type base,
const char * old_name, const char * old_name,
const char *new_db, const char *new_db,
const char * new_name); const char * new_name);
bool close_cached_table(THD *thd,TABLE *table);
int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys); int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
int mysql_drop_index(THD *thd, TABLE_LIST *table_list, int mysql_drop_index(THD *thd, TABLE_LIST *table_list,
List<Alter_drop> &drop_list); List<Alter_drop> &drop_list);
...@@ -458,6 +457,7 @@ Field *find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables); ...@@ -458,6 +457,7 @@ Field *find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables);
Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
bool check_grant,bool allow_rowid); bool check_grant,bool allow_rowid);
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
#include <openssl/des.h>
struct st_des_keyblock struct st_des_keyblock
{ {
des_cblock key1, key2, key3; des_cblock key1, key2, key3;
......
...@@ -1520,7 +1520,6 @@ the problem, but since we have already crashed, something is definitely wrong\n\ ...@@ -1520,7 +1520,6 @@ the problem, but since we have already crashed, something is definitely wrong\n\
and this may fail.\n\n"); and this may fail.\n\n");
fprintf(stderr, "key_buffer_size=%lu\n", (ulong) keybuff_size); fprintf(stderr, "key_buffer_size=%lu\n", (ulong) keybuff_size);
fprintf(stderr, "read_buffer_size=%ld\n", global_system_variables.read_buff_size); fprintf(stderr, "read_buffer_size=%ld\n", global_system_variables.read_buff_size);
fprintf(stderr, "sort_buffer_size=%ld\n", thd->variables.sortbuff_size);
fprintf(stderr, "max_used_connections=%ld\n", max_used_connections); fprintf(stderr, "max_used_connections=%ld\n", max_used_connections);
fprintf(stderr, "max_connections=%ld\n", max_connections); fprintf(stderr, "max_connections=%ld\n", max_connections);
fprintf(stderr, "threads_connected=%d\n", thread_count); fprintf(stderr, "threads_connected=%d\n", thread_count);
...@@ -1528,7 +1527,7 @@ and this may fail.\n\n"); ...@@ -1528,7 +1527,7 @@ and this may fail.\n\n");
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %ld K\n\ key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %ld K\n\
bytes of memory\n", ((ulong) keybuff_size + bytes of memory\n", ((ulong) keybuff_size +
(global_system_variables.read_buff_size + (global_system_variables.read_buff_size +
thd->variables.sortbuff_size) * global_system_variables.sortbuff_size) *
max_connections)/ 1024); max_connections)/ 1024);
fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n"); fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n");
...@@ -1557,14 +1556,9 @@ the thread stack. Please read http://www.mysql.com/doc/L/i/Linux.html\n\n", ...@@ -1557,14 +1556,9 @@ the thread stack. Please read http://www.mysql.com/doc/L/i/Linux.html\n\n",
Some pointers may be invalid and cause the dump to abort...\n"); Some pointers may be invalid and cause the dump to abort...\n");
safe_print_str("thd->query", thd->query, 1024); safe_print_str("thd->query", thd->query, 1024);
fprintf(stderr, "thd->thread_id=%ld\n", thd->thread_id); fprintf(stderr, "thd->thread_id=%ld\n", thd->thread_id);
fprintf(stderr, "\n\
Successfully dumped variables, if you ran with --log, take a look at the\n\
details of what thread %ld did to cause the crash. In some cases of really\n\
bad corruption, the values shown above may be invalid.\n\n",
thd->thread_id);
} }
fprintf(stderr, "\ fprintf(stderr, "\
The manual page at http://www.mysql.com/doc/C/r/Crashing.html contains\n\ The manual page at http://www.mysql.com/doc/en/Crashing.html contains\n\
information that should help you find out what is causing the crash.\n"); information that should help you find out what is causing the crash.\n");
fflush(stderr); fflush(stderr);
#endif /* HAVE_STACKTRACE */ #endif /* HAVE_STACKTRACE */
...@@ -1639,6 +1633,7 @@ static void init_signals(void) ...@@ -1639,6 +1633,7 @@ static void init_signals(void)
sigaddset(&set,SIGHUP); sigaddset(&set,SIGHUP);
/* Fix signals if blocked by parents (can happen on Mac OS X) */ /* Fix signals if blocked by parents (can happen on Mac OS X) */
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0; sa.sa_flags = 0;
sa.sa_handler = print_signal_warning; sa.sa_handler = print_signal_warning;
sigaction(SIGTERM, &sa, (struct sigaction*) 0); sigaction(SIGTERM, &sa, (struct sigaction*) 0);
...@@ -2279,7 +2274,7 @@ int main(int argc, char **argv) ...@@ -2279,7 +2274,7 @@ int main(int argc, char **argv)
#endif #endif
/* init_slave() must be called after the thread keys are created */ /* init_slave() must be called after the thread keys are created */
init_slave(); init_slave();
DBUG_ASSERT(current_thd == 0); DBUG_ASSERT(current_thd == 0);
if (opt_bin_log && !server_id) if (opt_bin_log && !server_id)
{ {
...@@ -2307,7 +2302,6 @@ The server will not act as a slave."); ...@@ -2307,7 +2302,6 @@ The server will not act as a slave.");
using_update_log=1; using_update_log=1;
} }
if (opt_bootstrap) if (opt_bootstrap)
{ {
int error=bootstrap(stdin); int error=bootstrap(stdin);
......
...@@ -731,7 +731,7 @@ ulong Query_cache::resize(ulong query_cache_size_arg) ...@@ -731,7 +731,7 @@ ulong Query_cache::resize(ulong query_cache_size_arg)
query_cache_size_arg)); query_cache_size_arg));
free_cache(0); free_cache(0);
query_cache_size= query_cache_size_arg; query_cache_size= query_cache_size_arg;
DBUG_RETURN(init_cache()); DBUG_RETURN(::query_cache_size= init_cache());
} }
...@@ -1282,6 +1282,12 @@ ulong Query_cache::init_cache() ...@@ -1282,6 +1282,12 @@ ulong Query_cache::init_cache()
mem_bin_steps = 1; mem_bin_steps = 1;
mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2; mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2;
prev_size = 0; prev_size = 0;
if (mem_bin_size <= min_allocation_unit)
{
DBUG_PRINT("qcache", ("too small query cache => query cache disabled"));
// TODO here (and above) should be warning in 4.1
goto err;
}
while (mem_bin_size > min_allocation_unit) while (mem_bin_size > min_allocation_unit)
{ {
mem_bin_num += mem_bin_count; mem_bin_num += mem_bin_count;
...@@ -1308,14 +1314,6 @@ ulong Query_cache::init_cache() ...@@ -1308,14 +1314,6 @@ ulong Query_cache::init_cache()
query_cache_size -= additional_data_size; query_cache_size -= additional_data_size;
STRUCT_LOCK(&structure_guard_mutex); STRUCT_LOCK(&structure_guard_mutex);
if (max_mem_bin_size <= min_allocation_unit)
{
DBUG_PRINT("qcache",
(" max bin size (%lu) <= min_allocation_unit => cache disabled",
max_mem_bin_size));
STRUCT_UNLOCK(&structure_guard_mutex);
goto err;
}
if (!(cache = (byte *) if (!(cache = (byte *)
my_malloc_lock(query_cache_size+additional_data_size, MYF(0)))) my_malloc_lock(query_cache_size+additional_data_size, MYF(0))))
......
...@@ -912,58 +912,76 @@ mysql_rename_table(enum db_type base, ...@@ -912,58 +912,76 @@ mysql_rename_table(enum db_type base,
} }
/* /*
close table in this thread and force close + reopen in other threads Force all other threads to stop using the table
This assumes that the calling thread has lock on LOCK_open
Win32 clients must also have a WRITE LOCK on the table ! SYNOPSIS
wait_while_table_is_used()
thd Thread handler
table Table to remove from cache
NOTES
When returning, the table will be unusable for other threads until
the table is closed.
PREREQUISITES
Lock on LOCK_open
Win32 clients must also have a WRITE LOCK on the table !
*/ */
static void safe_remove_from_cache(THD *thd,TABLE *table) static void wait_while_table_is_used(THD *thd,TABLE *table)
{ {
DBUG_ENTER("safe_remove_from_cache"); DBUG_PRINT("enter",("table: %s", table->real_name));
if (table) DBUG_ENTER("wait_while_table_is_used");
{ safe_mutex_assert_owner(&LOCK_open);
DBUG_PRINT("enter",("table: %s", table->real_name));
VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Close all data files
/* Mark all tables that are in use as 'old' */
mysql_lock_abort(thd,table); // end threads waiting on lock
#if defined(USING_TRANSACTIONS) || defined( __WIN__) || defined( __EMX__) || !defined(OS2) VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Close all data files
/* Wait until all there are no other threads that has this table open */ /* Mark all tables that are in use as 'old' */
while (remove_table_from_cache(thd,table->table_cache_key, mysql_lock_abort(thd, table); // end threads waiting on lock
table->real_name))
{ /* Wait until all there are no other threads that has this table open */
dropping_tables++; while (remove_table_from_cache(thd,table->table_cache_key,
(void) pthread_cond_wait(&COND_refresh,&LOCK_open); table->real_name))
dropping_tables--; {
} dropping_tables++;
#else (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
(void) remove_table_from_cache(thd,table->table_cache_key, dropping_tables--;
table->real_name);
#endif
/* When lock on LOCK_open is freed other threads can continue */
pthread_cond_broadcast(&COND_refresh);
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
/*
Close a cached table
SYNOPSIS
clsoe_cached_table()
thd Thread handler
table Table to remove from cache
bool close_cached_table(THD *thd,TABLE *table) NOTES
Function ends by signaling threads waiting for the table to try to
reopen the table.
PREREQUISITES
Lock on LOCK_open
Win32 clients must also have a WRITE LOCK on the table !
*/
static bool close_cached_table(THD *thd, TABLE *table)
{ {
DBUG_ENTER("close_cached_table"); DBUG_ENTER("close_cached_table");
safe_mutex_assert_owner(&LOCK_open);
wait_while_table_is_used(thd,table);
if (table) /* Close lock if this is not got with LOCK TABLES */
if (thd->lock)
{ {
safe_remove_from_cache(thd,table); mysql_unlock_tables(thd, thd->lock);
/* Close lock if this is not got with LOCK TABLES */ thd->lock=0; // Start locked threads
if (thd->lock)
{
mysql_unlock_tables(thd, thd->lock);
thd->lock=0; // Start locked threads
}
/* Close all copies of 'table'. This also frees all LOCK TABLES lock */
thd->open_tables=unlink_open_table(thd,thd->open_tables,table);
} }
/* Close all copies of 'table'. This also frees all LOCK TABLES lock */
thd->open_tables=unlink_open_table(thd,thd->open_tables,table);
/* When lock on LOCK_open is freed other threads can continue */
pthread_cond_broadcast(&COND_refresh);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -1094,10 +1112,13 @@ static int prepare_for_repair(THD* thd, TABLE_LIST *table_list, ...@@ -1094,10 +1112,13 @@ static int prepare_for_repair(THD* thd, TABLE_LIST *table_list,
sprintf(tmp,"%s-%lx_%lx", from, current_pid, thd->thread_id); sprintf(tmp,"%s-%lx_%lx", from, current_pid, thd->thread_id);
pthread_mutex_lock(&LOCK_open); /* If we could open the table, close it */
close_cached_table(thd,table_list->table); if (table_list->table)
pthread_mutex_unlock(&LOCK_open); {
pthread_mutex_lock(&LOCK_open);
close_cached_table(thd, table);
pthread_mutex_unlock(&LOCK_open);
}
if (lock_and_wait_for_table_name(thd,table_list)) if (lock_and_wait_for_table_name(thd,table_list))
{ {
error= -1; error= -1;
...@@ -1494,11 +1515,10 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -1494,11 +1515,10 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
else else
{ {
*fn_ext(new_name)=0; *fn_ext(new_name)=0;
close_cached_table(thd,table); close_cached_table(thd, table);
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_name)) if (mysql_rename_table(old_db_type,db,table_name,new_db,new_name))
error= -1; error= -1;
} }
VOID(pthread_cond_broadcast(&COND_refresh));
VOID(pthread_mutex_unlock(&LOCK_open)); VOID(pthread_mutex_unlock(&LOCK_open));
} }
if (!error) if (!error)
...@@ -1507,12 +1527,18 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -1507,12 +1527,18 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
case LEAVE_AS_IS: case LEAVE_AS_IS:
break; break;
case ENABLE: case ENABLE:
safe_remove_from_cache(thd,table); VOID(pthread_mutex_lock(&LOCK_open));
error= table->file->activate_all_index(thd); wait_while_table_is_used(thd, table);
VOID(pthread_mutex_unlock(&LOCK_open));
error= table->file->activate_all_index(thd);
/* COND_refresh will be signaled in close_thread_tables() */
break; break;
case DISABLE: case DISABLE:
safe_remove_from_cache(thd,table); VOID(pthread_mutex_lock(&LOCK_open));
wait_while_table_is_used(thd, table);
VOID(pthread_mutex_unlock(&LOCK_open));
table->file->deactivate_non_unique_index(HA_POS_ERROR); table->file->deactivate_non_unique_index(HA_POS_ERROR);
/* COND_refresh will be signaled in close_thread_tables() */
break; break;
} }
} }
...@@ -1936,7 +1962,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -1936,7 +1962,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
close the original table at before doing the rename close the original table at before doing the rename
*/ */
table_name=thd->strdup(table_name); // must be saved table_name=thd->strdup(table_name); // must be saved
if (close_cached_table(thd,table)) if (close_cached_table(thd, table))
{ // Aborted { // Aborted
VOID(quick_rm_table(new_db_type,new_db,tmp_name)); VOID(quick_rm_table(new_db_type,new_db,tmp_name));
VOID(pthread_mutex_unlock(&LOCK_open)); VOID(pthread_mutex_unlock(&LOCK_open));
...@@ -1970,7 +1996,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -1970,7 +1996,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
This shouldn't happen. We solve this the safe way by This shouldn't happen. We solve this the safe way by
closing the locked table. closing the locked table.
*/ */
close_cached_table(thd,table); if (table)
close_cached_table(thd,table);
VOID(pthread_mutex_unlock(&LOCK_open)); VOID(pthread_mutex_unlock(&LOCK_open));
goto err; goto err;
} }
...@@ -1980,7 +2007,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -1980,7 +2007,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
Not table locking or alter table with rename Not table locking or alter table with rename
free locks and remove old table free locks and remove old table
*/ */
close_cached_table(thd,table); if (table)
close_cached_table(thd,table);
VOID(quick_rm_table(old_db_type,db,old_name)); VOID(quick_rm_table(old_db_type,db,old_name));
} }
else else
...@@ -2000,7 +2028,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -2000,7 +2028,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (close_data_tables(thd,db,table_name) || if (close_data_tables(thd,db,table_name) ||
reopen_tables(thd,1,0)) reopen_tables(thd,1,0))
{ // This shouldn't happen { // This shouldn't happen
close_cached_table(thd,table); // Remove lock for table if (table)
close_cached_table(thd,table); // Remove lock for table
VOID(pthread_mutex_unlock(&LOCK_open)); VOID(pthread_mutex_unlock(&LOCK_open));
goto err; goto err;
} }
......
...@@ -3397,6 +3397,7 @@ keyword: ...@@ -3397,6 +3397,7 @@ keyword:
| USE_FRM {} | USE_FRM {}
| VARIABLES {} | VARIABLES {}
| WORK_SYM {} | WORK_SYM {}
| X509_SYM {}
| YEAR_SYM {}; | YEAR_SYM {};
/* Option functions */ /* Option functions */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment