From 0c7631e76312c5e8872adfd02a14c9ab2a27700b Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/june.mysql.com" <> Date: Sat, 28 Apr 2007 14:37:40 +0500 Subject: [PATCH 1/4] BUG#27998 - mysqld crashed when executing INSERT DELAYED on a BLACKHOLE table Using INSERT DELAYED on BLACKHOLE tables could lead to server crash. This happens because delayed thread wants to upgrade a lock, but BLACKHOLE tables do not have locks at all. This patch rejects attempts to use INSERT DELAYED on MERGE tables. --- mysql-test/r/blackhole.result | 4 ++++ mysql-test/t/blackhole.test | 9 +++++++++ sql/ha_blackhole.h | 3 +-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/blackhole.result b/mysql-test/r/blackhole.result index 4b779094376..2d020e0eed7 100644 --- a/mysql-test/r/blackhole.result +++ b/mysql-test/r/blackhole.result @@ -123,3 +123,7 @@ master-bin.000001 # Query 1 # use `test`; create table t3 like t1 master-bin.000001 # Query 1 # use `test`; insert into t1 select * from t3 master-bin.000001 # Query 1 # use `test`; replace into t1 select * from t3 drop table t1,t2,t3; +CREATE TABLE t1(a INT) ENGINE=BLACKHOLE; +INSERT DELAYED INTO t1 VALUES(1); +ERROR HY000: Table storage engine for 't1' doesn't have this option +DROP TABLE t1; diff --git a/mysql-test/t/blackhole.test b/mysql-test/t/blackhole.test index 257770d311c..4375f1c13ce 100644 --- a/mysql-test/t/blackhole.test +++ b/mysql-test/t/blackhole.test @@ -126,4 +126,13 @@ show binlog events; drop table t1,t2,t3; +# +# BUG#27998 - mysqld crashed when executing INSERT DELAYED on a BLACKHOLE +# table +# +CREATE TABLE t1(a INT) ENGINE=BLACKHOLE; +--error 1031 +INSERT DELAYED INTO t1 VALUES(1); +DROP TABLE t1; + # End of 4.1 tests diff --git a/sql/ha_blackhole.h b/sql/ha_blackhole.h index 177b59fa970..e5f5ee69a82 100644 --- a/sql/ha_blackhole.h +++ b/sql/ha_blackhole.h @@ -46,8 +46,7 @@ public: { return(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER | HA_DUPP_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY | - HA_FILE_BASED | HA_CAN_GEOMETRY | HA_READ_RND_SAME | - HA_CAN_INSERT_DELAYED); + HA_FILE_BASED | HA_CAN_GEOMETRY | HA_READ_RND_SAME); } ulong index_flags(uint inx, uint part, bool all_parts) const { From 3ea2ee357b03d909566965046a9a2c5f32f91b3b Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/april.(none)" <> Date: Wed, 16 May 2007 23:42:32 +0500 Subject: [PATCH 2/4] BUG#25712 - insert delayed and check table run together report crashed tables In case system doesn't have native pread/pwrite calls (e.g. Windows) and there is CHECK TABLE runs concurrently with another statement that reads from a table, the table may be reported as crashed. This is fixed by locking file descriptor when my_seek is executed on MyISAM index file and emulated pread/pwrite may be executed concurrently. Affects MyISAM tables on platforms that do not have native pread/pwrite calls (e.g. Windows). No deterministic test case for this bug. --- myisam/mi_check.c | 13 +++++++------ mysys/my_seek.c | 15 +++++++++++++-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 3a7817b7f03..ce8fb04874e 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -336,7 +336,7 @@ int chk_size(MI_CHECK *param, register MI_INFO *info) flush_key_blocks(info->s->key_cache, info->s->kfile, FLUSH_FORCE_WRITE); - size=my_seek(info->s->kfile,0L,MY_SEEK_END,MYF(0)); + size= my_seek(info->s->kfile, 0L, MY_SEEK_END, MYF(MY_THREADSAFE)); if ((skr=(my_off_t) info->state->key_file_length) != size) { if (skr > size) @@ -595,7 +595,8 @@ static int chk_index_down(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, { /* purecov: begin tested */ /* Give it a chance to fit in the real file size. */ - my_off_t max_length= my_seek(info->s->kfile, 0L, MY_SEEK_END, MYF(0)); + my_off_t max_length= my_seek(info->s->kfile, 0L, MY_SEEK_END, + MYF(MY_THREADSAFE)); mi_check_print_error(param, "Invalid key block position: %s " "key block size: %u file_length: %s", llstr(page, llbuff), keyinfo->block_length, @@ -4039,10 +4040,10 @@ int test_if_almost_full(MI_INFO *info) { if (info->s->options & HA_OPTION_COMPRESS_RECORD) return 0; - return (my_seek(info->s->kfile,0L,MY_SEEK_END,MYF(0))/10*9 > - (my_off_t) (info->s->base.max_key_file_length) || - my_seek(info->dfile,0L,MY_SEEK_END,MYF(0))/10*9 > - (my_off_t) info->s->base.max_data_file_length); + return my_seek(info->s->kfile, 0L, MY_SEEK_END, MYF(MY_THREADSAFE)) / 10 * 9 > + (my_off_t) info->s->base.max_key_file_length || + my_seek(info->dfile, 0L, MY_SEEK_END, MYF(0)) / 10 * 9 > + (my_off_t) info->s->base.max_data_file_length; } /* Recreate table with bigger more alloced record-data */ diff --git a/mysys/my_seek.c b/mysys/my_seek.c index a9ae68cd5f0..cb0fe75d7e5 100644 --- a/mysys/my_seek.c +++ b/mysys/my_seek.c @@ -24,7 +24,9 @@ my_off_t pos The expected position (absolute or relative) int whence A direction parameter and one of {SEEK_SET, SEEK_CUR, SEEK_END} - myf MyFlags Not used. + myf MyFlags MY_THREADSAFE must be set in case my_seek may be mixed + with my_pread/my_pwrite calls and fd is shared among + threads. DESCRIPTION The my_seek function is a wrapper around the system call lseek and @@ -51,7 +53,16 @@ my_off_t my_seek(File fd, my_off_t pos, int whence, whence, MyFlags)); DBUG_ASSERT(pos != MY_FILEPOS_ERROR); /* safety check */ - newpos=lseek(fd, pos, whence); +#if defined(THREAD) && !defined(HAVE_PREAD) + if (MyFlags & MY_THREADSAFE) + { + pthread_mutex_lock(&my_file_info[fd].mutex); + newpos= lseek(fd, pos, whence); + pthread_mutex_lock(&my_file_info[fd].mutex); + } + else +#endif + newpos= lseek(fd, pos, whence); if (newpos == (os_off_t) -1) { my_errno=errno; From 4f11124c485ccfed76e50b19eeaf18101d3bdf53 Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/june.mysql.com" <> Date: Thu, 17 May 2007 12:43:52 +0500 Subject: [PATCH 3/4] Addition to fix for BUG#25712 - insert delayed and check table run together report crashed tables Let MY_THREADSAFE have distinct value. Some functions call my_seek passing MyFlags argument directly to it. This may cause unnecessary locks, which may finally lead to a dead-lock (specifically see my_lock). --- include/my_sys.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/my_sys.h b/include/my_sys.h index 4c9a7a7964c..759531fa649 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -73,8 +73,8 @@ extern int NEAR my_errno; /* Last error in mysys */ #define MY_ALLOW_ZERO_PTR 64 /* my_realloc() ; zero ptr -> malloc */ #define MY_FREE_ON_ERROR 128 /* my_realloc() ; Free old ptr on error */ #define MY_HOLD_ON_ERROR 256 /* my_realloc() ; Return old ptr on error */ -#define MY_THREADSAFE 128 /* pread/pwrite: Don't allow interrupts */ #define MY_DONT_OVERWRITE_FILE 1024 /* my_copy; Don't overwrite file */ +#define MY_THREADSAFE 2048 /* my_seek(): lock fd mutex */ #define MY_CHECK_ERROR 1 /* Params to my_end; Check open-close */ #define MY_GIVE_INFO 2 /* Give time info about process*/ From f6a111dfef4ef1c442a4954d31628eed92a0f357 Mon Sep 17 00:00:00 2001 From: "svoj@mysql.com/june.mysql.com" <> Date: Thu, 17 May 2007 15:23:59 +0500 Subject: [PATCH 4/4] Addition to fix for BUG#25712 - insert delayed and check table run together report crashed tables Fixed wrongly applied patch. --- mysys/my_seek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/my_seek.c b/mysys/my_seek.c index cb0fe75d7e5..805a5654ffc 100644 --- a/mysys/my_seek.c +++ b/mysys/my_seek.c @@ -58,7 +58,7 @@ my_off_t my_seek(File fd, my_off_t pos, int whence, { pthread_mutex_lock(&my_file_info[fd].mutex); newpos= lseek(fd, pos, whence); - pthread_mutex_lock(&my_file_info[fd].mutex); + pthread_mutex_unlock(&my_file_info[fd].mutex); } else #endif