diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 4cc7ef813c3..be4a3e06fbb 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -1255,15 +1255,6 @@ void die(const char *fmt, ...) DBUG_ENTER("die"); DBUG_PRINT("enter", ("start_lineno: %d", start_lineno)); - /* - Protect against dying twice - first time 'die' is called, try to write log files - second time, just exit - */ - if (dying) - cleanup_and_exit(1); - dying= 1; - /* Print the error message */ fprintf(stderr, "mysqltest: "); if (cur_file && cur_file != file_stack) @@ -1282,6 +1273,15 @@ void die(const char *fmt, ...) fprintf(stderr, "\n"); fflush(stderr); + /* + Protect against dying twice + first time 'die' is called, try to write log files + second time, just exit + */ + if (dying) + cleanup_and_exit(1); + dying= 1; + log_file.show_tail(opt_tail_lines); /* diff --git a/mysql-test/r/warnings_debug.result b/mysql-test/r/warnings_debug.result new file mode 100644 index 00000000000..08908bf0437 --- /dev/null +++ b/mysql-test/r/warnings_debug.result @@ -0,0 +1,10 @@ +drop table if exists t1; +create table t1 (a int primary key) engine=innodb; +SET SESSION debug="+d,warn_during_ha_commit_trans"; +INSERT INTO t1 VALUES (1); +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +SHOW WARNINGS; +Level Code Message +Warning 1196 Some non-transactional changed tables couldn't be rolled back +drop table t1; diff --git a/mysql-test/t/warnings_debug.test b/mysql-test/t/warnings_debug.test new file mode 100644 index 00000000000..99d02330960 --- /dev/null +++ b/mysql-test/t/warnings_debug.test @@ -0,0 +1,19 @@ +--source include/have_innodb.inc +--source include/have_debug.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (a int primary key) engine=innodb; + +# Test that warnings produced during autocommit (after calling +# set_ok_status()) are still reported to the client. +SET SESSION debug="+d,warn_during_ha_commit_trans"; +INSERT INTO t1 VALUES (1); +# The warning will be shown automatically by mysqltest; there was a bug where +# this didn't happen because the warning was not counted when sending result +# packet. Show the warnings manually also. +SHOW WARNINGS; + +drop table t1; diff --git a/sql/handler.cc b/sql/handler.cc index 29aabda1343..48add3a1e53 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1094,6 +1094,12 @@ int ha_commit_trans(THD *thd, bool all) my_xid xid= thd->transaction.xid_state.xid.get_my_xid(); DBUG_ENTER("ha_commit_trans"); + /* Just a random warning to test warnings pushed during autocommit. */ + DBUG_EXECUTE_IF("warn_during_ha_commit_trans", + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARNING_NOT_COMPLETE_ROLLBACK, + ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));); + /* We must not commit the normal transaction if a statement transaction is pending. Otherwise statement transaction diff --git a/sql/protocol.cc b/sql/protocol.cc index 786d6ef8544..8a9d712077d 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -203,7 +203,7 @@ net_send_ok(THD *thd, NET *net= &thd->net; uchar buff[MYSQL_ERRMSG_SIZE+10],*pos; bool error= FALSE; - DBUG_ENTER("my_ok"); + DBUG_ENTER("net_send_ok"); if (! net->vio) // hack for re-parsing queries { diff --git a/sql/sql_class.h b/sql/sql_class.h index 4682938fd6d..bb986d6377f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1224,6 +1224,13 @@ public: return m_total_warn_count; } + /* Used to count any warnings pushed after calling set_ok_status(). */ + void increment_warning() + { + if (m_status != DA_EMPTY) + m_total_warn_count++; + } + Diagnostics_area() { reset_diagnostics_area(); } private: diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 9ea7facbe41..835e60cd6ba 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -159,6 +159,8 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, } thd->warn_count[(uint) level]++; thd->total_warn_count++; + /* Make sure we also count warnings pushed after calling set_ok_status(). */ + thd->main_da.increment_warning(); DBUG_RETURN(err); } diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index 0eab7c62796..fd02e2ac0ec 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -1993,19 +1993,6 @@ static my_bool write_tail(MARIA_HA *info, /* Keep BLOCKUSED_USE_ORG_BITMAP */ block->used|= BLOCKUSED_USED | BLOCKUSED_TAIL; - /* Increase data file size, if extended */ - position= (my_off_t) block->page * block_size; - if (share->state.state.data_file_length <= position) - { - /* - We are modifying a state member before writing the UNDO; this is a WAL - violation. But for data_file_length this is ok, as long as we change - data_file_length after writing any log record (FILE_ID/REDO/UNDO) (see - collect_tables()). - */ - _ma_set_share_data_file_length(share, position + block_size); - } - if (block_is_read) { /* Current page link is last element in pinned_pages */ @@ -2021,17 +2008,33 @@ static my_bool write_tail(MARIA_HA *info, page_link->unlock= PAGECACHE_LOCK_READ_UNLOCK; res= 0; } - else if (!(res= pagecache_write(share->pagecache, - &info->dfile, block->page, 0, - row_pos.buff,share->page_type, - PAGECACHE_LOCK_READ, - PAGECACHE_PIN, - PAGECACHE_WRITE_DELAY, &page_link.link, - LSN_IMPOSSIBLE))) + else { - page_link.unlock= PAGECACHE_LOCK_READ_UNLOCK; - page_link.changed= 1; - push_dynamic(&info->pinned_pages, (void*) &page_link); + if (!(res= pagecache_write(share->pagecache, + &info->dfile, block->page, 0, + row_pos.buff,share->page_type, + PAGECACHE_LOCK_READ, + PAGECACHE_PIN, + PAGECACHE_WRITE_DELAY, &page_link.link, + LSN_IMPOSSIBLE))) + { + page_link.unlock= PAGECACHE_LOCK_READ_UNLOCK; + page_link.changed= 1; + push_dynamic(&info->pinned_pages, (void*) &page_link); + } + + /* Increase data file size, if extended */ + position= (my_off_t) block->page * block_size; + if (share->state.state.data_file_length <= position) + { + /* + We are modifying a state member before writing the UNDO; this is a WAL + violation. But for data_file_length this is ok, as long as we change + data_file_length after writing any log record (FILE_ID/REDO/UNDO) (see + collect_tables()). + */ + _ma_set_share_data_file_length(share, position + block_size); + } } DBUG_RETURN(res); } @@ -2068,7 +2071,7 @@ static my_bool write_full_pages(MARIA_HA *info, uint data_size= FULL_PAGE_SIZE(block_size); uchar *buff= info->keyread_buff; uint page_count, sub_blocks; - my_off_t position; + my_off_t position, max_position; DBUG_ENTER("write_full_pages"); DBUG_PRINT("enter", ("length: %lu page: %lu page_count: %lu", (ulong) length, (ulong) block->page, @@ -2080,9 +2083,7 @@ static my_bool write_full_pages(MARIA_HA *info, page_count= block->page_count; sub_blocks= block->sub_blocks; - position= (my_off_t) (page + page_count) * block_size; - if (share->state.state.data_file_length < position) - _ma_set_share_data_file_length(share, position); + max_position= (my_off_t) (page + page_count) * block_size; /* Increase data file size, if extended */ @@ -2105,8 +2106,7 @@ static my_bool write_full_pages(MARIA_HA *info, (ulong) block->page, (ulong) block->page_count)); position= (page + page_count + 1) * block_size; - if (share->state.state.data_file_length < position) - _ma_set_share_data_file_length(share, position); + set_if_bigger(max_position, position); } lsn_store(buff, lsn); buff[PAGE_TYPE_OFFSET]= (uchar) BLOB_PAGE; @@ -2134,6 +2134,8 @@ static my_bool write_full_pages(MARIA_HA *info, page++; DBUG_ASSERT(block->used & BLOCKUSED_USED); } + if (share->state.state.data_file_length < max_position) + _ma_set_share_data_file_length(share, max_position); DBUG_RETURN(0); } @@ -3121,11 +3123,6 @@ static my_bool write_block_record(MARIA_HA *info, } #endif - /* Increase data file size, if extended */ - position= (my_off_t) head_block->page * block_size; - if (share->state.state.data_file_length <= position) - _ma_set_share_data_file_length(share, position + block_size); - if (head_block_is_read) { MARIA_PINNED_PAGE *page_link; @@ -3154,6 +3151,11 @@ static my_bool write_block_record(MARIA_HA *info, page_link.unlock= PAGECACHE_LOCK_READ_UNLOCK; page_link.changed= 1; push_dynamic(&info->pinned_pages, (void*) &page_link); + + /* Increase data file size, if extended */ + position= (my_off_t) head_block->page * block_size; + if (share->state.state.data_file_length <= position) + _ma_set_share_data_file_length(share, position + block_size); } if (share->now_transactional && (tmp_data_used || blob_full_pages_exists)) @@ -5162,6 +5164,7 @@ my_bool _ma_scan_init_block_record(MARIA_HA *info) info->scan.number_of_rows= 0; info->scan.bitmap_pos= info->scan.bitmap_end; info->scan.bitmap_page= (pgcache_page_no_t) 0 - share->bitmap.pages_covered; + info->scan.max_page= share->state.state.data_file_length / share->block_size; /* We need to flush what's in memory (bitmap.map) to page cache otherwise, as we are going to read bitmaps from page cache in table scan (see @@ -5363,6 +5366,11 @@ restart_bitmap_scan: page= (info->scan.bitmap_page + 1 + (data - info->scan.bitmap_buff) / 6 * 16 + bit_pos - 1); info->scan.row_base_page= ma_recordpos(page, 0); + if (page >= info->scan.max_page) + { + DBUG_PRINT("info", ("Found end of file")); + DBUG_RETURN((my_errno= HA_ERR_END_OF_FILE)); + } if (!(pagecache_read(share->pagecache, &info->dfile, page, 0, info->scan.page_buff, diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h index bdc4d4c5ed2..b998ac4f3a0 100644 --- a/storage/maria/maria_def.h +++ b/storage/maria/maria_def.h @@ -476,7 +476,7 @@ typedef struct st_maria_block_scan { uchar *bitmap_buff, *bitmap_pos, *bitmap_end, *page_buff; uchar *dir, *dir_end; - pgcache_page_no_t bitmap_page; + pgcache_page_no_t bitmap_page, max_page; ulonglong bits; uint number_of_rows, bit_pos; MARIA_RECORD_POS row_base_page; diff --git a/storage/xtradb/include/os0sync.h b/storage/xtradb/include/os0sync.h index 0c22162b900..c230a03b6db 100644 --- a/storage/xtradb/include/os0sync.h +++ b/storage/xtradb/include/os0sync.h @@ -189,7 +189,7 @@ os_event_wait_low( /**********************************************************//** Waits for an event object until it is in the signaled state or -a timeout is exceeded. In Unix the timeout is always infinite. +a timeout is exceeded. @return 0 if success, OS_SYNC_TIME_EXCEEDED if timeout was exceeded */ UNIV_INTERN ulint diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h index dc455581350..8c64d5cee71 100644 --- a/storage/xtradb/include/srv0srv.h +++ b/storage/xtradb/include/srv0srv.h @@ -57,6 +57,9 @@ extern const char srv_mysql50_table_name_prefix[9]; thread starts running */ extern os_event_t srv_lock_timeout_thread_event; +/* This event is set to tell the purge thread to shut down */ +extern os_event_t srv_purge_thread_event; + /* If the last data file is auto-extended, we add this many pages to it at a time */ #define SRV_AUTO_EXTEND_INCREMENT \ diff --git a/storage/xtradb/log/log0log.c b/storage/xtradb/log/log0log.c index fade31037b5..b9f19aeff31 100644 --- a/storage/xtradb/log/log0log.c +++ b/storage/xtradb/log/log0log.c @@ -3102,6 +3102,7 @@ logs_empty_and_mark_files_at_shutdown(void) algorithm only works if the server is idle at shutdown */ srv_shutdown_state = SRV_SHUTDOWN_CLEANUP; + os_event_set(srv_purge_thread_event); loop: os_thread_sleep(100000); diff --git a/storage/xtradb/os/os0sync.c b/storage/xtradb/os/os0sync.c index 60467242e14..f9ab58c2ee4 100644 --- a/storage/xtradb/os/os0sync.c +++ b/storage/xtradb/os/os0sync.c @@ -31,6 +31,9 @@ Created 9/6/1995 Heikki Tuuri #ifdef __WIN__ #include +#else +#include +#include #endif #include "ut0mem.h" @@ -407,14 +410,14 @@ os_event_wait_low( /**********************************************************//** Waits for an event object until it is in the signaled state or -a timeout is exceeded. In Unix the timeout is always infinite. +a timeout is exceeded. @return 0 if success, OS_SYNC_TIME_EXCEEDED if timeout was exceeded */ UNIV_INTERN ulint os_event_wait_time( /*===============*/ os_event_t event, /*!< in: event to wait */ - ulint time) /*!< in: timeout in microseconds, or + ulint wtime) /*!< in: timeout in microseconds, or OS_SYNC_INFINITE_TIME */ { #ifdef __WIN__ @@ -422,8 +425,8 @@ os_event_wait_time( ut_a(event); - if (time != OS_SYNC_INFINITE_TIME) { - err = WaitForSingleObject(event->handle, (DWORD) time / 1000); + if (wtime != OS_SYNC_INFINITE_TIME) { + err = WaitForSingleObject(event->handle, (DWORD) wtime / 1000); } else { err = WaitForSingleObject(event->handle, INFINITE); } @@ -439,13 +442,47 @@ os_event_wait_time( return(1000000); /* dummy value to eliminate compiler warn. */ } #else - UT_NOT_USED(time); + int err; + int ret = 0; + ulint tmp; + ib_int64_t old_count; + struct timeval tv_start; + struct timespec timeout; - /* In Posix this is just an ordinary, infinite wait */ + if (wtime == OS_SYNC_INFINITE_TIME) { + os_event_wait(event); + return 0; + } - os_event_wait(event); + /* Compute the absolute point in time at which to time out. */ + gettimeofday(&tv_start, NULL); + tmp = tv_start.tv_usec + wtime; + timeout.tv_sec = tv_start.tv_sec + (tmp / 1000000); + timeout.tv_nsec = (tmp % 1000000) * 1000; - return(0); + os_fast_mutex_lock(&(event->os_mutex)); + old_count = event->signal_count; + + for (;;) { + if (event->is_set == TRUE || event->signal_count != old_count) + break; + + err = pthread_cond_timedwait(&(event->cond_var), + &(event->os_mutex), &timeout); + if (err == ETIMEDOUT) { + ret = OS_SYNC_TIME_EXCEEDED; + break; + } + } + + os_fast_mutex_unlock(&(event->os_mutex)); + + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + + os_thread_exit(NULL); + } + + return ret; #endif } diff --git a/storage/xtradb/srv/srv0srv.c b/storage/xtradb/srv/srv0srv.c index c1d0f255c64..43799aab196 100644 --- a/storage/xtradb/srv/srv0srv.c +++ b/storage/xtradb/srv/srv0srv.c @@ -704,6 +704,8 @@ UNIV_INTERN srv_slot_t* srv_mysql_table = NULL; UNIV_INTERN os_event_t srv_lock_timeout_thread_event; +UNIV_INTERN os_event_t srv_purge_thread_event; + UNIV_INTERN srv_sys_t* srv_sys = NULL; /* padding to prevent other memory update hotspots from residing on @@ -1009,6 +1011,7 @@ srv_init(void) } srv_lock_timeout_thread_event = os_event_create(NULL); + srv_purge_thread_event = os_event_create(NULL); for (i = 0; i < SRV_MASTER + 1; i++) { srv_n_threads_active[i] = 0; @@ -3337,9 +3340,10 @@ loop: mutex_exit(&kernel_mutex); sleep_ms = 10; + os_event_reset(srv_purge_thread_event); } - os_thread_sleep( sleep_ms * 1000 ); + os_event_wait_time(srv_purge_thread_event, sleep_ms * 1000); history_len = trx_sys->rseg_history_len; if (history_len > 1000)