#At file:///home2/mydev/bzrroot/mysql-6.0-keycache-1/ based on revid:jorgen.loland@stripped
2810 Ingo Struewing 2009-04-03
Bug#44068 - RESTORE can disable the MyISAM Key Cache
The test case myisam_keycache_coverage used to fail if it ran
after backup_myisam_sync.
The reason was that the latter test case disabled the key cache
during RESTORE. The error injection in myisam_keycache_coverage
became void as the key cache wasn't used any more. Reads of the
index file bypassed the cache, and the statements succeeded.
Fixed by avoiding de-initialization of the key cache if it was
not initialized by the MyISAM log reading function mi_examine_log().
The function will initialize and de-initialize the key cache if it
is used by the myisamlog utility. It won't touch the key cache any
more, if it is called from inside the server.
Additional change: To make the state of the key cache visible,
I added cleanup for the status variables blocks_used and
blocks_unused. This improves the testability.
@ mysql-test/r/myisam_keycache_coverage.result
Bug#44068 - RESTORE can disable the MyISAM Key Cache
Updated test result.
@ mysql-test/suite/backup/r/backup_myisam_sync.result
Bug#44068 - RESTORE can disable the MyISAM Key Cache
Updated test result.
@ mysql-test/suite/backup/t/backup_myisam_sync.test
Bug#44068 - RESTORE can disable the MyISAM Key Cache
Added checks for the state of the key cache.
@ mysql-test/t/myisam_keycache_coverage.test
Bug#44068 - RESTORE can disable the MyISAM Key Cache
Added debug variable initialization to be safe.
Added FORCE INDEX to the reference statement to make it
equal to the tested statement.
Removed old attempts to stabilize the test case.
@ mysys/mf_keycache.c
Bug#44068 - RESTORE can disable the MyISAM Key Cache
Added cleanup for blocks_used and blocks_unused.
Added DBUG.
@ storage/myisam/mi_examine_log.c
Bug#44068 - RESTORE can disable the MyISAM Key Cache
Added local variable key_cache_blocks to be used to call
end_key_cache() only if init_key_cache() did in fact
initialize the cache.
modified:
mysql-test/r/myisam_keycache_coverage.result
mysql-test/suite/backup/r/backup_myisam_sync.result
mysql-test/suite/backup/t/backup_myisam_sync.test
mysql-test/t/myisam_keycache_coverage.test
mysys/mf_keycache.c
storage/myisam/mi_examine_log.c
=== modified file 'mysql-test/r/myisam_keycache_coverage.result'
--- a/mysql-test/r/myisam_keycache_coverage.result 2009-03-30 16:47:55 +0000
+++ b/mysql-test/r/myisam_keycache_coverage.result 2009-04-03 09:44:39 +0000
@@ -1,6 +1,8 @@
#
# MyISAM keycache coverage tests.
#
+SET GLOBAL debug='';
+SET debug='';
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 VARCHAR(5), c2 int) ENGINE=MyISAM;
CREATE INDEX i1 ON t1 (c1, c2);
@@ -11,7 +13,7 @@ INSERT INTO t1 SELECT * FROM t1;
#
# Positive tests.
#
-SELECT COUNT(*) FROM t1 WHERE c2 < 5;
+SELECT COUNT(*) FROM t1 FORCE INDEX(i1) WHERE c2 < 5;
COUNT(*)
8
LOAD INDEX INTO CACHE t1;
@@ -25,12 +27,7 @@ FLUSH TABLE t1;
#
# Inject error key_cache_read_block_error
#
-EXPLAIN SELECT COUNT(*) FROM t1 WHERE c2 < 5;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL i1 13 NULL 8 Using where; Using index
-SET debug='+d,key_cache_read_block_error';
-FLUSH TABLES;
-SELECT COUNT(*) FROM t1 FORCE INDEX(i1) WHERE c2 < 5;
+SET debug='d,key_cache_read_block_error';
SELECT COUNT(*) FROM t1 FORCE INDEX(i1) WHERE c2 < 5;
ERROR HY000: Incorrect key file for table 't1.MYI'; try to repair it
FLUSH TABLE t1;
=== modified file 'mysql-test/suite/backup/r/backup_myisam_sync.result'
--- a/mysql-test/suite/backup/r/backup_myisam_sync.result 2009-02-13 12:40:13 +0000
+++ b/mysql-test/suite/backup/r/backup_myisam_sync.result 2009-04-03 09:44:39 +0000
@@ -36,6 +36,15 @@ LENGTH(c1)
CHECKSUM TABLE t1;
Table Checksum
mysqltest.t1 1728069308
+
+# Verify that the MyISAM Key Cache is enabled.
+# See Bug#44068 (RESTORE can disable the MyISAM Key Cache).
+SELECT SUM(VARIABLE_VALUE) > 0 AS key_cache_is_enabled
+FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE
+VARIABLE_NAME LIKE 'Key_blocks_%used';
+key_cache_is_enabled
+1
+
Signal BACKUP to finish
SET DEBUG_SYNC= 'now SIGNAL bup_finish';
@@ -59,6 +68,14 @@ mysqltest.t1 check status OK
connection default: cleanup
SET DEBUG_SYNC= 'RESET';
+# Verify that the MyISAM Key Cache is still enabled.
+# See Bug#44068 (RESTORE can disable the MyISAM Key Cache).
+SELECT SUM(VARIABLE_VALUE) > 0 AS key_cache_is_enabled
+FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE
+VARIABLE_NAME LIKE 'Key_blocks_%used';
+key_cache_is_enabled
+1
+
# final cleanup
USE test;
DROP DATABASE mysqltest;
=== modified file 'mysql-test/suite/backup/t/backup_myisam_sync.test'
--- a/mysql-test/suite/backup/t/backup_myisam_sync.test 2009-02-24 20:57:21 +0000
+++ b/mysql-test/suite/backup/t/backup_myisam_sync.test 2009-04-03 09:44:39 +0000
@@ -59,6 +59,14 @@ while ($1)
SELECT LENGTH(c1) FROM t1;
CHECKSUM TABLE t1;
+--echo
+--echo # Verify that the MyISAM Key Cache is enabled.
+--echo # See Bug#44068 (RESTORE can disable the MyISAM Key Cache).
+SELECT SUM(VARIABLE_VALUE) > 0 AS key_cache_is_enabled
+ FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE
+ VARIABLE_NAME LIKE 'Key_blocks_%used';
+--echo
+
--echo Signal BACKUP to finish
SET DEBUG_SYNC= 'now SIGNAL bup_finish';
@@ -84,10 +92,17 @@ connection default;
remove_file $MYSQLD_BACKUPDIR/bup_myisam_sync.bak;
SET DEBUG_SYNC= 'RESET';
+--echo
+--echo # Verify that the MyISAM Key Cache is still enabled.
+--echo # See Bug#44068 (RESTORE can disable the MyISAM Key Cache).
+SELECT SUM(VARIABLE_VALUE) > 0 AS key_cache_is_enabled
+ FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE
+ VARIABLE_NAME LIKE 'Key_blocks_%used';
+--echo
+
#
# Cleanup from this test case
#
---echo
--echo # final cleanup
USE test;
DROP DATABASE mysqltest;
=== modified file 'mysql-test/t/myisam_keycache_coverage.test'
--- a/mysql-test/t/myisam_keycache_coverage.test 2009-03-30 16:47:55 +0000
+++ b/mysql-test/t/myisam_keycache_coverage.test 2009-04-03 09:44:39 +0000
@@ -5,6 +5,9 @@
--source include/have_debug.inc
--disable_warnings
+# Reset debug server variable
+SET GLOBAL debug='';
+SET debug='';
DROP TABLE IF EXISTS t1;
--enable_warnings
@@ -18,7 +21,7 @@ INSERT INTO t1 SELECT * FROM t1;
--echo #
--echo # Positive tests.
--echo #
-SELECT COUNT(*) FROM t1 WHERE c2 < 5;
+SELECT COUNT(*) FROM t1 FORCE INDEX(i1) WHERE c2 < 5;
LOAD INDEX INTO CACHE t1;
UPDATE t1 SET c2=2;
@@ -30,42 +33,7 @@ FLUSH TABLE t1;
--echo #
--echo # Inject error key_cache_read_block_error
--echo #
-#
-# I have seen the below SELECT to succeed from time to time,
-# though it shall fail due to the injected error. As far as I undestand,
-# the only way for this to happen is that SELECT does not use the index.
-# Since the problem is random, I add an EXPLAIN here, to see if this
-# does indeed happen. If it shows a result difference from time to time,
-# then perhaps FLUSH TABLE t1 does not always work reliably.
-# In addition to the EXPLAIN, which is here to prove the assumption,
-# I add FORCE INDEX to keep the SELECT failing, which is the whole
-# purpose of this test.
-#
-EXPLAIN SELECT COUNT(*) FROM t1 WHERE c2 < 5;
-#
-# The EXPLAIN shows that the index is used. It fails sporadically anyway.
-# It fails frequently on my machine, but curiously on the first attempt.
-# Both retries were always successful. Running the test stand alone or
-# in a small group does never fail. So I wonder if the setting of the
-# 'debug' server variable might fail. I had "SET debug='d,..." here.
-# Perhaps this is vulnerable to some preset of the variable.
-# So I set it with "+d" as we do at many other places.
-#
-SET debug='+d,key_cache_read_block_error';
-#
-# Changing to "+d" did not help. Trying a full flush of all tables.
-# This shouldn't make a difference, but...
-# Flushing shouldn't play a role since the error injection happens
-# after the copy from cache block to MyISAM buffer.
-#
-FLUSH TABLES;
-#
-# As expected FLUSH TABLES didn't help either.
-# Now duplicating the offending SELECT, ignoring success on the first attempt.
-#
---replace_regex /'.*[\/\\]/'/
---error 0,126
-SELECT COUNT(*) FROM t1 FORCE INDEX(i1) WHERE c2 < 5;
+SET debug='d,key_cache_read_block_error';
--replace_regex /'.*[\/\\]/'/
--error 126
SELECT COUNT(*) FROM t1 FORCE INDEX(i1) WHERE c2 < 5;
=== modified file 'mysys/mf_keycache.c'
--- a/mysys/mf_keycache.c 2009-01-29 21:17:59 +0000
+++ b/mysys/mf_keycache.c 2009-04-03 09:44:39 +0000
@@ -765,6 +765,13 @@ void end_key_cache(KEY_CACHE *keycache,
(ulong) keycache->global_cache_r_requests,
(ulong) keycache->global_cache_read));
+ /*
+ Reset these values to be able to detect a disabled key cache.
+ See Bug#44068 (RESTORE can disable the MyISAM Key Cache).
+ */
+ keycache->blocks_used= 0;
+ keycache->blocks_unused= 0;
+
if (cleanup)
{
pthread_mutex_destroy(&keycache->cache_lock);
@@ -2606,7 +2613,10 @@ uchar *key_cache_read(KEY_CACHE *keycach
/* Cache could be disabled in a later iteration. */
if (!keycache->can_be_used)
- goto no_key_cache;
+ {
+ KEYCACHE_DBUG_PRINT("key_cache_read", ("keycache cannot be used"));
+ goto no_key_cache;
+ }
/* Start reading at the beginning of the cache block. */
filepos-= offset;
/* Do not read beyond the end of the cache block. */
@@ -2726,6 +2736,7 @@ uchar *key_cache_read(KEY_CACHE *keycach
} while ((length-= read_length));
goto end;
}
+ KEYCACHE_DBUG_PRINT("key_cache_read", ("keycache not initialized"));
no_key_cache:
/* Key cache is not used */
@@ -2746,6 +2757,7 @@ end:
dec_counter_for_resize_op(keycache);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
}
+ DBUG_PRINT("exit", ("error: %d", error ));
DBUG_RETURN(error ? (uchar*) 0 : start);
}
=== modified file 'storage/myisam/mi_examine_log.c'
--- a/storage/myisam/mi_examine_log.c 2009-02-22 18:02:16 +0000
+++ b/storage/myisam/mi_examine_log.c 2009-04-03 09:44:39 +0000
@@ -175,6 +175,7 @@ int mi_examine_log(MI_EXAMINE_LOG_PARAM
{ { 11, 14 }, { 15, 22 }, { 15, 22 }, { 11, 14 }, { 11, 14 }, { 11, 14 },
{ 11, 14 }, { 11, 14 }, { 9, 16 }, { 9, 16 }, { 7, 12 } };
uint has_pid_and_result[]= {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0};
+ int key_cache_blocks;
DBUG_ENTER("mi_examine_log");
DBUG_PRINT("myisamlog", ("max_files: %u update: %u",
mi_exl->max_files, mi_exl->update));
@@ -208,8 +209,13 @@ int mi_examine_log(MI_EXAMINE_LOG_PARAM
bzero(mi_exl->com_count,sizeof(mi_exl->com_count));
init_tree(&tree,0,0,sizeof(file_info),(qsort_cmp2) file_info_compare,1,
(tree_element_free) file_info_free, NULL);
- (void) init_key_cache(dflt_key_cache,KEY_CACHE_BLOCK_SIZE,KEY_CACHE_SIZE,
- 0, 0);
+ /*
+ init_key_cache() returns the number of cache blocks allocated, if
+ *this* call allocated them. If the function fails, or if the cache
+ was already initialized before, it returns zero.
+ */
+ key_cache_blocks= init_key_cache(dflt_key_cache, KEY_CACHE_BLOCK_SIZE,
+ KEY_CACHE_SIZE, 0, 0);
/*
Initialize members of file_info that are used for pointing to
@@ -778,7 +784,9 @@ int mi_examine_log(MI_EXAMINE_LOG_PARAM
}
DBUG_PRINT("myisamlog", ("end loop access_time: %lu cmd_cnt: %lu",
access_time, mi_exl->number_of_commands));
- end_key_cache(dflt_key_cache,1);
+ /* End the key cache only if it was initialized by this function. */
+ if (key_cache_blocks)
+ end_key_cache(dflt_key_cache,1);
delete_tree(&tree);
(void) end_io_cache(&cache);
(void) my_close(log_file,MYF(0));
@@ -803,7 +811,9 @@ int mi_examine_log(MI_EXAMINE_LOG_PARAM
fflush(stderr);
end:
DBUG_PRINT("myisamlog", ("end label"));
- end_key_cache(dflt_key_cache, 1);
+ /* End the key cache only if it was initialized by this function. */
+ if (key_cache_blocks)
+ end_key_cache(dflt_key_cache, 1);
delete_tree(&tree);
(void) end_io_cache(&cache);
(void) my_close(log_file,MYF(0));
Attachment: [text/bzr-bundle] bzr/ingo.struewing@sun.com-20090403094439-0bxx74tvwpsdivyc.bundle