From 0eaf97393dbe4e8e13bbe85c18c71b41e473b086 Mon Sep 17 00:00:00 2001 From: unknown 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: A test case for BUG#27998. mysql-test/t/blackhole.test: A test case for BUG#27998. sql/ha_blackhole.h: Removed HA_CAN_INSERT_DELAYED flag from table_flags(). The insert delayed thread upgrades the lock. Hence it is incapable to handle BLACKHOLE tables, which do not have locks at all. --- 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 e1e83a8b66dc59b1e46cd78db6a20b8ba2ea44ba Mon Sep 17 00:00:00 2001 From: unknown 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: Key file descriptor is shared among threads and mixed set of my_pread/my_pwrite and my_seek calls is possible. This is not a problem on systems that have native pread/pwrite calls. In case system doesn't have native pread/pwrite calls (e.g. Windows) we must ensure that my_pread/my_pwrite are not executed at the same time with my_seek. This is done by passing MY_THREADSAFE flag to my_seek. mysys/my_seek.c: On platforms that do not have native pread/pwrite calls (e.g. Windows) these calls are emulated as follow: lock fd, lseek, read, unlock fd. In case file descriptor is shared among threads, where one thread executes my_pread and another thread executes my_seek, we may read from a wrong position. This may happen because my_seek doesn't lock fd and thus may be executed by another thread after emulated pread has done lseek and before it has done read. To fix problem mentioned above we introduce new flag MY_THREADSAFE to my_seek, which is meaningful only in case pread/pwrite calls are emulated. If this flag is set, lseek operation is performed as follow: lock fd, seek, unlock fd. --- 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 6e09887f5d4ef9c09c17af8dc4912201cc153b2b Mon Sep 17 00:00:00 2001 From: unknown 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: 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). Also it doesn't affect my_pread/my_pwrite in any way. So the comment was updated. --- 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 a656c71e8ae765ea194a59a69d440d203308f235 Mon Sep 17 00:00:00 2001 From: unknown 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