Commit 7a543344 authored by monty@narttu.mysql.fi's avatar monty@narttu.mysql.fi

Merge with 4.0.13

parents dad06645 e6cdc816
...@@ -100,7 +100,7 @@ typedef struct st_alarm { ...@@ -100,7 +100,7 @@ typedef struct st_alarm {
#define thr_alarm_init(A) (*(A))=0 #define thr_alarm_init(A) (*(A))=0
#define thr_alarm_in_use(A) (*(A)!= 0) #define thr_alarm_in_use(A) (*(A)!= 0)
void init_thr_alarm(uint max_alarm); void init_thr_alarm(uint max_alarm);
bool thr_alarm(thr_alarm_t *alarmed, uint sec, ALARM *buff); my_bool thr_alarm(thr_alarm_t *alarmed, uint sec, ALARM *buff);
void thr_alarm_kill(pthread_t thread_id); void thr_alarm_kill(pthread_t thread_id);
void thr_end_alarm(thr_alarm_t *alarmed); void thr_end_alarm(thr_alarm_t *alarmed);
void end_thr_alarm(my_bool free_structures); void end_thr_alarm(my_bool free_structures);
......
...@@ -103,7 +103,8 @@ struct com_shm_endpoint_struct{ ...@@ -103,7 +103,8 @@ struct com_shm_endpoint_struct{
the area currently may contain a datagram; the area currently may contain a datagram;
NOTE: automatic event */ NOTE: automatic event */
os_event_t empty; /* this is in the signaled state if the area os_event_t empty; /* this is in the signaled state if the area
currently may be empty; NOTE: automatic event */ currently may be empty; NOTE: automatic
event */
ip_mutex_hdl_t* ip_mutex; /* handle to the interprocess mutex ip_mutex_hdl_t* ip_mutex; /* handle to the interprocess mutex
protecting the shared memory */ protecting the shared memory */
UT_LIST_NODE_T(com_shm_endpoint_t) list; /* If the endpoint struct UT_LIST_NODE_T(com_shm_endpoint_t) list; /* If the endpoint struct
...@@ -793,16 +794,18 @@ com_shm_create_or_open( ...@@ -793,16 +794,18 @@ com_shm_create_or_open(
ut_strcpy(buf + len, (char*)"_IBSHM_EV_NE"), ut_strcpy(buf + len, (char*)"_IBSHM_EV_NE"),
event_ne = os_event_create_auto(buf); event_ne = os_event_create(buf);
ut_ad(event_ne); ut_ad(event_ne);
ut_strcpy(buf + len, (char*)"_IBSHM_EV_EM"), ut_strcpy(buf + len, (char*)"_IBSHM_EV_EM"),
event_em = os_event_create_auto(buf); event_em = os_event_create(buf);
ut_ad(event_em); ut_ad(event_em);
ut_a(0); /* event_ne and event_em should be auto events! */
com_shm_endpoint_set_shm(ep, shm); com_shm_endpoint_set_shm(ep, shm);
com_shm_endpoint_set_map(ep, map); com_shm_endpoint_set_map(ep, map);
......
...@@ -13,13 +13,26 @@ Created 9/6/1995 Heikki Tuuri ...@@ -13,13 +13,26 @@ Created 9/6/1995 Heikki Tuuri
#include "ut0lst.h" #include "ut0lst.h"
#ifdef __WIN__ #ifdef __WIN__
#define os_fast_mutex_t CRITICAL_SECTION #define os_fast_mutex_t CRITICAL_SECTION
typedef HANDLE os_event_t;
typedef HANDLE os_native_event_t;
typedef struct os_event_struct os_event_struct_t;
typedef os_event_struct_t* os_event_t;
struct os_event_struct {
os_native_event_t handle;
/* Windows event */
UT_LIST_NODE_T(os_event_struct_t) os_event_list;
/* list of all created events */
};
#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 struct os_event_struct os_event_struct_t;
typedef os_event_struct_t* os_event_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 */
...@@ -39,16 +52,16 @@ typedef os_mutex_str_t* os_mutex_t; ...@@ -39,16 +52,16 @@ 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 */ /* Mutex protecting counts and the event and OS 'slow' mutex lists */
extern os_mutex_t os_sync_mutex; extern os_mutex_t os_sync_mutex;
/* This is incremented by 1 in os_thread_create and decremented by 1 in /* This is incremented by 1 in os_thread_create and decremented by 1 in
os_thread_exit */ os_thread_exit */
extern ulint os_thread_count; extern ulint os_thread_count;
/* The following are approximate counters for debugging in Unix */
extern ulint os_event_count; extern ulint os_event_count;
extern ulint os_mutex_count; extern ulint os_mutex_count;
extern ulint os_fast_mutex_count;
/************************************************************* /*************************************************************
Initializes global event and OS 'slow' mutex lists. */ Initializes global event and OS 'slow' mutex lists. */
...@@ -57,15 +70,14 @@ void ...@@ -57,15 +70,14 @@ void
os_sync_init(void); os_sync_init(void);
/*==============*/ /*==============*/
/************************************************************* /*************************************************************
Frees created events (not in Windows) and OS 'slow' mutexes. */ Frees created events and OS 'slow' mutexes. */
void void
os_sync_free(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:
just have two states: signaled and nonsignaled. signaled and nonsignaled. The created event is manual reset: it must be reset
The created event is manual reset: it must be reset
explicitly by calling sync_os_reset_event. */ explicitly by calling sync_os_reset_event. */
os_event_t os_event_t
...@@ -74,10 +86,10 @@ os_event_create( ...@@ -74,10 +86,10 @@ os_event_create(
/* out: the event handle */ /* out: the event handle */
char* name); /* in: the name of the event, if NULL char* name); /* in: the name of the event, if NULL
the event is created without a name */ the event is created without a name */
#ifdef __WIN__
/************************************************************* /*************************************************************
Creates an auto-reset event semaphore, i.e., an event Creates an auto-reset event semaphore, i.e., an event which is automatically
which is automatically reset when a single thread is reset when a single thread is released. Works only in Windows. */
released. */
os_event_t os_event_t
os_event_create_auto( os_event_create_auto(
...@@ -85,6 +97,7 @@ os_event_create_auto( ...@@ -85,6 +97,7 @@ os_event_create_auto(
/* out: the event handle */ /* out: the event handle */
char* name); /* in: the name of the event, if NULL char* name); /* in: the name of the event, if NULL
the event is created without a name */ the event is created without a name */
#endif
/************************************************************** /**************************************************************
Sets an event semaphore to the signaled state: lets waiting threads Sets an event semaphore to the signaled state: lets waiting threads
proceed. */ proceed. */
...@@ -120,7 +133,7 @@ os_event_wait( ...@@ -120,7 +133,7 @@ os_event_wait(
os_event_t event); /* in: event to wait */ os_event_t event); /* in: event to wait */
/************************************************************** /**************************************************************
Waits for an event object until it is in the signaled state or Waits for an event object until it is in the signaled state or
a timeout is exceeded. */ a timeout is exceeded. In Unix the timeout is always infinite. */
ulint ulint
os_event_wait_time( os_event_wait_time(
...@@ -131,8 +144,9 @@ os_event_wait_time( ...@@ -131,8 +144,9 @@ os_event_wait_time(
os_event_t event, /* in: event to wait */ os_event_t event, /* in: event to wait */
ulint time); /* in: timeout in microseconds, or ulint time); /* in: timeout in microseconds, or
OS_SYNC_INFINITE_TIME */ OS_SYNC_INFINITE_TIME */
#ifdef __WIN__
/************************************************************** /**************************************************************
Waits for any event in an event array. Returns if even a single Waits for any event in an OS native event array. Returns if even a single
one is signaled or becomes signaled. */ one is signaled or becomes signaled. */
ulint ulint
...@@ -140,14 +154,15 @@ os_event_wait_multiple( ...@@ -140,14 +154,15 @@ os_event_wait_multiple(
/*===================*/ /*===================*/
/* out: index of the event /* out: index of the event
which was signaled */ which was signaled */
ulint n, /* in: number of events in the ulint n, /* in: number of events in the
array */ array */
os_event_t* event_array); /* in: pointer to an array of event os_native_event_t* native_event_array);
/* in: pointer to an array of event
handles */ handles */
#endif
/************************************************************* /*************************************************************
Creates an operating system mutex semaphore. Creates an operating system mutex semaphore. Because these are slow, the
Because these are slow, the mutex semaphore of the database mutex semaphore of InnoDB itself (mutex_t) should be used where possible. */
itself (sync_mutex_t) should be used where possible. */
os_mutex_t os_mutex_t
os_mutex_create( os_mutex_create(
......
...@@ -44,4 +44,3 @@ os_fast_mutex_trylock( ...@@ -44,4 +44,3 @@ os_fast_mutex_trylock(
#endif #endif
#endif #endif
} }
...@@ -65,7 +65,9 @@ os_thread_pf( ...@@ -65,7 +65,9 @@ os_thread_pf(
/******************************************************************** /********************************************************************
Creates a new thread of execution. The execution starts from Creates a new thread of execution. The execution starts from
the function given. The start function takes a void* parameter the function given. The start function takes a void* parameter
and returns a ulint. */ and returns a ulint.
NOTE: We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
os_thread_t os_thread_t
os_thread_create( os_thread_create(
......
...@@ -80,6 +80,8 @@ struct os_aio_slot_struct{ ...@@ -80,6 +80,8 @@ struct os_aio_slot_struct{
which pending aio operation was which pending aio operation was
completed */ completed */
#ifdef WIN_ASYNC_IO #ifdef WIN_ASYNC_IO
os_event_t event; /* event object we need in the
OVERLAPPED struct */
OVERLAPPED control; /* Windows control block for the OVERLAPPED control; /* Windows control block for the
aio request */ aio request */
#elif defined(POSIX_ASYNC_IO) #elif defined(POSIX_ASYNC_IO)
...@@ -107,11 +109,14 @@ struct os_aio_array_struct{ ...@@ -107,11 +109,14 @@ struct os_aio_array_struct{
ulint n_reserved;/* Number of reserved slots in the ulint n_reserved;/* Number of reserved slots in the
aio array outside the ibuf segment */ aio array outside the ibuf segment */
os_aio_slot_t* slots; /* Pointer to the slots in the array */ os_aio_slot_t* slots; /* Pointer to the slots in the array */
os_event_t* events; /* Pointer to an array of event handles #ifdef __WIN__
where we copied the handles from slots, os_native_event_t* native_events;
in the same order. This can be used in /* Pointer to an array of OS native event
WaitForMultipleObjects; used only in handles where we copied the handles from
slots, in the same order. This can be used
in WaitForMultipleObjects; used only in
Windows */ Windows */
#endif
}; };
/* Array of events used in simulated aio */ /* Array of events used in simulated aio */
...@@ -296,7 +301,7 @@ os_file_handle_error( ...@@ -296,7 +301,7 @@ os_file_handle_error(
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 */ const char* operation)/* in: operation */
{ {
ulint err; ulint err;
...@@ -338,8 +343,8 @@ os_file_handle_error( ...@@ -338,8 +343,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: System call %s.\n", operation);
fprintf(stderr, "InnoDB: Cannot continue operation.\n"); fprintf(stderr, "InnoDB: Cannot continue operation.\n");
fflush(stderr); fflush(stderr);
...@@ -422,9 +427,8 @@ try_again: ...@@ -422,9 +427,8 @@ try_again:
*success = FALSE; *success = FALSE;
retry = os_file_handle_error(file, name, retry = os_file_handle_error(file, name,
create_mode == OS_FILE_OPEN ? create_mode == OS_FILE_OPEN ?
"open" : "create"); "open" : "create");
if (retry) { if (retry) {
goto try_again; goto try_again;
} }
...@@ -465,10 +469,8 @@ try_again: ...@@ -465,10 +469,8 @@ try_again:
*success = FALSE; *success = FALSE;
retry = os_file_handle_error(file, name, retry = os_file_handle_error(file, name,
create_mode == OS_FILE_OPEN ? create_mode == OS_FILE_OPEN ?
"open" : "create"); "open" : "create");
if (retry) { if (retry) {
goto try_again; goto try_again;
} }
...@@ -576,9 +578,8 @@ try_again: ...@@ -576,9 +578,8 @@ try_again:
*success = FALSE; *success = FALSE;
retry = os_file_handle_error(file, name, retry = os_file_handle_error(file, name,
create_mode == OS_FILE_OPEN ? create_mode == OS_FILE_OPEN ?
"open" : "create"); "open" : "create");
if (retry) { if (retry) {
goto try_again; goto try_again;
} }
...@@ -625,9 +626,8 @@ try_again: ...@@ -625,9 +626,8 @@ try_again:
*success = FALSE; *success = FALSE;
retry = os_file_handle_error(file, name, retry = os_file_handle_error(file, name,
create_mode == OS_FILE_OPEN ? create_mode == OS_FILE_OPEN ?
"open" : "create"); "open" : "create");
if (retry) { if (retry) {
goto try_again; goto try_again;
} }
...@@ -1319,19 +1319,22 @@ os_aio_array_create( ...@@ -1319,19 +1319,22 @@ os_aio_array_create(
array->n_segments = n_segments; array->n_segments = n_segments;
array->n_reserved = 0; array->n_reserved = 0;
array->slots = ut_malloc(n * sizeof(os_aio_slot_t)); array->slots = ut_malloc(n * sizeof(os_aio_slot_t));
array->events = ut_malloc(n * sizeof(os_event_t)); #ifdef __WIN__
array->native_events = ut_malloc(n * sizeof(os_native_event_t));
#endif
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
slot = os_aio_array_get_nth_slot(array, i); slot = os_aio_array_get_nth_slot(array, i);
slot->pos = i; slot->pos = i;
slot->reserved = FALSE; slot->reserved = FALSE;
#ifdef WIN_ASYNC_IO #ifdef WIN_ASYNC_IO
slot->event = os_event_create(NULL);
over = &(slot->control); over = &(slot->control);
over->hEvent = os_event_create(NULL); over->hEvent = slot->event->handle;
*((array->events) + i) = over->hEvent; *((array->native_events) + i) = over->hEvent;
#endif #endif
} }
...@@ -1429,7 +1432,7 @@ os_aio_array_wake_win_aio_at_shutdown( ...@@ -1429,7 +1432,7 @@ os_aio_array_wake_win_aio_at_shutdown(
for (i = 0; i < array->n_slots; i++) { for (i = 0; i < array->n_slots; i++) {
os_event_set(*(array->events + i)); os_event_set((array->slots + i)->event);
} }
} }
#endif #endif
...@@ -1689,7 +1692,7 @@ loop: ...@@ -1689,7 +1692,7 @@ loop:
control = &(slot->control); control = &(slot->control);
control->Offset = (DWORD)offset; control->Offset = (DWORD)offset;
control->OffsetHigh = (DWORD)offset_high; control->OffsetHigh = (DWORD)offset_high;
os_event_reset(control->hEvent); os_event_reset(slot->event);
#elif defined(POSIX_ASYNC_IO) #elif defined(POSIX_ASYNC_IO)
...@@ -1747,7 +1750,7 @@ os_aio_array_free_slot( ...@@ -1747,7 +1750,7 @@ os_aio_array_free_slot(
} }
#ifdef WIN_ASYNC_IO #ifdef WIN_ASYNC_IO
os_event_reset(slot->control.hEvent); os_event_reset(slot->event);
#endif #endif
os_mutex_exit(array->mutex); os_mutex_exit(array->mutex);
} }
...@@ -1872,7 +1875,7 @@ os_aio( ...@@ -1872,7 +1875,7 @@ os_aio(
offset where to read or write */ offset where to read or write */
ulint offset_high, /* in: most significant 32 bits of ulint offset_high, /* in: most significant 32 bits of
offset */ offset */
ulint n, /* in: number of bytes to read or write */ ulint n, /* in: number of bytes to read or write */
void* message1,/* in: messages for the aio handler (these void* message1,/* in: messages for the aio handler (these
can be used to identify a completed aio can be used to identify a completed aio
operation); if mode is OS_AIO_SYNC, these operation); if mode is OS_AIO_SYNC, these
...@@ -1916,7 +1919,8 @@ os_aio( ...@@ -1916,7 +1919,8 @@ os_aio(
wait in the Windows case. */ wait in the Windows case. */
if (type == OS_FILE_READ) { if (type == OS_FILE_READ) {
return(os_file_read(file, buf, offset, offset_high, n)); return(os_file_read(file, buf, offset,
offset_high, n));
} }
ut_a(type == OS_FILE_WRITE); ut_a(type == OS_FILE_WRITE);
...@@ -1994,8 +1998,7 @@ try_again: ...@@ -1994,8 +1998,7 @@ try_again:
#ifdef WIN_ASYNC_IO #ifdef WIN_ASYNC_IO
if (os_aio_use_native_aio) { if (os_aio_use_native_aio) {
if ((ret && len == n) if ((ret && len == n)
|| (!ret && GetLastError() == ERROR_IO_PENDING)) { || (!ret && GetLastError() == ERROR_IO_PENDING)) {
/* aio was queued successfully! */ /* aio was queued successfully! */
if (mode == OS_AIO_SYNC) { if (mode == OS_AIO_SYNC) {
...@@ -2025,8 +2028,8 @@ try_again: ...@@ -2025,8 +2028,8 @@ try_again:
os_aio_array_free_slot(array, slot); os_aio_array_free_slot(array, slot);
retry = os_file_handle_error(file, name, "aio"); retry = os_file_handle_error(file, name,
type == OS_FILE_READ ? "aio read" : "aio write");
if (retry) { if (retry) {
goto try_again; goto try_again;
...@@ -2091,15 +2094,15 @@ os_aio_windows_handle( ...@@ -2091,15 +2094,15 @@ os_aio_windows_handle(
n = array->n_slots / array->n_segments; n = array->n_slots / array->n_segments;
if (array == os_aio_sync_array) { if (array == os_aio_sync_array) {
srv_io_thread_op_info[orig_seg] = "wait Windows aio for 1 page"; srv_io_thread_op_info[orig_seg] =
"wait Windows aio for 1 page";
ut_ad(pos < array->n_slots); os_event_wait(os_aio_array_get_nth_slot(array, pos)->event);
os_event_wait(array->events[pos]);
i = pos; i = pos;
} else { } else {
srv_io_thread_op_info[orig_seg] = srv_io_thread_op_info[orig_seg] =
"wait Windows aio"; "wait Windows aio";
i = os_event_wait_multiple(n, (array->events) + segment * n); i = os_event_wait_multiple(n,
(array->native_events) + segment * n);
} }
os_mutex_enter(array->mutex); os_mutex_enter(array->mutex);
...@@ -2124,7 +2127,7 @@ os_aio_windows_handle( ...@@ -2124,7 +2127,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, "aio"); os_file_handle_error(slot->file, slot->name, "Windows aio");
ret_val = FALSE; ret_val = FALSE;
} }
......
...@@ -32,24 +32,23 @@ struct os_mutex_struct{ ...@@ -32,24 +32,23 @@ struct os_mutex_struct{
/* list of all 'slow' OS mutexes created */ /* list of all 'slow' OS mutexes created */
}; };
/* Mutex protecting the thread count and the lists of OS mutexes /* Mutex protecting counts and the lists of OS mutexes and events */
and events */
os_mutex_t os_sync_mutex; os_mutex_t os_sync_mutex;
ibool os_sync_mutex_inited = FALSE; ibool os_sync_mutex_inited = FALSE;
/* This is incremented by 1 in os_thread_create and decremented by 1 in /* This is incremented by 1 in os_thread_create and decremented by 1 in
os_thread_exit */ os_thread_exit */
ulint os_thread_count = 0; ulint os_thread_count = 0;
/* The list of all events created (not in Windows) */ /* The list of all events created */
UT_LIST_BASE_NODE_T(os_event_struct_t) os_event_list; UT_LIST_BASE_NODE_T(os_event_struct_t) os_event_list;
/* The list of all OS 'slow' mutexes */ /* The list of all OS 'slow' mutexes */
UT_LIST_BASE_NODE_T(os_mutex_str_t) os_mutex_list; 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_event_count = 0; ulint os_mutex_count = 0;
ulint os_mutex_count = 0; ulint os_fast_mutex_count = 0;
/************************************************************* /*************************************************************
...@@ -68,7 +67,7 @@ os_sync_init(void) ...@@ -68,7 +67,7 @@ os_sync_init(void)
} }
/************************************************************* /*************************************************************
Frees created events (not in Windows) and OS 'slow' mutexes. */ Frees created events and OS 'slow' mutexes. */
void void
os_sync_free(void) os_sync_free(void)
...@@ -89,6 +88,12 @@ os_sync_free(void) ...@@ -89,6 +88,12 @@ os_sync_free(void)
mutex = UT_LIST_GET_FIRST(os_mutex_list); mutex = UT_LIST_GET_FIRST(os_mutex_list);
while (mutex) { while (mutex) {
if (mutex == os_sync_mutex) {
/* Set the flag to FALSE so that we do not try to
reserve os_sync_mutex any more in remaining freeing
operations in shutdown */
os_sync_mutex_inited = FALSE;
}
os_mutex_free(mutex); os_mutex_free(mutex);
...@@ -97,10 +102,9 @@ os_sync_free(void) ...@@ -97,10 +102,9 @@ 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
just have two states: signaled and nonsignaled. states: signaled and nonsignaled. The created event is manual reset: it
The created event is manual reset: it must be reset must be reset explicitly by calling sync_os_reset_event. */
explicitly by calling sync_os_reset_event. */
os_event_t os_event_t
os_event_create( os_event_create(
...@@ -112,20 +116,18 @@ os_event_create( ...@@ -112,20 +116,18 @@ os_event_create(
#ifdef __WIN__ #ifdef __WIN__
os_event_t event; os_event_t event;
event = CreateEvent(NULL, /* No security attributes */ event = ut_malloc(sizeof(struct os_event_struct));
event->handle = CreateEvent(NULL,/* No security attributes */
TRUE, /* Manual reset */ TRUE, /* Manual reset */
FALSE, /* Initial state nonsignaled */ FALSE, /* Initial state nonsignaled */
name); name);
if (!event) { if (!event->handle) {
fprintf(stderr, fprintf(stderr,
"InnoDB: Could not create a Windows event semaphore; Windows error %lu\n", "InnoDB: Could not create a Windows event semaphore; Windows error %lu\n",
(ulint)GetLastError()); (ulint)GetLastError());
} }
#else /* Unix */
ut_a(event);
return(event);
#else
os_event_t event; os_event_t event;
UT_NOT_USED(name); UT_NOT_USED(name);
...@@ -141,7 +143,9 @@ os_event_create( ...@@ -141,7 +143,9 @@ os_event_create(
ut_a(0 == pthread_cond_init(&(event->cond_var), NULL)); ut_a(0 == pthread_cond_init(&(event->cond_var), NULL));
#endif #endif
event->is_set = FALSE; event->is_set = FALSE;
#endif /* __WIN__ */
/* Put to the list of events */
os_mutex_enter(os_sync_mutex); os_mutex_enter(os_sync_mutex);
UT_LIST_ADD_FIRST(os_event_list, os_event_list, event); UT_LIST_ADD_FIRST(os_event_list, os_event_list, event);
...@@ -151,13 +155,12 @@ os_event_create( ...@@ -151,13 +155,12 @@ os_event_create(
os_mutex_exit(os_sync_mutex); os_mutex_exit(os_sync_mutex);
return(event); return(event);
#endif
} }
#ifdef __WIN__
/************************************************************* /*************************************************************
Creates an auto-reset event semaphore, i.e., an event Creates an auto-reset event semaphore, i.e., an event which is automatically
which is automatically reset when a single thread is reset when a single thread is released. Works only in Windows. */
released. */
os_event_t os_event_t
os_event_create_auto( os_event_create_auto(
...@@ -166,26 +169,33 @@ os_event_create_auto( ...@@ -166,26 +169,33 @@ os_event_create_auto(
char* name) /* in: the name of the event, if NULL char* name) /* in: the name of the event, if NULL
the event is created without a name */ the event is created without a name */
{ {
#ifdef __WIN__
os_event_t event; os_event_t event;
event = CreateEvent(NULL, /* No security attributes */ event = ut_malloc(sizeof(struct os_event_struct));
event->handle = CreateEvent(NULL,/* No security attributes */
FALSE, /* Auto-reset */ FALSE, /* Auto-reset */
FALSE, /* Initial state nonsignaled */ FALSE, /* Initial state nonsignaled */
name); name);
ut_a(event);
return(event); if (!event->handle) {
#else fprintf(stderr,
/* Does nothing in Posix because we do not need this with MySQL */ "InnoDB: Could not create a Windows auto event semaphore; Windows error %lu\n",
(ulint)GetLastError());
}
UT_NOT_USED(name); /* Put to the list of events */
os_mutex_enter(os_sync_mutex);
ut_a(0); UT_LIST_ADD_FIRST(os_event_list, os_event_list, event);
return(NULL); os_event_count++;
#endif
os_mutex_exit(os_sync_mutex);
return(event);
} }
#endif
/************************************************************** /**************************************************************
Sets an event semaphore to the signaled state: lets waiting threads Sets an event semaphore to the signaled state: lets waiting threads
...@@ -198,7 +208,7 @@ os_event_set( ...@@ -198,7 +208,7 @@ os_event_set(
{ {
#ifdef __WIN__ #ifdef __WIN__
ut_a(event); ut_a(event);
ut_a(SetEvent(event)); ut_a(SetEvent(event->handle));
#else #else
ut_a(event); ut_a(event);
...@@ -227,7 +237,7 @@ os_event_reset( ...@@ -227,7 +237,7 @@ os_event_reset(
#ifdef __WIN__ #ifdef __WIN__
ut_a(event); ut_a(event);
ut_a(ResetEvent(event)); ut_a(ResetEvent(event->handle));
#else #else
ut_a(event); ut_a(event);
...@@ -255,12 +265,14 @@ os_event_free( ...@@ -255,12 +265,14 @@ os_event_free(
#ifdef __WIN__ #ifdef __WIN__
ut_a(event); ut_a(event);
ut_a(CloseHandle(event)); ut_a(CloseHandle(event->handle));
#else #else
ut_a(event); ut_a(event);
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)));
#endif
/* Remove from the list of events */
os_mutex_enter(os_sync_mutex); os_mutex_enter(os_sync_mutex);
...@@ -271,7 +283,6 @@ os_event_free( ...@@ -271,7 +283,6 @@ os_event_free(
os_mutex_exit(os_sync_mutex); os_mutex_exit(os_sync_mutex);
ut_free(event); ut_free(event);
#endif
} }
/************************************************************** /**************************************************************
...@@ -291,7 +302,7 @@ os_event_wait( ...@@ -291,7 +302,7 @@ os_event_wait(
ut_a(event); ut_a(event);
/* Specify an infinite time limit for waiting */ /* Specify an infinite time limit for waiting */
err = WaitForSingleObject(event, INFINITE); err = WaitForSingleObject(event->handle, INFINITE);
ut_a(err == WAIT_OBJECT_0); ut_a(err == WAIT_OBJECT_0);
...@@ -324,7 +335,7 @@ loop: ...@@ -324,7 +335,7 @@ loop:
/************************************************************** /**************************************************************
Waits for an event object until it is in the signaled state or Waits for an event object until it is in the signaled state or
a timeout is exceeded. */ a timeout is exceeded. In Unix the timeout is always infinite. */
ulint ulint
os_event_wait_time( os_event_wait_time(
...@@ -341,9 +352,9 @@ os_event_wait_time( ...@@ -341,9 +352,9 @@ os_event_wait_time(
ut_a(event); ut_a(event);
if (time != OS_SYNC_INFINITE_TIME) { if (time != OS_SYNC_INFINITE_TIME) {
err = WaitForSingleObject(event, time / 1000); err = WaitForSingleObject(event->handle, time / 1000);
} else { } else {
err = WaitForSingleObject(event, INFINITE); err = WaitForSingleObject(event->handle, INFINITE);
} }
if (err == WAIT_OBJECT_0) { if (err == WAIT_OBJECT_0) {
...@@ -367,8 +378,9 @@ os_event_wait_time( ...@@ -367,8 +378,9 @@ os_event_wait_time(
#endif #endif
} }
#ifdef __WIN__
/************************************************************** /**************************************************************
Waits for any event in an event array. Returns if even a single Waits for any event in an OS native event array. Returns if even a single
one is signaled or becomes signaled. */ one is signaled or becomes signaled. */
ulint ulint
...@@ -376,18 +388,18 @@ os_event_wait_multiple( ...@@ -376,18 +388,18 @@ os_event_wait_multiple(
/*===================*/ /*===================*/
/* out: index of the event /* out: index of the event
which was signaled */ which was signaled */
ulint n, /* in: number of events in the ulint n, /* in: number of events in the
array */ array */
os_event_t* event_array) /* in: pointer to an array of event os_native_event_t* native_event_array)
/* in: pointer to an array of event
handles */ handles */
{ {
#ifdef __WIN__
DWORD index; DWORD index;
ut_a(event_array); ut_a(native_event_array);
ut_a(n > 0); ut_a(n > 0);
index = WaitForMultipleObjects(n, event_array, index = WaitForMultipleObjects(n, native_event_array,
FALSE, /* Wait for any 1 event */ FALSE, /* Wait for any 1 event */
INFINITE); /* Infinite wait time INFINITE); /* Infinite wait time
limit */ limit */
...@@ -399,21 +411,12 @@ os_event_wait_multiple( ...@@ -399,21 +411,12 @@ os_event_wait_multiple(
} }
return(index - WAIT_OBJECT_0); return(index - WAIT_OBJECT_0);
#else
ut_a(n == 0);
/* In Posix we can only wait for a single event */
os_event_wait(*event_array);
return(0);
#endif
} }
#endif
/************************************************************* /*************************************************************
Creates an operating system mutex semaphore. Creates an operating system mutex semaphore. Because these are slow, the
Because these are slow, the mutex semaphore of the database mutex semaphore of InnoDB itself (mutex_t) should be used where possible. */
itself (sync_mutex_t) should be used where possible. */
os_mutex_t os_mutex_t
os_mutex_create( os_mutex_create(
...@@ -430,50 +433,35 @@ os_mutex_create( ...@@ -430,50 +433,35 @@ os_mutex_create(
FALSE, /* Initial state: no owner */ FALSE, /* Initial state: no owner */
name); name);
ut_a(mutex); ut_a(mutex);
mutex_str = ut_malloc(sizeof(os_mutex_str_t));
mutex_str->handle = mutex;
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);
#else #else
os_fast_mutex_t* os_mutex; os_fast_mutex_t* mutex;
os_mutex_t mutex_str; os_mutex_t mutex_str;
UT_NOT_USED(name); UT_NOT_USED(name);
os_mutex = ut_malloc(sizeof(os_fast_mutex_t)); mutex = ut_malloc(sizeof(os_fast_mutex_t));
os_fast_mutex_init(os_mutex);
os_fast_mutex_init(mutex);
#endif
mutex_str = ut_malloc(sizeof(os_mutex_str_t)); mutex_str = ut_malloc(sizeof(os_mutex_str_t));
mutex_str->handle = os_mutex; mutex_str->handle = mutex;
mutex_str->count = 0; mutex_str->count = 0;
if (os_sync_mutex_inited) { if (os_sync_mutex_inited) {
/* When creating os_sync_mutex itself we cannot reserve it */
os_mutex_enter(os_sync_mutex); os_mutex_enter(os_sync_mutex);
} }
UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str); UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str);
os_mutex_count++;
if (os_sync_mutex_inited) { if (os_sync_mutex_inited) {
os_mutex_exit(os_sync_mutex); os_mutex_exit(os_sync_mutex);
} }
return(mutex_str); return(mutex_str);
#endif
} }
/************************************************************** /**************************************************************
...@@ -513,21 +501,14 @@ os_mutex_exit( ...@@ -513,21 +501,14 @@ os_mutex_exit(
/*==========*/ /*==========*/
os_mutex_t mutex) /* in: mutex to release */ os_mutex_t mutex) /* in: mutex to release */
{ {
#ifdef __WIN__
ut_a(mutex); ut_a(mutex);
ut_a(mutex->count == 1); ut_a(mutex->count == 1);
(mutex->count)--; (mutex->count)--;
#ifdef __WIN__
ut_a(ReleaseMutex(mutex->handle)); ut_a(ReleaseMutex(mutex->handle));
#else #else
ut_a(mutex);
ut_a(mutex->count == 1);
(mutex->count)--;
os_fast_mutex_unlock(mutex->handle); os_fast_mutex_unlock(mutex->handle);
#endif #endif
} }
...@@ -540,25 +521,25 @@ os_mutex_free( ...@@ -540,25 +521,25 @@ os_mutex_free(
/*==========*/ /*==========*/
os_mutex_t mutex) /* in: mutex to free */ os_mutex_t mutex) /* in: mutex to free */
{ {
#ifdef __WIN__
ut_a(mutex); ut_a(mutex);
os_mutex_enter(os_sync_mutex); if (os_sync_mutex_inited) {
os_mutex_enter(os_sync_mutex);
}
UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex); UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex);
os_mutex_count--;
os_mutex_exit(os_sync_mutex); if (os_sync_mutex_inited) {
os_mutex_exit(os_sync_mutex);
}
#ifdef __WIN__
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);
...@@ -583,8 +564,19 @@ os_fast_mutex_init( ...@@ -583,8 +564,19 @@ 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
if (os_sync_mutex_inited) {
/* When creating os_sync_mutex itself (in Unix) we cannot
reserve it */
os_mutex_enter(os_sync_mutex);
}
os_fast_mutex_count++;
if (os_sync_mutex_inited) {
os_mutex_exit(os_sync_mutex);
}
} }
/************************************************************** /**************************************************************
...@@ -631,6 +623,17 @@ os_fast_mutex_free( ...@@ -631,6 +623,17 @@ 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
if (os_sync_mutex_inited) {
/* When freeing the last mutexes, we have
already freed os_sync_mutex */
os_mutex_enter(os_sync_mutex);
}
os_fast_mutex_count--;
if (os_sync_mutex_inited) {
os_mutex_exit(os_sync_mutex);
}
} }
...@@ -186,6 +186,10 @@ os_thread_exit( ...@@ -186,6 +186,10 @@ os_thread_exit(
void* exit_value) /* in: exit value; in Windows this void* void* exit_value) /* in: exit value; in Windows this void*
is cast as a DWORD */ is cast as a DWORD */
{ {
#ifdef UNIV_DEBUG_THREAD_CREATION
printf("A thread exits.\n");
printf("Thread id %lu\n", os_thread_pf(os_thread_get_curr_id()));
#endif
os_mutex_enter(os_sync_mutex); os_mutex_enter(os_sync_mutex);
os_thread_count--; os_thread_count--;
os_mutex_exit(os_sync_mutex); os_mutex_exit(os_sync_mutex);
......
...@@ -868,6 +868,7 @@ srv_release_max_if_no_queries(void) ...@@ -868,6 +868,7 @@ srv_release_max_if_no_queries(void)
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
} }
#ifdef notdefined
/*********************************************************************** /***********************************************************************
Releases one utility thread if no queries are active and Releases one utility thread if no queries are active and
the high-water mark 2 for the utility is exceeded. */ the high-water mark 2 for the utility is exceeded. */
...@@ -902,7 +903,6 @@ srv_release_one_if_no_queries(void) ...@@ -902,7 +903,6 @@ srv_release_one_if_no_queries(void)
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
} }
#ifdef notdefined
/*********************************************************************** /***********************************************************************
Decrements the utility meter by the value given and suspends the calling Decrements the utility meter by the value given and suspends the calling
thread, which must be an utility thread of the type given, if necessary. */ thread, which must be an utility thread of the type given, if necessary. */
...@@ -1012,6 +1012,8 @@ srv_communication_init( ...@@ -1012,6 +1012,8 @@ srv_communication_init(
ut_a(ret == 0); ut_a(ret == 0);
} }
#ifdef notdefined
/************************************************************************* /*************************************************************************
Implements the recovery utility. */ Implements the recovery utility. */
...@@ -1072,6 +1074,7 @@ srv_purge_thread( ...@@ -1072,6 +1074,7 @@ srv_purge_thread(
return(0); return(0);
} }
#endif /* notdefined */
/************************************************************************* /*************************************************************************
Creates the utility threads. */ Creates the utility threads. */
...@@ -1102,6 +1105,7 @@ srv_create_utility_threads(void) ...@@ -1102,6 +1105,7 @@ srv_create_utility_threads(void)
ut_a(thread); */ ut_a(thread); */
} }
#ifdef notdefined
/************************************************************************* /*************************************************************************
Implements the communication threads. */ Implements the communication threads. */
static static
...@@ -1151,6 +1155,7 @@ srv_com_thread( ...@@ -1151,6 +1155,7 @@ srv_com_thread(
return(0); return(0);
} }
#endif
/************************************************************************* /*************************************************************************
Creates the communication threads. */ Creates the communication threads. */
...@@ -1171,6 +1176,7 @@ srv_create_com_threads(void) ...@@ -1171,6 +1176,7 @@ srv_create_com_threads(void)
} }
} }
#ifdef notdefined
/************************************************************************* /*************************************************************************
Implements the worker threads. */ Implements the worker threads. */
static static
...@@ -1215,6 +1221,7 @@ srv_worker_thread( ...@@ -1215,6 +1221,7 @@ srv_worker_thread(
return(0); return(0);
} }
#endif
/************************************************************************* /*************************************************************************
Creates the worker threads. */ Creates the worker threads. */
...@@ -2490,6 +2497,10 @@ srv_lock_timeout_and_monitor_thread( ...@@ -2490,6 +2497,10 @@ srv_lock_timeout_and_monitor_thread(
char* buf; char* buf;
ulint i; ulint i;
#ifdef UNIV_DEBUG_THREAD_CREATION
printf("Lock timeout thread starts\n");
printf("Thread id %lu\n", os_thread_pf(os_thread_get_curr_id()));
#endif
UT_NOT_USED(arg); UT_NOT_USED(arg);
srv_last_monitor_time = time(NULL); srv_last_monitor_time = time(NULL);
last_table_monitor_time = time(NULL); last_table_monitor_time = time(NULL);
...@@ -2630,6 +2641,10 @@ loop: ...@@ -2630,6 +2641,10 @@ loop:
exit_func: exit_func:
srv_lock_timeout_and_monitor_active = FALSE; srv_lock_timeout_and_monitor_active = FALSE;
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
os_thread_exit(NULL);
#ifndef __WIN__ #ifndef __WIN__
return(NULL); return(NULL);
#else #else
...@@ -2655,6 +2670,10 @@ srv_error_monitor_thread( ...@@ -2655,6 +2670,10 @@ srv_error_monitor_thread(
ulint cnt = 0; ulint cnt = 0;
UT_NOT_USED(arg); UT_NOT_USED(arg);
#ifdef UNIV_DEBUG_THREAD_CREATION
printf("Error monitor thread starts\n");
printf("Thread id %lu\n", os_thread_pf(os_thread_get_curr_id()));
#endif
loop: loop:
srv_error_monitor_active = TRUE; srv_error_monitor_active = TRUE;
...@@ -2691,6 +2710,9 @@ loop: ...@@ -2691,6 +2710,9 @@ loop:
srv_error_monitor_active = FALSE; srv_error_monitor_active = FALSE;
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
os_thread_exit(NULL); os_thread_exit(NULL);
#ifndef __WIN__ #ifndef __WIN__
...@@ -2771,6 +2793,10 @@ srv_master_thread( ...@@ -2771,6 +2793,10 @@ srv_master_thread(
UT_NOT_USED(arg); UT_NOT_USED(arg);
#ifdef UNIV_DEBUG_THREAD_CREATION
printf("Master thread starts\n");
printf("Thread id %lu\n", os_thread_pf(os_thread_get_curr_id()));
#endif
srv_main_thread_process_no = os_proc_get_number(); srv_main_thread_process_no = os_proc_get_number();
srv_main_thread_id = os_thread_pf(os_thread_get_curr_id()); srv_main_thread_id = os_thread_pf(os_thread_get_curr_id());
...@@ -3006,6 +3032,15 @@ background_loop: ...@@ -3006,6 +3032,15 @@ background_loop:
n_tables_to_drop = row_drop_tables_for_mysql_in_background(); n_tables_to_drop = row_drop_tables_for_mysql_in_background();
if (n_tables_to_drop > 0) {
/* Do not monopolize the CPU even if there are tables waiting
in the background drop queue. (It is essentially a bug if
MySQL tries to drop a table while there are still open handles
to it and we had to put it to the background drop queue.) */
os_thread_sleep(100000);
}
srv_main_thread_op_info = (char*)"purging"; srv_main_thread_op_info = (char*)"purging";
if (srv_fast_shutdown && srv_shutdown_state > 0) { if (srv_fast_shutdown && srv_shutdown_state > 0) {
...@@ -3144,6 +3179,13 @@ suspend_thread: ...@@ -3144,6 +3179,13 @@ suspend_thread:
goto loop; goto loop;
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit.
The thread actually never comes here because it is exited in an
os_event_wait(). */
os_thread_exit(NULL);
#ifndef __WIN__ #ifndef __WIN__
return(NULL); return(NULL);
#else #else
......
...@@ -414,8 +414,10 @@ io_handler_thread( ...@@ -414,8 +414,10 @@ io_handler_thread(
segment = *((ulint*)arg); segment = *((ulint*)arg);
/* printf("Io handler thread %lu starts\n", segment); */ #ifdef UNIV_DEBUG_THREAD_CREATION
printf("Io handler thread %lu starts\n", segment);
printf("Thread id %lu\n", os_thread_pf(os_thread_get_curr_id()));
#endif
for (i = 0;; i++) { for (i = 0;; i++) {
fil_aio_wait(segment); fil_aio_wait(segment);
...@@ -424,6 +426,13 @@ io_handler_thread( ...@@ -424,6 +426,13 @@ io_handler_thread(
mutex_exit(&ios_mutex); mutex_exit(&ios_mutex);
} }
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit.
The thread actually never comes here because it is exited in an
os_event_wait(). */
os_thread_exit(NULL);
#ifndef __WIN__ #ifndef __WIN__
return(NULL); return(NULL);
#else #else
...@@ -1585,21 +1594,32 @@ innobase_shutdown_for_mysql(void) ...@@ -1585,21 +1594,32 @@ innobase_shutdown_for_mysql(void)
os_thread_count); os_thread_count);
} }
/* 3. Free all InnoDB's own mutexes */ /* 3. Free all InnoDB's own mutexes and the os_fast_mutexes inside
them */
sync_close(); sync_close();
/* 4. Free all OS synchronization primitives (in Windows currently /* 4. Free the os_conc_mutex and all os_events and os_mutexes */
events are not freed) */
srv_free(); srv_free();
os_sync_free(); os_sync_free();
/* 5. Free all allocated memory (and the os_fast_mutex created in /* 5. Free all allocated memory and the os_fast_mutex created in
ut0mem.c */ ut0mem.c */
ut_free_all_mem(); ut_free_all_mem();
if (os_thread_count != 0
|| os_event_count != 0
|| os_mutex_count != 0
|| os_fast_mutex_count != 0) {
fprintf(stderr,
"InnoDB: Warning: some resources were not cleaned up in shutdown:\n"
"InnoDB: threads %lu, events %lu, os_mutexes %lu, os_fast_mutexes %lu\n",
os_thread_count, os_event_count, os_mutex_count,
os_fast_mutex_count);
}
if (srv_print_verbose_log) { if (srv_print_verbose_log) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Shutdown completed\n"); fprintf(stderr, " InnoDB: Shutdown completed\n");
......
...@@ -64,7 +64,7 @@ concat_ws(NULL,'a') concat_ws(',',NULL,'') ...@@ -64,7 +64,7 @@ concat_ws(NULL,'a') concat_ws(',',NULL,'')
NULL NULL
select concat_ws(',','',NULL,'a'); select concat_ws(',','',NULL,'a');
concat_ws(',','',NULL,'a') concat_ws(',','',NULL,'a')
a ,a
SELECT CONCAT('"',CONCAT_WS('";"',repeat('a',60),repeat('b',60),repeat('c',60),repeat('d',100)), '"'); SELECT CONCAT('"',CONCAT_WS('";"',repeat('a',60),repeat('b',60),repeat('c',60),repeat('d',100)), '"');
CONCAT('"',CONCAT_WS('";"',repeat('a',60),repeat('b',60),repeat('c',60),repeat('d',100)), '"') CONCAT('"',CONCAT_WS('";"',repeat('a',60),repeat('b',60),repeat('c',60),repeat('d',100)), '"')
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc";"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc";"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
......
...@@ -22,3 +22,9 @@ day id category name ...@@ -22,3 +22,9 @@ day id category name
drop table t1; drop table t1;
drop table t2; drop table t2;
drop table t3; drop table t3;
create table t1(a int, b int, unique(b));
insert into t1 values(1,10);
load data infile '../../std_data/rpl_loaddata.dat' into table t1;
show status like 'slave_running';
Variable_name Value
Slave_running OFF
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
# #
# check replication of load data for temporary tables with additional parameters # check replication of load data for temporary tables with additional parameters
# #
# check if duplicate entries trigger an error (they should unless IGNORE or
# REPLACE was used on the master) (bug 571).
source include/master-slave.inc; source include/master-slave.inc;
create table t1(a int not null auto_increment, b int, primary key(a) ); create table t1(a int not null auto_increment, b int, primary key(a) );
...@@ -27,7 +30,21 @@ connection master; ...@@ -27,7 +30,21 @@ connection master;
drop table t1; drop table t1;
drop table t2; drop table t2;
drop table t3; drop table t3;
create table t1(a int, b int, unique(b));
save_master_pos; save_master_pos;
connection slave; connection slave;
sync_with_master; sync_with_master;
insert into t1 values(1,10);
connection master;
load data infile '../../std_data/rpl_loaddata.dat' into table t1;
save_master_pos;
connection slave;
# don't sync_with_master because the slave SQL thread should be stopped because
# of the error so MASTER_POS_WAIT() will not return; just sleep and hope the
# slave SQL thread will have had time to stop.
sleep 1;
show status like 'slave_running';
...@@ -122,12 +122,24 @@ void init_thr_alarm(uint max_alarms) ...@@ -122,12 +122,24 @@ void init_thr_alarm(uint max_alarms)
/* /*
Request alarm after sec seconds. Request alarm after sec seconds.
A pointer is returned with points to a non-zero int when the alarm has been
given. This can't be called from the alarm-handling thread. SYNOPSIS
Returns 0 if no more alarms are allowed (aborted by process) thr_alarm()
alrm Pointer to alarm detection
alarm_data Structure to store in alarm queue
NOTES
This function can't be called from the alarm-handling thread.
RETURN VALUES
0 ok
1 If no more alarms are allowed (aborted by process)
Stores in first argument a pointer to a non-zero int which is set to 0
when the alarm has been given
*/ */
bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
{ {
ulong now; ulong now;
sigset_t old_mask; sigset_t old_mask;
...@@ -209,7 +221,7 @@ void thr_end_alarm(thr_alarm_t *alarmed) ...@@ -209,7 +221,7 @@ void thr_end_alarm(thr_alarm_t *alarmed)
ALARM *alarm_data; ALARM *alarm_data;
sigset_t old_mask; sigset_t old_mask;
uint i; uint i;
bool found=0; my_bool found=0;
DBUG_ENTER("thr_end_alarm"); DBUG_ENTER("thr_end_alarm");
pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask); pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
...@@ -230,10 +242,9 @@ void thr_end_alarm(thr_alarm_t *alarmed) ...@@ -230,10 +242,9 @@ void thr_end_alarm(thr_alarm_t *alarmed)
DBUG_ASSERT(!*alarmed || found); DBUG_ASSERT(!*alarmed || found);
if (!found) if (!found)
{ {
#ifdef MAIN if (*alarmed)
printf("Warning: Didn't find alarm %lx in queue of %d alarms\n", fprintf(stderr,"Warning: Didn't find alarm %lx in queue of %d alarms\n",
(long) *alarmed, alarm_queue.elements); (long) *alarmed, alarm_queue.elements);
#endif
DBUG_PRINT("warning",("Didn't find alarm %lx in queue\n", DBUG_PRINT("warning",("Didn't find alarm %lx in queue\n",
(long) *alarmed)); (long) *alarmed));
} }
......
...@@ -131,9 +131,11 @@ static void innobase_print_error(const char* db_errpfx, char* buffer); ...@@ -131,9 +131,11 @@ static void innobase_print_error(const char* db_errpfx, char* buffer);
/********************************************************************** /**********************************************************************
Releases possible search latch and InnoDB thread FIFO ticket. These should 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 be released at each SQL statement end, and also when mysqld passes the
also in the middle of an SQL statement. */ control to the client. It does no harm to release these also in the middle
of an SQL statement. */
static static
inline
void void
innobase_release_stat_resources( innobase_release_stat_resources(
/*============================*/ /*============================*/
...@@ -914,6 +916,11 @@ innobase_commit_low( ...@@ -914,6 +916,11 @@ innobase_commit_low(
trx_t* trx) /* in: transaction handle */ trx_t* trx) /* in: transaction handle */
{ {
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
if (trx->conc_state == TRX_NOT_STARTED) {
return;
}
/* TODO: Guilhem should check if master_log_name, pending /* TODO: Guilhem should check if master_log_name, pending
etc. are right if the master log gets rotated! Possible bug here. etc. are right if the master log gets rotated! Possible bug here.
Comment by Heikki March 4, 2003. */ Comment by Heikki March 4, 2003. */
...@@ -929,11 +936,13 @@ innobase_commit_low( ...@@ -929,11 +936,13 @@ innobase_commit_low(
)); ));
} }
#endif /* HAVE_REPLICATION */ #endif /* HAVE_REPLICATION */
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
} }
/********************************************************************* /*********************************************************************
Commits a transaction in an InnoDB database. */ Commits a transaction in an InnoDB database or marks an SQL statement
ended. */
int int
innobase_commit( innobase_commit(
...@@ -951,29 +960,45 @@ innobase_commit( ...@@ -951,29 +960,45 @@ innobase_commit(
DBUG_ENTER("innobase_commit"); DBUG_ENTER("innobase_commit");
DBUG_PRINT("trans", ("ending transaction")); DBUG_PRINT("trans", ("ending transaction"));
trx = check_trx_exists(thd); /* The flag thd->transaction.all.innodb_active_trans is set to 1
in ::external_lock and ::start_stmt, and it is only set to 0 in
a commit or a rollback. If it is 0 we know there cannot be resources
to be freed and we can return immediately. */
if (trx->auto_inc_lock) { if (thd->transaction.all.innodb_active_trans == 0) {
/* If we had reserved the auto-inc lock for DBUG_RETURN(0);
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) { trx = check_trx_exists(thd);
if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle
|| (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) {
innobase_commit_low(trx); innobase_commit_low(trx);
thd->transaction.all.innodb_active_trans=0;
thd->transaction.all.innodb_active_trans = 0;
} else {
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);
}
/* Store the current undo_no of the transaction so that we
know where to roll back if we have to roll back the next
SQL statement */
trx_mark_sql_stat_end(trx);
} }
/* Release possible statement level resources */ /* Release a possible FIFO ticket and search latch */
innobase_release_stat_resources(trx); innobase_release_stat_resources(trx);
trx_mark_sql_stat_end(trx);
/* Tell InnoDB server that there might be work for /* Tell the InnoDB server that there might be work for utility
utility threads: */ threads: */
srv_active_wake_master_thread(); srv_active_wake_master_thread();
...@@ -1044,7 +1069,7 @@ innobase_commit_complete( ...@@ -1044,7 +1069,7 @@ innobase_commit_complete(
} }
/********************************************************************* /*********************************************************************
Rolls back a transaction in an InnoDB database. */ Rolls back a transaction or the latest SQL statement in an InnoDB database. */
int int
innobase_rollback( innobase_rollback(
...@@ -1085,11 +1110,9 @@ innobase_rollback( ...@@ -1085,11 +1110,9 @@ innobase_rollback(
srv_conc_exit_innodb(trx); srv_conc_exit_innodb(trx);
/* Release possible statement level resources */ /* Release a possible FIFO ticket and search latch */
innobase_release_stat_resources(trx); innobase_release_stat_resources(trx);
trx_mark_sql_stat_end(trx);
DBUG_RETURN(convert_error_code_to_mysql(error, NULL)); DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
} }
...@@ -3032,6 +3055,8 @@ create_index( ...@@ -3032,6 +3055,8 @@ create_index(
KEY* key; KEY* key;
KEY_PART_INFO* key_part; KEY_PART_INFO* key_part;
ulint ind_type; ulint ind_type;
ulint col_type;
ulint prefix_len;
ulint i; ulint i;
DBUG_ENTER("create_index"); DBUG_ENTER("create_index");
...@@ -3059,6 +3084,27 @@ create_index( ...@@ -3059,6 +3084,27 @@ create_index(
for (i = 0; i < n_fields; i++) { for (i = 0; i < n_fields; i++) {
key_part = key->key_part + i; key_part = key->key_part + i;
if (key_part->length != key_part->field->pack_length()) {
prefix_len = key_part->length;
col_type = get_innobase_type_from_mysql_type(
key_part->field);
if (col_type == DATA_INT
|| col_type == DATA_FLOAT
|| col_type == DATA_DOUBLE
|| col_type == DATA_DECIMAL) {
fprintf(stderr,
"InnoDB: error: MySQL is trying to create a column prefix index field\n"
"InnoDB: on an inappropriate data type %lu. Table name %s, column name %s.\n",
col_type, table_name,
key_part->field->field_name);
prefix_len = 0;
}
} else {
prefix_len = 0;
}
/* We assume all fields should be sorted in ascending /* We assume all fields should be sorted in ascending
order, hence the '0': */ order, hence the '0': */
dict_mem_index_add_field(index, dict_mem_index_add_field(index,
...@@ -3600,8 +3646,7 @@ ha_innobase::records_in_range( ...@@ -3600,8 +3646,7 @@ ha_innobase::records_in_range(
/************************************************************************* /*************************************************************************
Gives an UPPER BOUND to the number of rows in a table. This is used in Gives an UPPER BOUND to the number of rows in a table. This is used in
filesort.cc and its better if the upper bound hold. filesort.cc. */
*/
ha_rows ha_rows
ha_innobase::estimate_number_of_rows(void) ha_innobase::estimate_number_of_rows(void)
...@@ -3636,11 +3681,11 @@ ha_innobase::estimate_number_of_rows(void) ...@@ -3636,11 +3681,11 @@ ha_innobase::estimate_number_of_rows(void)
/* Calculate a minimum length for a clustered index record and from /* Calculate a minimum length for a clustered index record and from
that an upper bound for the number of rows. Since we only calculate that an upper bound for the number of rows. Since we only calculate
new statistics in row0mysql.c when a tablehas grown new statistics in row0mysql.c when a table has grown by a threshold
by a threshold factor, we must add a safety factor 2 in front factor, we must add a safety factor 2 in front of the formula below. */
of the formula below. */
estimate = 2 * local_data_file_length / dict_index_calc_min_rec_len(index); estimate = 2 * local_data_file_length /
dict_index_calc_min_rec_len(index);
prebuilt->trx->op_info = (char*)""; prebuilt->trx->op_info = (char*)"";
...@@ -3667,27 +3712,36 @@ ha_innobase::scan_time() ...@@ -3667,27 +3712,36 @@ ha_innobase::scan_time()
return((double) (prebuilt->table->stat_clustered_index_size)); return((double) (prebuilt->table->stat_clustered_index_size));
} }
/* /**********************************************************************
Calculate the time it takes to read a set of ranges through and index Calculate the time it takes to read a set of ranges through an index
This enables us to optimise reads for clustered indexes. This enables us to optimise reads for clustered indexes. */
*/
double ha_innobase::read_time(uint index, uint ranges, ha_rows rows) double
ha_innobase::read_time(
/*===================*/
/* out: estimated time measured in disk seeks */
uint index, /* in: key number */
uint ranges, /* in: how many ranges */
ha_rows rows) /* in: estimated number of rows in the ranges */
{ {
ha_rows total_rows; ha_rows total_rows;
double time_for_scan; double time_for_scan;
if (index != table->primary_key)
return handler::read_time(index, ranges, rows); // Not clustered if (index != table->primary_key)
if (rows <= 2) return handler::read_time(index, ranges, rows); // Not clustered
return (double) rows;
/* if (rows <= 2)
Assume that the read is proportional to scan time for all rows + one return (double) rows;
seek per range.
*/ /* Assume that the read time is proportional to the scan time for all
time_for_scan= scan_time(); rows + at most one seek per range. */
if ((total_rows= estimate_number_of_rows()) < rows)
return time_for_scan; time_for_scan= scan_time();
return (ranges + (double) rows / (double) total_rows * time_for_scan);
if ((total_rows= estimate_number_of_rows()) < rows)
return time_for_scan;
return (ranges + (double) rows / (double) total_rows * time_for_scan);
} }
/************************************************************************* /*************************************************************************
...@@ -4040,10 +4094,10 @@ ha_innobase::reset(void) ...@@ -4040,10 +4094,10 @@ ha_innobase::reset(void)
} }
/********************************************************************** /**********************************************************************
Inside LOCK TABLES MySQL will not call external_lock() between SQL MySQL calls this function at the start of each SQL statement. Inside LOCK
statements. It will call this function at the start of each SQL statement. TABLES the ::external_lock method does not work to mark SQL statement
Note also a spacial case: if a temporary table is created inside LOCK borders. Note also a special case: if a temporary table is created inside
TABLES, MySQL has not called external_lock() at all on that table. */ LOCK TABLES, MySQL has not called external_lock() at all on that table. */
int int
ha_innobase::start_stmt( ha_innobase::start_stmt(
...@@ -4058,8 +4112,14 @@ ha_innobase::start_stmt( ...@@ -4058,8 +4112,14 @@ ha_innobase::start_stmt(
trx = prebuilt->trx; trx = prebuilt->trx;
/* Here we release the search latch and the InnoDB thread FIFO ticket
if they were reserved. They should have been released already at the
end of the previous statement, but because inside LOCK TABLES the
lock count method does not work to mark the end of a SELECT statement,
that may not be the case. We MUST release the search latch before an
INSERT, for example. */
innobase_release_stat_resources(trx); innobase_release_stat_resources(trx);
trx_mark_sql_stat_end(trx);
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
&& trx->read_view) { && trx->read_view) {
...@@ -4082,7 +4142,8 @@ ha_innobase::start_stmt( ...@@ -4082,7 +4142,8 @@ ha_innobase::start_stmt(
prebuilt->select_lock_type = LOCK_X; prebuilt->select_lock_type = LOCK_X;
} }
/* Set the MySQL flag to mark that there is an active transaction */
thd->transaction.all.innodb_active_trans = 1; thd->transaction.all.innodb_active_trans = 1;
return(0); return(0);
...@@ -4146,17 +4207,20 @@ ha_innobase::external_lock( ...@@ -4146,17 +4207,20 @@ ha_innobase::external_lock(
} }
if (lock_type != F_UNLCK) { if (lock_type != F_UNLCK) {
if (trx->n_mysql_tables_in_use == 0) { /* MySQL is setting a new table lock */
trx_mark_sql_stat_end(trx);
}
/* Set the MySQL flag to mark that there is an active
transaction */
thd->transaction.all.innodb_active_trans = 1; thd->transaction.all.innodb_active_trans = 1;
trx->n_mysql_tables_in_use++; trx->n_mysql_tables_in_use++;
prebuilt->mysql_has_locked = TRUE; prebuilt->mysql_has_locked = TRUE;
trx->isolation_level = innobase_map_isolation_level( if (trx->n_mysql_tables_in_use == 1) {
trx->isolation_level = innobase_map_isolation_level(
(enum_tx_isolation) (enum_tx_isolation)
thd->variables.tx_isolation); thd->variables.tx_isolation);
}
if (trx->isolation_level == TRX_ISO_SERIALIZABLE if (trx->isolation_level == TRX_ISO_SERIALIZABLE
&& prebuilt->select_lock_type == LOCK_NONE) { && prebuilt->select_lock_type == LOCK_NONE) {
...@@ -4172,37 +4236,44 @@ ha_innobase::external_lock( ...@@ -4172,37 +4236,44 @@ ha_innobase::external_lock(
trx->mysql_n_tables_locked++; trx->mysql_n_tables_locked++;
} }
} else {
trx->n_mysql_tables_in_use--;
prebuilt->mysql_has_locked = FALSE;
auto_inc_counter_for_this_stat = 0;
if (trx->n_mysql_tables_in_use == 0) { DBUG_RETURN(error);
}
trx->mysql_n_tables_locked = 0; /* MySQL is releasing a table lock */
prebuilt->used_in_HANDLER = FALSE; trx->n_mysql_tables_in_use--;
prebuilt->mysql_has_locked = FALSE;
auto_inc_counter_for_this_stat = 0;
/* Here we release the search latch and InnoDB /* If the MySQL lock count drops to zero we know that the current SQL
thread FIFO ticket if they were reserved. */ statement has ended */
innobase_release_stat_resources(trx); if (trx->n_mysql_tables_in_use == 0) {
trx->mysql_n_tables_locked = 0;
prebuilt->used_in_HANDLER = FALSE;
if (!(thd->options
& (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
if (thd->transaction.all.innodb_active_trans != 0) {
innobase_commit(thd, trx);
}
} else {
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
&& trx->read_view) { && trx->read_view) {
/* At low transaction isolation levels we let /* At low transaction isolation levels we let
each consistent read set its own snapshot */ each consistent read set its own snapshot */
read_view_close_for_mysql(trx); read_view_close_for_mysql(trx);
} }
if (!(thd->options
& (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
innobase_commit(thd, trx);
}
} }
/* Here we release the search latch and the InnoDB thread FIFO
ticket if they were reserved. */
innobase_release_stat_resources(trx);
} }
DBUG_RETURN(error); DBUG_RETURN(error);
...@@ -4513,4 +4584,3 @@ ha_innobase::get_auto_increment() ...@@ -4513,4 +4584,3 @@ ha_innobase::get_auto_increment()
} }
#endif /* HAVE_INNOBASE_DB */ #endif /* HAVE_INNOBASE_DB */
...@@ -218,8 +218,12 @@ void ha_close_connection(THD* thd) ...@@ -218,8 +218,12 @@ void ha_close_connection(THD* thd)
} }
/* /*
This is used to commit or rollback a single statement depending This is used to commit or rollback a single statement depending on the value
on the value of error of error. Note that if the autocommit is on, then the following call inside
InnoDB will commit or rollback the whole transaction (= the statement). The
autocommit mechanism built into InnoDB is based on counting locks, but if
the user has used LOCK TABLES then that mechanism does not know to do the
commit.
*/ */
int ha_autocommit_or_rollback(THD *thd, int error) int ha_autocommit_or_rollback(THD *thd, int error)
......
...@@ -515,18 +515,18 @@ String *Item_func_concat_ws::val_str(String *str) ...@@ -515,18 +515,18 @@ String *Item_func_concat_ws::val_str(String *str)
str->length(0); // QQ; Should be removed str->length(0); // QQ; Should be removed
res=str; res=str;
// Skip until non-null and non-empty argument is found. // Skip until non-null argument is found.
// If not, return the empty string // If not, return the empty string
for (i=0; i < arg_count; i++) for (i=0; i < arg_count; i++)
if ((res= args[i]->val_str(str)) && res->length()) if ((res= args[i]->val_str(str)))
break; break;
if (i == arg_count) if (i == arg_count)
return &empty_string; return &empty_string;
for (i++; i < arg_count ; i++) for (i++; i < arg_count ; i++)
{ {
if (!(res2= args[i]->val_str(use_as_buff)) || !res2->length()) if (!(res2= args[i]->val_str(use_as_buff)))
continue; // Skip NULL and empty string continue; // Skip NULL
if (res->length() + sep_str->length() + res2->length() > if (res->length() + sep_str->length() + res2->length() >
current_thd->variables.max_allowed_packet) current_thd->variables.max_allowed_packet)
......
...@@ -1573,9 +1573,27 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, ...@@ -1573,9 +1573,27 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
else else
{ {
char llbuff[22]; char llbuff[22];
enum enum_duplicates handle_dup = DUP_IGNORE; enum enum_duplicates handle_dup;
if (sql_ex.opt_flags & REPLACE_FLAG) if (sql_ex.opt_flags & REPLACE_FLAG)
handle_dup= DUP_REPLACE; handle_dup= DUP_REPLACE;
else if (sql_ex.opt_flags & IGNORE_FLAG)
handle_dup= DUP_IGNORE;
else
/*
Note that when replication is running fine, if it was DUP_ERROR on the
master then we could choose DUP_IGNORE here, because if DUP_ERROR
suceeded on master, and data is identical on the master and slave,
then there should be no uniqueness errors on slave, so DUP_IGNORE is
the same as DUP_ERROR. But in the unlikely case of uniqueness errors
(because the data on the master and slave happen to be different (user
error or bug), we want LOAD DATA to print an error message on the
slave to discover the problem.
If reading from net (a 3.23 master), mysql_load() will change this
to DUP_IGNORE.
*/
handle_dup= DUP_ERROR;
sql_exchange ex((char*)fname, sql_ex.opt_flags & DUMPFILE_FLAG); sql_exchange ex((char*)fname, sql_ex.opt_flags & DUMPFILE_FLAG);
String field_term(sql_ex.field_term,sql_ex.field_term_len,log_cs); String field_term(sql_ex.field_term,sql_ex.field_term_len,log_cs);
String enclosed(sql_ex.enclosed,sql_ex.enclosed_len,log_cs); String enclosed(sql_ex.enclosed,sql_ex.enclosed_len,log_cs);
...@@ -1637,12 +1655,19 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, ...@@ -1637,12 +1655,19 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
close_thread_tables(thd); close_thread_tables(thd);
if (thd->query_error) if (thd->query_error)
{ {
int sql_error= thd->net.last_errno; /* this err/sql_errno code is copy-paste from send_error() */
if (!sql_error) const char *err;
sql_error= ER_UNKNOWN_ERROR; int sql_errno;
slave_print_error(rli,sql_error, if ((err=thd->net.last_error)[0])
"Error '%s' running LOAD DATA INFILE", sql_errno=thd->net.last_errno;
ER_SAFE(sql_error)); else
{
sql_errno=ER_UNKNOWN_ERROR;
err=ER(sql_errno);
}
slave_print_error(rli,sql_errno,
"Error '%s' running load data infile",
err);
free_root(&thd->mem_root,0); free_root(&thd->mem_root,0);
return 1; return 1;
} }
......
...@@ -267,7 +267,7 @@ ulong slave_net_timeout; ...@@ -267,7 +267,7 @@ ulong slave_net_timeout;
ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0; ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
ulong query_cache_size=0; ulong query_cache_size=0;
ulong com_stat[(uint) SQLCOM_END], com_other; ulong com_stat[(uint) SQLCOM_END], com_other;
ulong bytes_sent, bytes_received; ulong bytes_sent, bytes_received, net_big_packet_count;
ulong refresh_version=1L,flush_version=1L; /* Increments on each reload */ ulong refresh_version=1L,flush_version=1L; /* Increments on each reload */
ulong query_id, long_query_count, aborted_threads, aborted_connects; ulong query_id, long_query_count, aborted_threads, aborted_connects;
ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size; ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size;
...@@ -987,14 +987,21 @@ static void set_ports() ...@@ -987,14 +987,21 @@ static void set_ports()
static void set_user(const char *user) static void set_user(const char *user)
{ {
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__) #if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
struct passwd *ent; struct passwd *ent;
uid_t user_id= geteuid();
// don't bother if we aren't superuser // don't bother if we aren't superuser
if (geteuid()) if (user_id)
{ {
if (user) if (user)
fprintf(stderr, {
"Warning: One can only use the --user switch if running as root\n"); /* Don't give a warning, if real user is same as given with --user */
struct passwd *user_info= getpwnam(user);
if (!user_info || user_id != user_info->pw_uid)
fprintf(stderr,
"Warning: One can only use the --user switch if running as root\n");
}
return; return;
} }
else if (!user) else if (!user)
......
...@@ -73,11 +73,13 @@ void sql_print_error(const char *format,...); ...@@ -73,11 +73,13 @@ void sql_print_error(const char *format,...);
#define USE_QUERY_CACHE #define USE_QUERY_CACHE
extern uint test_flags; extern uint test_flags;
extern void query_cache_insert(NET *net, const char *packet, ulong length); extern void query_cache_insert(NET *net, const char *packet, ulong length);
extern ulong bytes_sent, bytes_received; extern ulong bytes_sent, bytes_received, net_big_packet_count;
extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received; extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
#else #else
#undef statistic_add #undef statistic_add
#undef statistic_increment
#define statistic_add(A,B,C) #define statistic_add(A,B,C)
#define statistic_increment(A,B)
#endif #endif
#define TEST_BLOCKING 8 #define TEST_BLOCKING 8
...@@ -562,7 +564,7 @@ static my_bool net_safe_read(NET *net, char *buff, uint32 length, ...@@ -562,7 +564,7 @@ static my_bool net_safe_read(NET *net, char *buff, uint32 length,
if ((tmp=vio_read(net->vio,(char*) net->buff, length)) <= 0) if ((tmp=vio_read(net->vio,(char*) net->buff, length)) <= 0)
{ {
my_bool interrupted = vio_should_retry(net->vio); my_bool interrupted = vio_should_retry(net->vio);
if (!thr_got_alarm(&alarmed) && interrupted) if (!thr_got_alarm(alarmed) && interrupted)
{ /* Probably in MIT threads */ { /* Probably in MIT threads */
if (retry_count++ < net->retry_count) if (retry_count++ < net->retry_count)
continue; continue;
...@@ -596,10 +598,13 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed, ...@@ -596,10 +598,13 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
DBUG_ENTER("my_net_skip_rest"); DBUG_ENTER("my_net_skip_rest");
DBUG_PRINT("enter",("bytes_to_skip: %u", (uint) remain)); DBUG_PRINT("enter",("bytes_to_skip: %u", (uint) remain));
if (!thr_alarm_in_use(&alarmed)) /* The following is good for debugging */
statistic_increment(net_big_packet_count,&LOCK_bytes_received);
if (!thr_alarm_in_use(alarmed))
{ {
my_bool old_mode; my_bool old_mode;
if (!thr_alarm(alarmed,net->read_timeout, alarm_buff) || if (thr_alarm(alarmed,net->read_timeout, alarm_buff) ||
vio_blocking(net->vio, TRUE, &old_mode) < 0) vio_blocking(net->vio, TRUE, &old_mode) < 0)
DBUG_RETURN(1); /* Can't setup, abort */ DBUG_RETURN(1); /* Can't setup, abort */
} }
......
...@@ -287,7 +287,7 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log, ...@@ -287,7 +287,7 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
goto err; goto err;
rli->cur_log = &rli->cache_buf; rli->cur_log = &rli->cache_buf;
} }
if (pos > BIN_LOG_HEADER_SIZE) if (pos >= BIN_LOG_HEADER_SIZE)
my_b_seek(rli->cur_log,(off_t)pos); my_b_seek(rli->cur_log,(off_t)pos);
err: err:
...@@ -2154,8 +2154,13 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) ...@@ -2154,8 +2154,13 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
else else
{ {
sql_print_error("\ sql_print_error("\
Could not parse log event entry, check the master for binlog corruption\n\ Could not parse relay log event entry. The possible reasons are: the master's \
This may also be a network problem, or just a bug in the master or slave code.\ binary log is corrupted (you can check this by running 'mysqlbinlog' on the \
binary log), the slave's relay log is corrupted (you can check this by running \
'mysqlbinlog' on the relay log), a network problem, or a bug in the master's \
or slave's MySQL code. If you want to check the master's binary log or slave's \
relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' \
on this slave.\
"); ");
return 1; return 1;
} }
......
...@@ -891,7 +891,11 @@ pthread_handler_decl(handle_one_connection,arg) ...@@ -891,7 +891,11 @@ pthread_handler_decl(handle_one_connection,arg)
send_error(thd,net->last_errno,NullS); send_error(thd,net->last_errno,NullS);
statistic_increment(aborted_threads,&LOCK_status); statistic_increment(aborted_threads,&LOCK_status);
} }
else if (thd->killed)
{
statistic_increment(aborted_threads,&LOCK_status);
}
end_thread: end_thread:
close_connection(thd, 0, 1); close_connection(thd, 0, 1);
end_thread(thd,1); end_thread(thd,1);
...@@ -1068,7 +1072,10 @@ bool do_command(THD *thd) ...@@ -1068,7 +1072,10 @@ bool do_command(THD *thd)
vio_description(net->vio))); vio_description(net->vio)));
/* Check if we can continue without closing the connection */ /* Check if we can continue without closing the connection */
if (net->error != 3) if (net->error != 3)
{
statistic_increment(aborted_threads,&LOCK_status);
DBUG_RETURN(TRUE); // We have to close it. DBUG_RETURN(TRUE); // We have to close it.
}
send_error(thd,net->last_errno,NullS); send_error(thd,net->last_errno,NullS);
net->error= 0; net->error= 0;
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
......
...@@ -997,7 +997,7 @@ int show_binlog_events(THD* thd) ...@@ -997,7 +997,7 @@ int show_binlog_events(THD* thd)
{ {
LEX_MASTER_INFO *lex_mi = &thd->lex.mi; LEX_MASTER_INFO *lex_mi = &thd->lex.mi;
ha_rows event_count, limit_start, limit_end; ha_rows event_count, limit_start, limit_end;
my_off_t pos = lex_mi->pos; my_off_t pos = max(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly
char search_file_name[FN_REFLEN], *name; char search_file_name[FN_REFLEN], *name;
const char *log_file_name = lex_mi->log_file_name; const char *log_file_name = lex_mi->log_file_name;
pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock(); pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock();
...@@ -1025,12 +1025,6 @@ int show_binlog_events(THD* thd) ...@@ -1025,12 +1025,6 @@ int show_binlog_events(THD* thd)
if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0) if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0)
goto err; goto err;
if (pos < 4)
{
errmsg = "Invalid log position";
goto err;
}
pthread_mutex_lock(log_lock); pthread_mutex_lock(log_lock);
my_b_seek(&log, pos); my_b_seek(&log, pos);
......
...@@ -804,6 +804,18 @@ master_def: ...@@ -804,6 +804,18 @@ master_def:
MASTER_LOG_POS_SYM EQ ulonglong_num MASTER_LOG_POS_SYM EQ ulonglong_num
{ {
Lex->mi.pos = $3; Lex->mi.pos = $3;
/*
If the user specified a value < BIN_LOG_HEADER_SIZE, adjust it
instead of causing subsequent errors.
We need to do it in this file, because only there we know that
MASTER_LOG_POS has been explicitely specified. On the contrary
in change_master() (sql_repl.cc) we cannot distinguish between 0
(MASTER_LOG_POS explicitely specified as 0) and 0 (unspecified),
whereas we want to distinguish (specified 0 means "read the binlog
from 0" (4 in fact), unspecified means "don't change the position
(keep the preceding value)").
*/
Lex->mi.pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.pos);
} }
| |
MASTER_CONNECT_RETRY_SYM EQ ULONG_NUM MASTER_CONNECT_RETRY_SYM EQ ULONG_NUM
...@@ -819,6 +831,8 @@ master_def: ...@@ -819,6 +831,8 @@ master_def:
RELAY_LOG_POS_SYM EQ ULONG_NUM RELAY_LOG_POS_SYM EQ ULONG_NUM
{ {
Lex->mi.relay_log_pos = $3; Lex->mi.relay_log_pos = $3;
/* Adjust if < BIN_LOG_HEADER_SIZE (same comment as Lex->mi.pos) */
Lex->mi.relay_log_pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.relay_log_pos);
} }
; ;
......
...@@ -141,10 +141,13 @@ ...@@ -141,10 +141,13 @@
*/ */
#define MIN_TURBOBM_PATTERN_LEN 3 #define MIN_TURBOBM_PATTERN_LEN 3
/* Defines for binary logging */ /*
Defines for binary logging.
#define BIN_LOG_HEADER_SIZE 4 Do not decrease the value of BIN_LOG_HEADER_SIZE.
Do not even increase it before checking code.
*/
#define BIN_LOG_HEADER_SIZE 4
#define FLOATING_POINT_BUFFER 331 #define FLOATING_POINT_BUFFER 331
/* Include prototypes for unireg */ /* Include prototypes for unireg */
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
# Required-Start: $local_fs $network $remote_fs # Required-Start: $local_fs $network $remote_fs
# Required-Stop: $local_fs $network $remote_fs # Required-Stop: $local_fs $network $remote_fs
# Default-Start: 2 3 4 5 # Default-Start: 2 3 4 5
# Default-Stop: 2 3 4 5 # Default-Stop: 0 1 6
# Short-Description: start and stop MySQL # Short-Description: start and stop MySQL
# Description: MySQL is a very fast and reliable SQL database engine. # Description: MySQL is a very fast and reliable SQL database engine.
### END INIT INFO ### END INIT INFO
......
...@@ -254,6 +254,13 @@ export PATH ...@@ -254,6 +254,13 @@ export PATH
# Build the 4.0 Max binary (includes BDB and UDFs and therefore # Build the 4.0 Max binary (includes BDB and UDFs and therefore
# cannot be linked statically against the patched glibc) # cannot be linked statically against the patched glibc)
# If we want to compile with RAID using gcc 3, we need to use
# gcc instead of g++ to avoid linking problems (RAID code is written in C++)
if gcc -v 2>&1 | grep 'version 3' > /dev/null 2>&1
then
export CXX="gcc"
fi
BuildMySQL "--enable-shared \ BuildMySQL "--enable-shared \
--with-openssl \ --with-openssl \
--with-berkeley-db \ --with-berkeley-db \
...@@ -319,6 +326,10 @@ install -m644 $MBD/sql/mysqld.sym $RBR/usr/lib/mysql/mysqld.sym ...@@ -319,6 +326,10 @@ install -m644 $MBD/sql/mysqld.sym $RBR/usr/lib/mysql/mysqld.sym
install -m644 $MBD/support-files/mysql-log-rotate $RBR/etc/logrotate.d/mysql install -m644 $MBD/support-files/mysql-log-rotate $RBR/etc/logrotate.d/mysql
install -m755 $MBD/support-files/mysql.server $RBR/etc/init.d/mysql install -m755 $MBD/support-files/mysql.server $RBR/etc/init.d/mysql
# Create a symlink "rcmysql", pointing to the init.script. SuSE users
# will appreciate that, as all services usually offer this.
ln -s ../../sbin/init.d/mysql $RPM_BUILD_ROOT/usr/sbin/rcmysql
# Create symbolic compatibility link safe_mysqld -> mysqld_safe # Create symbolic compatibility link safe_mysqld -> mysqld_safe
# (safe_mysqld will be gone in MySQL 4.1) # (safe_mysqld will be gone in MySQL 4.1)
ln -sf ./mysqld_safe $RBR/usr/bin/safe_mysqld ln -sf ./mysqld_safe $RBR/usr/bin/safe_mysqld
...@@ -463,6 +474,7 @@ fi ...@@ -463,6 +474,7 @@ fi
%attr(755, root, root) /usr/bin/safe_mysqld %attr(755, root, root) /usr/bin/safe_mysqld
%attr(755, root, root) /usr/sbin/mysqld %attr(755, root, root) /usr/sbin/mysqld
%attr(755, root, root) /usr/sbin/rcmysql
%attr(644, root, root) /usr/lib/mysql/mysqld.sym %attr(644, root, root) /usr/lib/mysql/mysqld.sym
%attr(644, root, root) /etc/logrotate.d/mysql %attr(644, root, root) /etc/logrotate.d/mysql
......
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