3016 Alexander Nozdrin 2009-02-11
Update default.conf
modified:
.bzr-mysql/default.conf
3015 Hakan Kuecuekyilmaz 2009-02-10 [merge]
Merged:
mysql-6.0 --> mysql-6.0-falcon.
removed:
mysql-test/suite/ndb/r/ndb_discover_db2.result
mysql-test/suite/ndb/t/ndb_discover_db2-master.opt
mysql-test/suite/ndb/t/ndb_discover_db2.test
mysql-test/suite/ndb/t/ndb_partition_error2-master.opt
mysql-test/suite/ndb/t/ndb_restore_partition-master.opt
mysql-test/suite/rpl_ndb_big/t/rpl_ndb_dd_partitions-master.opt
mysql-test/suite/rpl_ndb_big/t/rpl_ndb_dd_partitions-slave.opt
mysql-test/suite/rpl_ndb_big/t/rpl_truncate_7ndb_2-master.opt
added:
mysql-test/suite/ndb/r/ndb_dd_ddl_grant.result
mysql-test/suite/ndb/t/ndb_dd_ddl_grant.test
mysql-test/suite/ndb_binlog/my.cnf
mysql-test/suite/ndb_team/my.cnf
mysql-test/suite/rpl_ndb_big/my.cnf
mysql-test/suite/rpl_ndb_big/t/rpl_ndb_dd_partitions-master.opt
mysql-test/suite/rpl_ndb_big/t/rpl_ndb_dd_partitions-slave.opt
storage/ndb/src/mgmapi/mgmapi_error.c
storage/ndb/test/run-test/conf-upgrade.cnf
storage/ndb/test/run-test/upgrade-tests.txt
modified:
.bzrignore
Makefile.am
configure.in
extra/perror.c
mysql-test/Makefile.am
mysql-test/lib/v1/mysql-test-run.pl
mysql-test/lib/v1/ndb_config_1_node.ini
mysql-test/lib/v1/ndb_config_2_node.ini
mysql-test/mysql-test-run.pl
mysql-test/r/partition_mgm.result
mysql-test/std_data/ndb_config_config.ini
mysql-test/suite/ndb/my.cnf
mysql-test/suite/ndb/r/bug36547.result
mysql-test/suite/ndb/r/ndb_basic.result
mysql-test/suite/ndb/r/ndb_config.result
mysql-test/suite/ndb/r/ndb_dbug_lock.result
mysql-test/suite/ndb/r/ndb_dd_ddl.result
mysql-test/suite/ndb/r/ndb_discover_db.result
mysql-test/suite/ndb/r/ndb_read_multi_range.result
mysql-test/suite/ndb/t/bug36547.test
mysql-test/suite/ndb/t/ndb_dbug_lock.test
mysql-test/suite/ndb/t/ndb_dd_ddl.test
mysql-test/suite/ndb/t/ndb_dd_dump.test
mysql-test/suite/ndb/t/ndb_discover_db.test
mysql-test/suite/ndb/t/ndb_read_multi_range.test
mysql-test/suite/ndb/t/ndb_restore_partition.test
mysql-test/suite/ndb_binlog/r/ndb_binlog_basic.result
mysql-test/suite/ndb_binlog/r/ndb_binlog_restore.result
mysql-test/suite/ndb_binlog/t/ndb_binlog_basic.test
mysql-test/suite/ndb_team/r/rpl_ndb_extraColMaster.result
mysql-test/suite/ndb_team/t/rpl_ndb_dd_advance.test
mysql-test/suite/parts/r/partition_auto_increment_ndb.result
mysql-test/suite/rpl_ndb/my.cnf
mysql-test/suite/rpl_ndb_big/r/rpl_ndb_2innodb.result
mysql-test/suite/rpl_ndb_big/r/rpl_ndb_2myisam.result
mysql-test/suite/rpl_ndb_big/r/rpl_ndb_sync.result
mysql-test/suite/rpl_ndb_big/t/rpl_ndb_2innodb-master.opt
mysql-test/suite/rpl_ndb_big/t/rpl_ndb_2innodb.test
mysql-test/suite/rpl_ndb_big/t/rpl_ndb_2myisam-master.opt
mysql-test/suite/rpl_ndb_big/t/rpl_ndb_2myisam.test
mysql-test/suite/rpl_ndb_big/t/rpl_ndb_apply_status.test
mysql-test/suite/rpl_ndb_big/t/rpl_truncate_7ndb_2.test
mysql-test/t/partition_mgm.test
scripts/make_binary_distribution.sh
scripts/mysql_system_tables.sql
sql/ha_ndbcluster.cc
sql/ha_ndbcluster_binlog.cc
sql/mysqld.cc
sql/set_var.cc
sql/slave.cc
sql/sql_partition.cc
storage/csv/ha_tina.cc
storage/ndb/include/mgmapi/mgmapi.h
storage/ndb/include/mgmapi/mgmapi_config_parameters.h
storage/ndb/include/mgmapi/mgmapi_error.h
storage/ndb/include/mgmapi/ndb_logevent.h
storage/ndb/include/ndbapi/NdbScanOperation.hpp
storage/ndb/include/util/Bitmask.hpp
storage/ndb/src/common/portlib/NdbThread.c
storage/ndb/src/common/util/Bitmask.cpp
storage/ndb/src/kernel/blocks/ERROR_codes.txt
storage/ndb/src/kernel/blocks/backup/Backup.cpp
storage/ndb/src/kernel/blocks/backup/Backup.hpp
storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
storage/ndb/src/kernel/blocks/dbutil/DbUtil.cpp
storage/ndb/src/kernel/blocks/lgman.cpp
storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
storage/ndb/src/kernel/vm/Configuration.cpp
storage/ndb/src/mgmapi/Makefile.am
storage/ndb/src/mgmapi/ndb_logevent.cpp
storage/ndb/src/mgmsrv/MgmtSrvr.cpp
storage/ndb/src/mgmsrv/MgmtSrvr.hpp
storage/ndb/src/mgmsrv/Services.cpp
storage/ndb/src/mgmsrv/Services.hpp
storage/ndb/src/ndbapi/ClusterMgr.cpp
storage/ndb/src/ndbapi/ClusterMgr.hpp
storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp
storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp
storage/ndb/src/ndbapi/NdbScanOperation.cpp
storage/ndb/src/ndbapi/Ndbif.cpp
storage/ndb/src/ndbapi/TransporterFacade.hpp
storage/ndb/src/ndbapi/ndberror.c
storage/ndb/test/include/DbUtil.hpp
storage/ndb/test/ndbapi/testBasic.cpp
storage/ndb/test/ndbapi/testMgm.cpp
storage/ndb/test/ndbapi/testNodeRestart.cpp
storage/ndb/test/ndbapi/testScan.cpp
storage/ndb/test/ndbapi/testUpgrade.cpp
storage/ndb/test/run-test/Makefile.am
storage/ndb/test/run-test/atrt-gather-result.sh
storage/ndb/test/run-test/atrt.hpp
storage/ndb/test/run-test/autotest-boot.sh
storage/ndb/test/run-test/autotest-run.sh
storage/ndb/test/run-test/command.cpp
storage/ndb/test/run-test/daily-basic-tests.txt
storage/ndb/test/run-test/db.cpp
storage/ndb/test/run-test/files.cpp
storage/ndb/test/run-test/main.cpp
storage/ndb/test/run-test/setup.cpp
storage/ndb/test/src/DbUtil.cpp
storage/ndb/test/src/HugoTransactions.cpp
storage/ndb/test/src/NDBT_Tables.cpp
storage/ndb/test/tools/log_listner.cpp
storage/ndb/tools/waiter.cpp
=== modified file 'client/mysqldump.c'
--- a/client/mysqldump.c 2009-01-31 16:21:19 +0000
+++ b/client/mysqldump.c 2009-02-05 08:46:40 +0000
@@ -3691,7 +3691,6 @@ static int dump_tablespaces(char* ts_whe
" EXTRA"
" FROM INFORMATION_SCHEMA.FILES"
" WHERE FILE_TYPE = 'UNDO LOG'"
- " AND ENGINE != 'Falcon'"
" AND FILE_NAME IS NOT NULL",
256, 1024);
if(ts_where)
@@ -3788,8 +3787,7 @@ static int dump_tablespaces(char* ts_whe
" INITIAL_SIZE,"
" ENGINE"
" FROM INFORMATION_SCHEMA.FILES"
- " WHERE FILE_TYPE = 'DATAFILE'"
- " AND ENGINE != 'Falcon'",
+ " WHERE FILE_TYPE IN('DATAFILE', 'USER DATAFILE')",
256, 1024);
if(ts_where)
@@ -3828,17 +3826,14 @@ static int dump_tablespaces(char* ts_whe
row[1]);
if (first)
{
- fprintf(md_result_file,
- " USE LOGFILE GROUP %s\n"
- " EXTENT_SIZE %s\n",
- row[2],
- row[3]);
- }
- fprintf(md_result_file,
- " INITIAL_SIZE %s\n"
- " ENGINE=%s;\n",
- row[4],
- row[5]);
+ if (row[2])
+ fprintf(md_result_file, " USE LOGFILE GROUP %s\n", row[2]);
+ if (row[3])
+ fprintf(md_result_file, " EXTENT_SIZE %s\n", row[3]);
+ }
+ if (row[4])
+ fprintf(md_result_file, " INITIAL_SIZE %s\n", row[4]);
+ fprintf(md_result_file, " ENGINE=%s;\n", row[5]);
check_io(md_result_file);
if (first)
{
=== modified file 'extra/CMakeLists.txt'
--- a/extra/CMakeLists.txt 2008-12-12 07:48:03 +0000
+++ b/extra/CMakeLists.txt 2008-12-15 12:41:10 +0000
@@ -46,8 +46,6 @@ TARGET_LINK_LIBRARIES(perror strings mys
ADD_EXECUTABLE(resolveip resolveip.c)
TARGET_LINK_LIBRARIES(resolveip strings mysys dbug)
-ADD_EXECUTABLE(resolveip resolveip.c)
-TARGET_LINK_LIBRARIES(resolveip strings mysys debug dbug wsock32)
ADD_EXECUTABLE(replace replace.c)
TARGET_LINK_LIBRARIES(replace strings mysys dbug)
=== modified file 'mysql-test/Makefile.am'
--- a/mysql-test/Makefile.am 2009-02-02 22:37:44 +0000
+++ b/mysql-test/Makefile.am 2009-02-10 22:07:35 +0000
@@ -126,6 +126,7 @@ install_test_files:
dist-hook:
$(MAKE) INSTALL_TO_DIR="$(distdir)" install_test_files
+ $(INSTALL_DATA) $(srcdir)/include/*.txt $(distdir)/include
install-data-local:
$(MAKE) INSTALL_TO_DIR="$(DESTDIR)$(testdir)" install_test_files
=== modified file 'mysql-test/include/wait_until_connected_again.inc'
--- a/mysql-test/include/wait_until_connected_again.inc 2009-01-26 16:32:29 +0000
+++ b/mysql-test/include/wait_until_connected_again.inc 2009-02-10 12:29:35 +0000
@@ -1,13 +1,17 @@
#
# Include this script to wait until the connection to the
# server has been restored or timeout occurs.
-# You should have done --enable_reconnect first
+#
+# You should have done --enable_reconnect first.
+#
# When you change this file you may have to chance its cousin
# wait_until_disconnected.inc
--disable_result_log
--disable_query_log
-let $counter= 600;
+# We wait for 7 minutes, because some storage engines need quite
+# some to restart with Valgrind runs on Pushbuild.
+let $counter= 4200;
let $mysql_errno= 9999;
while ($mysql_errno)
{
=== modified file 'mysql-test/lib/mtr_report.pm'
--- a/mysql-test/lib/mtr_report.pm 2009-02-04 12:34:03 +0000
+++ b/mysql-test/lib/mtr_report.pm 2009-02-10 22:07:35 +0000
@@ -30,6 +30,8 @@ our @EXPORT= qw(report_option mtr_print_
mtr_report_test);
use mtr_match;
+use My::Platform;
+use POSIX qw[ _exit ];
require "mtr_io.pl";
my $tot_real_time= 0;
@@ -428,7 +430,14 @@ sub mtr_warning (@) {
sub mtr_error (@) {
print STDERR _name(), _timestamp(),
"mysql-test-run: *** ERROR: ", join(" ", @_), "\n";
- exit(1);
+ if (IS_WINDOWS)
+ {
+ POSIX::_exit(1);
+ }
+ else
+ {
+ exit(1);
+ }
}
=== modified file 'mysql-test/lib/mtr_unique.pm'
--- a/mysql-test/lib/mtr_unique.pm 2008-08-22 17:03:15 +0000
+++ b/mysql-test/lib/mtr_unique.pm 2009-02-07 00:45:12 +0000
@@ -28,7 +28,17 @@ sub msg {
# print "### unique($$) - ", join(" ", @_), "\n";
}
-my $file= "/tmp/mysql-test-ports";
+my $file;
+
+if(!IS_WINDOWS)
+{
+ $file= "/tmp/mysql-test-ports";
+}
+else
+{
+ $file= $ENV{'TEMP'}."/mysql-test-ports";
+}
+
my %mtr_unique_ids;
=== modified file 'mysql-test/lib/v1/mysql-test-run.pl'
--- a/mysql-test/lib/v1/mysql-test-run.pl 2009-02-01 21:05:19 +0000
+++ b/mysql-test/lib/v1/mysql-test-run.pl 2009-02-10 22:07:35 +0000
@@ -2414,7 +2414,7 @@ sub setup_vardir() {
mtr_error("The destination for symlink $opt_vardir does not exist")
if ! -d readlink($opt_vardir);
}
- elsif ( $opt_mem )
+ elsif ( $opt_mem && !$glob_win32)
{
# Runinng with "var" as a link to some "memory" location, normally tmpfs
mtr_verbose("Creating $opt_mem");
=== modified file 'mysql-test/mysql-test-run.pl'
--- a/mysql-test/mysql-test-run.pl 2009-02-03 06:49:48 +0000
+++ b/mysql-test/mysql-test-run.pl 2009-02-10 22:07:35 +0000
@@ -268,7 +268,7 @@ sub main {
"bzr_mysql-6.0-ndb" => "ndb_team,rpl_ndb_big,ndb_binlog",
"bzr_mysql-6.0-falcon" => "falcon_team",
"bzr_mysql-6.0-falcon-team" => "falcon_team",
- "bzr_mysql-6.0-falcon-wlad" => "falcon_team",
+ "bzr_mysql-6.0-falcon-ann" => "falcon_team",
"bzr_mysql-6.0-falcon-chris" => "falcon_team",
"bzr_mysql-6.0-falcon-kevin" => "falcon_team",
);
@@ -2012,7 +2012,7 @@ sub setup_vardir() {
mtr_error("The destination for symlink $opt_vardir does not exist")
if ! -d readlink($opt_vardir);
}
- elsif ( $opt_mem )
+ elsif ( $opt_mem && !IS_WINDOWS)
{
# Runinng with "var" as a link to some "memory" location, normally tmpfs
mtr_verbose("Creating $opt_mem");
=== modified file 'mysql-test/suite/backup/r/backup_tablespace.result'
--- a/mysql-test/suite/backup/r/backup_tablespace.result 2008-11-12 15:23:22 +0000
+++ b/mysql-test/suite/backup/r/backup_tablespace.result 2009-02-02 11:17:53 +0000
@@ -51,7 +51,7 @@ DROP TABLESPACE bup_ts ENGINE=FALCON;
CREATE TABLESPACE bup_ts ADD DATAFILE 'different.dat' ENGINE=FALCON;
Now restore the database.
RESTORE FROM 'backup_ts.bak';
-ERROR HY000: Tablespace `bup_ts` needed by tables being restored, but the current tablespace definition differs from how it was when backup was made.
+ERROR HY000: Tablespace `BUP_TS` needed by tables being restored, but the current tablespace definition differs from how it was when backup was made.
Cleanup
DROP DATABASE IF EXISTS backup_ts;
DROP TABLESPACE bup_ts ENGINE=FALCON;
=== modified file 'mysql-test/suite/backup_engines/t/disabled.def'
--- a/mysql-test/suite/backup_engines/t/disabled.def 2008-11-18 21:10:05 +0000
+++ b/mysql-test/suite/backup_engines/t/disabled.def 2009-01-14 11:08:44 +0000
@@ -9,5 +9,3 @@
# Do not use any TAB characters for whitespace.
#
##############################################################################
-backup_ptr_mixed : Bug#37281 2008-11-18 hakank Dates in Falcon on big-endian have wrong result.
-backup_ptr_row : Bug#37281 2008-11-18 hakank Dates in Falcon on big-endian have wrong result.
=== added file 'mysql-test/suite/falcon/r/falcon_bug_26433-big.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_26433-big.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_26433-big.result 2008-12-18 22:35:43 +0000
@@ -0,0 +1,80 @@
+*** Bug #26433 ***
+SET @@storage_engine = 'Falcon';
+DROP TABLE IF EXISTS t1;
+DROP PROCEDURE IF EXISTS p1;
+SET @a = 707;
+CREATE PROCEDURE p1 ()
+BEGIN
+DECLARE v int default 0;
+DECLARE v500 int;
+DECLARE v499 int;
+DECLARE v255 int;
+DECLARE v99 int;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+DECLARE vx int;
+SELECT 'error, probably 1025';
+DROP TABLE t1;
+SELECT '1';
+CREATE TABLE t1 (
+a int,
+b varchar(500) character set latin1,
+c varchar(500) character set latin2
+);
+SET vx = 0;
+WHILE vx < 20 do
+INSERT INTO t1 VALUES (vx, null, null);
+SET vx = vx + 1;
+END WHILE;
+SELECT '2';
+CREATE INDEX i1 ON t1 (b, a);
+CREATE INDEX i2 ON t1 (c, a);
+SELECT '3';
+END;
+SELECT 'a';
+CREATE TABLE t1 (
+a int,
+b varchar(500) character set latin1,
+c varchar(500) character set latin2
+);
+SELECT 'b';
+SET v = 0;
+WHILE v < 20 do
+INSERT INTO t1 VALUES (v, null, null);
+SET v = v + 1;
+END WHILE;
+SELECT 'c';
+CREATE INDEX i1 ON t1 (b, a);
+CREATE INDEX i2 ON t1 (c, a);
+SELECT 'd';
+SET v = 0;
+WHILE v < 2000 DO
+SET v500 = rand(@a) * 500;
+SET v499 = rand(@a) * 499;
+SET v255 = rand(@a) * 255;
+SET v99 = rand(@a) * 99;
+SET @x = concat('update t1 set b = repeat(0x', hex(v500),',',v499,'), a =', v,', c = repeat(0x', hex(v255), ',',v99,')');
+/* SELECT v, @x; */
+PREPARE stmt1 FROM @x;
+EXECUTE stmt1;
+IF v mod 2 = 0 THEN
+ALTER TABLE t1 MODIFY COLUMN b varchar(500) character set latin2;
+ALTER TABLE t1 MODIFY COLUMN c varchar(500) character set latin1;
+ELSE
+ALTER TABLE t1 MODIFY COLUMN b varchar(500) character set latin1;
+ALTER TABLE t1 MODIFY COLUMN c varchar(500) character set latin2;
+END IF;
+SET v = v + 1;
+END WHILE;
+END//
+CALL p1()//
+a
+a
+b
+b
+c
+c
+d
+d
+DROP TABLE t1;
+DROP PROCEDURE p1;
=== renamed file 'mysql-test/suite/falcon_team/r/falcon_bug_26433.result' => 'mysql-test/suite/falcon/r/falcon_bug_26433.result'
--- a/mysql-test/suite/falcon_team/r/falcon_bug_26433.result 2008-04-24 04:09:39 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_26433.result 2008-12-18 22:35:43 +0000
@@ -1,15 +1,15 @@
-SET @@storage_engine = Falcon;
*** Bug #26433 ***
+SET @@storage_engine = 'Falcon';
DROP TABLE IF EXISTS t1;
DROP PROCEDURE IF EXISTS p1;
-SET @a = 909;
+SET @a = 707;
CREATE PROCEDURE p1 ()
BEGIN
DECLARE v int default 0;
DECLARE v500 int;
-DECLARE v499 int;
-DECLARE v255 int;
-DECLARE v99 int;
+DECLARE v499 int;
+DECLARE v255 int;
+DECLARE v99 int;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
DECLARE vx int;
@@ -46,13 +46,13 @@ END WHILE;
SELECT 'c';
CREATE INDEX i1 ON t1 (b, a);
CREATE INDEX i2 ON t1 (c, a);
-select 'd';
+SELECT 'd';
SET v = 0;
-while v < 500 do
+WHILE v < 250 DO
SET v500 = rand(@a) * 500;
-SET v499 = rand(@a) * 499;
-SET v255 = rand(@a) * 255;
-SET v99 = rand(@a) * 99;
+SET v499 = rand(@a) * 499;
+SET v255 = rand(@a) * 255;
+SET v99 = rand(@a) * 99;
SET @x = concat('update t1 set b = repeat(0x', hex(v500),',',v499,'), a =', v,', c = repeat(0x', hex(v255), ',',v99,')');
/* SELECT v, @x; */
PREPARE stmt1 FROM @x;
@@ -76,70 +76,5 @@ c
c
d
d
-Warnings:
-Warning 1265 Data truncated for column 'b' at row 20
-Warning 1265 Data truncated for column 'b' at row 21
-Warning 1265 Data truncated for column 'b' at row 22
-Warning 1265 Data truncated for column 'b' at row 23
-Warning 1265 Data truncated for column 'b' at row 24
-Warning 1265 Data truncated for column 'b' at row 25
-Warning 1265 Data truncated for column 'b' at row 26
-Warning 1265 Data truncated for column 'b' at row 27
-Warning 1265 Data truncated for column 'b' at row 28
-Warning 1265 Data truncated for column 'b' at row 29
-Warning 1265 Data truncated for column 'b' at row 30
-Warning 1265 Data truncated for column 'b' at row 31
-Warning 1265 Data truncated for column 'b' at row 32
-Warning 1265 Data truncated for column 'b' at row 33
-Warning 1265 Data truncated for column 'b' at row 34
-Warning 1265 Data truncated for column 'b' at row 35
-Warning 1265 Data truncated for column 'b' at row 36
-Warning 1265 Data truncated for column 'b' at row 37
-Warning 1265 Data truncated for column 'b' at row 38
-Warning 1265 Data truncated for column 'b' at row 39
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 1
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 2
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 3
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 4
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 5
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 6
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 7
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 8
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 9
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 10
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 11
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 12
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 13
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 14
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 15
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 16
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 17
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 18
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 19
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 20
-Warning 1265 Data truncated for column 'b' at row 20
-Warning 1265 Data truncated for column 'b' at row 21
-Warning 1265 Data truncated for column 'b' at row 22
-Warning 1265 Data truncated for column 'b' at row 23
-Warning 1265 Data truncated for column 'b' at row 24
-Warning 1265 Data truncated for column 'b' at row 25
-Warning 1265 Data truncated for column 'b' at row 26
-Warning 1265 Data truncated for column 'b' at row 27
-Warning 1265 Data truncated for column 'b' at row 28
-Warning 1265 Data truncated for column 'b' at row 29
-Warning 1265 Data truncated for column 'b' at row 30
-Warning 1265 Data truncated for column 'b' at row 31
-Warning 1265 Data truncated for column 'b' at row 32
-Warning 1265 Data truncated for column 'b' at row 33
-Warning 1265 Data truncated for column 'b' at row 34
-Warning 1265 Data truncated for column 'b' at row 35
-Warning 1265 Data truncated for column 'b' at row 36
-Warning 1265 Data truncated for column 'b' at row 37
-Warning 1265 Data truncated for column 'b' at row 38
-Warning 1265 Data truncated for column 'b' at row 39
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 1
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 2
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 3
-Warning 1366 Incorrect string value: '\x92\x92\x92\x92\x92\x92...' for column 'c' at row 4
DROP TABLE t1;
DROP PROCEDURE p1;
=== renamed file 'mysql-test/suite/falcon_team/r/falcon_bug_28048.result' => 'mysql-test/suite/falcon/r/falcon_bug_28048.result'
=== modified file 'mysql-test/suite/falcon/r/falcon_bug_29246.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_29246.result 2008-12-04 11:00:12 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_29246.result 2008-12-16 21:11:25 +0000
@@ -1,7 +1,7 @@
*** Bug #29246 ***
SET @@storage_engine = 'Falcon';
DROP TABLE IF EXISTS t1;
-CREATE TABLE t1 (s1 VARCHAR(2) CHARACTER SET latin1 COLLATE latin1_german2_ci, KEY (s1(1))) ENGINE=falcon;
+CREATE TABLE t1 (s1 VARCHAR(2) CHARACTER SET latin1 COLLATE latin1_german2_ci, KEY (s1(1)));
INSERT INTO t1 VALUES(0xdc),('ue');
SELECT COUNT(*) FROM t1 WHERE s1 = 0xdc;
COUNT(*)
@@ -9,6 +9,9 @@ COUNT(*)
SELECT COUNT(*) FROM t1 WHERE s1 = 'ue';
COUNT(*)
2
+SELECT COUNT(*) FROM t1 WHERE s1 = 'UE';
+COUNT(*)
+2
SELECT count(*) FROM t1;
count(*)
2
=== renamed file 'mysql-test/suite/falcon_team/r/falcon_bug_31296.result' => 'mysql-test/suite/falcon/r/falcon_bug_31296.result'
=== modified file 'mysql-test/suite/falcon/r/falcon_bug_32398.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_32398.result 2008-07-23 17:58:12 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_32398.result 2009-02-02 12:07:20 +0000
@@ -1,7 +1,20 @@
-CREATE TABLESPACE ts1 ADD DATAFILE 'test/ts1.fts' ENGINE=falcon;
-ERROR HY000: Incorrect arguments to DATAFILE
-CREATE TABLESPACE ts1 ADD DATAFILE 'MYSQLD_DATADIR/test/ts1.fts'
-ENGINE=falcon;
-ERROR HY000: Incorrect arguments to DATAFILE
-CREATE TABLESPACE ts1 ADD DATAFILE 'ts1.fts' ENGINE=falcon;
-DROP TABLESPACE ts1 ENGINE=falcon;
+*** Bug #32398 ***
+SET @@storage_engine = 'Falcon';
+CREATE TABLESPACE ts1 ADD DATAFILE 'ts1.fts' ENGINE='Falcon';
+CREATE TABLESPACE ts2 ADD DATAFILE 'ts2.MYD' ENGINE='Falcon';
+CREATE TABLESPACE ts3 ADD DATAFILE 'ts3' ENGINE='Falcon';
+CREATE TABLESPACE ts4 ADD DATAFILE 'ts4test' ENGINE='Falcon';
+CREATE TABLESPACE ts5 ADD DATAFILE '' ENGINE='Falcon';
+ERROR HY000: Malformed file path ''
+SELECT TABLESPACE_NAME, FILE_NAME FROM INFORMATION_SCHEMA.FILES;
+TABLESPACE_NAME FILE_NAME
+FALCON_USER falcon_user.fts
+FALCON_TEMPORARY falcon_temporary.fts
+TS1 ts1.fts
+TS2 ts2.MYD.fts
+TS3 ts3.fts
+TS4 ts4test.fts
+DROP TABLESPACE ts1 ENGINE='Falcon';
+DROP TABLESPACE ts2 ENGINE='Falcon';
+DROP TABLESPACE ts3 ENGINE='Falcon';
+DROP TABLESPACE ts4 ENGINE='Falcon';
=== modified file 'mysql-test/suite/falcon/r/falcon_bug_32833.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_32833.result 2008-12-11 01:21:12 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_32833.result 2009-01-22 15:11:47 +0000
@@ -1,11 +1,11 @@
-SET STORAGE_ENGINE = Falcon;
*** Bug #32833 ***
+SET @@storage_engine = 'Falcon';
DROP TABLE IF EXISTS t1;
DROP PROCEDURE IF EXISTS p1;
# Create table
CREATE TABLE t1 (int_column INT, char_column CHAR(5) CHARACTER SET UTF32)
PARTITION BY KEY(char_column);
-# Create and call procedure
+# Create and call procedure for populating table
SET @@autocommit=0;
CREATE PROCEDURE p1 ()
BEGIN
@@ -33,6 +33,9 @@ count(*)
ALTER TABLE t1 MODIFY COLUMN char_column CHAR(5) CHARACTER SET utf8;
# Add index to UTF8 column
CREATE INDEX i ON t1 (char_column);
+SELECT count(*) FROM t1;
+count(*)
+2802
# Final cleanup
DROP TABLE t1;
DROP PROCEDURE p1;
=== added file 'mysql-test/suite/falcon/r/falcon_bug_33148.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_33148.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_33148.result 2008-12-18 15:19:41 +0000
@@ -0,0 +1,18 @@
+*** Bug #33148 ***
+SET @@storage_engine = 'Falcon';
+DROP TABLE IF EXISTS t1;
+CREATE TABLESPACE ts1 ADD DATAFILE 'ts1.fts' ENGINE=Falcon;
+CREATE TABLE t1(a INT) ENGINE=Falcon TABLESPACE ts1;
+
+CREATE TABLESPACE TS1
+ ADD DATAFILE 'ts1.fts'
+ EXTENT_SIZE 0
+ ENGINE=Falcon;
+SET @saved_cs_client = @@character_set_client;
+SET character_set_client = utf8;
+CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) /*!50100 TABLESPACE `ts1` */ ENGINE=Falcon DEFAULT CHARSET=latin1;
+SET character_set_client = @saved_cs_client;
+DROP TABLE t1;
+DROP TABLESPACE ts1 ENGINE=Falcon;
=== added file 'mysql-test/suite/falcon/r/falcon_bug_33720.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_33720.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_33720.result 2008-12-19 10:47:17 +0000
@@ -0,0 +1,5 @@
+*** Bug #33720 ***
+SET @@storage_engine = 'Falcon';
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1(a INT) TABLESPACE FALCON_TEMPORARY;
+ERROR HY000: Cannot create non-temporary table 'T1' in 'FALCON_TEMPORARY' tablespace.
=== added file 'mysql-test/suite/falcon/r/falcon_bug_35257.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_35257.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_35257.result 2008-12-10 13:25:17 +0000
@@ -0,0 +1,6 @@
+*** Bug #35257 ***
+SET @@storage_engine = 'Falcon';
+CREATE TABLESPACE ts1 ADD DATAFILE 'ts1.fts' ENGINE=Falcon;
+CREATE TABLESPACE TS1 ADD DATAFILE 'ts2.fts' ENGINE=Falcon;
+ERROR HY000: Tablespace 'TS1' already exists
+DROP TABLESPACE ts1 ENGINE=Falcon;
=== added file 'mysql-test/suite/falcon/r/falcon_bug_36186.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_36186.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_36186.result 2009-01-13 19:14:09 +0000
@@ -0,0 +1,15 @@
+*** Bug #36186 ***
+SET @@storage_engine = 'Falcon';
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (s1 varchar(2) character set utf32);
+CREATE INDEX i ON t1 (s1);
+INSERT INTO t1 VALUES ('$$'),('00'),('>>');
+SELECT * FROM t1 WHERE s1 < 'a';
+s1
+$$
+00
+>>
+SELECT count(*) FROM t1;
+count(*)
+3
+DROP TABLE t1;
=== added file 'mysql-test/suite/falcon/r/falcon_bug_40607.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_40607.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_40607.result 2009-01-20 08:09:02 +0000
@@ -0,0 +1,20 @@
+*** Bug #40607 ***
+SET @@storage_engine = 'Falcon';
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (id decimal unsigned, key (id));
+INSERT INTO t1 VALUES (5),(6),(7), (8), (9);
+SELECT * FROM t1 WHERE id < 7;
+id
+5
+6
+SELECT * FROM t1 WHERE id = 7;
+id
+7
+SELECT * FROM t1 WHERE id > 7;
+id
+8
+9
+SELECT count(*) FROM t1;
+count(*)
+5
+DROP TABLE t1;
=== added file 'mysql-test/suite/falcon/r/falcon_bug_40801.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_40801.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_40801.result 2009-01-23 06:07:36 +0000
@@ -0,0 +1,98 @@
+#---- Bug 40801 ----
+SET @@storage_engine = 'Falcon';
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+CREATE TABLE t1 (a varchar(1000));
+INSERT INTO t1 VALUES (repeat('-', 1000));
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+CREATE TABLE t2 (f1 CHAR(10) PRIMARY KEY);
+INSERT INTO t2 VALUES ('-');
+UPDATE t2 SET f1 = 'A';
+UPDATE t2 SET f1 = 'B';
+UPDATE t2 SET f1 = 'C';
+UPDATE t2 SET f1 = 'D';
+# Establish connection con1 (user=root)
+BEGIN;
+SELECT * FROM t2;
+f1
+D
+SELECT * FROM t2 WHERE f1 = 'D';
+f1
+D
+# Use default client to commit an update;
+# Change the field value to 'A'
+UPDATE t2 SET f1 = 'A';
+# Establish connection con2 (user=root)
+BEGIN;
+SELECT * FROM t2;
+f1
+A
+SELECT * FROM t2 WHERE f1 = 'A';
+f1
+A
+# Use default client to commit an update;
+# Change the field value back to 'B'
+# and then 'C' in a second savepoint, then commit.
+BEGIN;
+UPDATE t2 SET f1 = 'B';
+SAVEPOINT sp1;
+UPDATE t2 SET f1 = 'C';
+RELEASE SAVEPOINT sp1;
+COMMIT;
+# Establish connection con3 (user=root)
+BEGIN;
+SELECT * FROM t2;
+f1
+C
+SELECT * FROM t2 WHERE f1 = 'C';
+f1
+C
+# Use default client to update value back to '-'
+UPDATE t2 SET f1 = '-';
+SELECT * FROM t2;
+f1
+-
+SELECT * FROM t2 WHERE f1 = '-';
+f1
+-
+# There are now two record versions with 'A' and two with 'C'
+# This update should cause a scavenge to prune old records.
+UPDATE t1 SET a = repeat('a',1000);
+SELECT * FROM t2;
+f1
+D
+SELECT * FROM t2 WHERE f1 = 'D';
+f1
+D
+COMMIT;
+SELECT * FROM t2;
+f1
+A
+SELECT * FROM t2 WHERE f1 = 'A';
+f1
+A
+COMMIT;
+SELECT * FROM t2;
+f1
+C
+SELECT * FROM t2 WHERE f1 = 'C';
+f1
+C
+COMMIT;
+COMMIT;
+COMMIT;
+COMMIT;
+DROP TABLE t1;
+DROP TABLE t2;
=== added file 'mysql-test/suite/falcon/r/falcon_bug_41548.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_41548.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_41548.result 2008-12-29 09:57:26 +0000
@@ -0,0 +1,14 @@
+*** Bug #41548 ***
+SET @@storage_engine = 'Falcon';
+ALTER TABLESPACE ts1 ADD DATAFILE 'test.txt' ENGINE=Falcon;
+ERROR HY000: Falcon doesn't support ALTER TABLESPACE
+CREATE LOGFILE GROUP lg1 ADD UNDOFILE 'test.txt' ENGINE=Falcon;
+ERROR HY000: Falcon doesn't support CREATE LOGFILE GROUP
+ALTER LOGFILE GROUP lg1 ADD UNDOFILE 'test.txt' ENGINE=Falcon;
+ERROR HY000: Falcon doesn't support ALTER LOGFILE GROUP
+DROP LOGFILE GROUP lg1 ENGINE=Falcon;
+ERROR HY000: Falcon doesn't support DROP LOGFILE GROUP
+ALTER TABLESPACE ts1 CHANGE DATAFILE 'test.txt' INITIAL_SIZE=1;
+ERROR HY000: Falcon doesn't support CHANGE FILE TABLESPACE
+ALTER TABLESPACE ts1 READ_ONLY;
+ERROR HY000: Falcon doesn't support ALTER ACCESS MODE TABLESPACE
=== added file 'mysql-test/suite/falcon/r/falcon_bug_41582.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_41582.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_41582.result 2009-01-20 08:09:02 +0000
@@ -0,0 +1,142 @@
+*** Bug #41582 ***
+SET @@storage_engine = 'Falcon';
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1(id decimal(11,0), key(id));
+INSERT INTO t1 VALUES (4299999998), (4299999999), (4300000000), (4300000001), (4300000002);
+SELECT count(*) FROM t1;
+count(*)
+5
+SELECT * FROM t1 WHERE id > 4300000000;
+id
+4300000001
+4300000002
+SELECT * FROM t1 WHERE id = 4300000000;
+id
+4300000000
+SELECT * FROM t1 WHERE id < 4300000000;
+id
+4299999998
+4299999999
+DROP TABLE t1;
+CREATE TABLE t1(id numeric(11), key(id));
+INSERT INTO t1 VALUES (4299999998), (4299999999), (4300000000), (4300000001), (4300000002);
+SELECT count(*) FROM t1;
+count(*)
+5
+SELECT * FROM t1 WHERE id > 4300000000;
+id
+4300000001
+4300000002
+SELECT * FROM t1 WHERE id = 4300000000;
+id
+4300000000
+SELECT * FROM t1 WHERE id < 4300000000;
+id
+4299999998
+4299999999
+DROP TABLE t1;
+CREATE TABLE t1(id decimal(11,0), key(id));
+INSERT INTO t1 VALUES (11), (12), (13), (14), (15);
+SELECT count(*) FROM t1;
+count(*)
+5
+SELECT * FROM t1 WHERE id > 13;
+id
+14
+15
+SELECT * FROM t1 WHERE id = 13;
+id
+13
+SELECT * FROM t1 WHERE id < 13;
+id
+11
+12
+DROP TABLE t1;
+CREATE TABLE t1(id numeric(11), key(id));
+INSERT INTO t1 VALUES (11), (12), (13), (14), (15);
+SELECT count(*) FROM t1;
+count(*)
+5
+SELECT * FROM t1 WHERE id > 13;
+id
+14
+15
+SELECT * FROM t1 WHERE id = 13;
+id
+13
+SELECT * FROM t1 WHERE id < 13;
+id
+11
+12
+DROP TABLE t1;
+CREATE TABLE t1(id decimal(13,3), key(id));
+INSERT INTO t1 VALUES (4299999998.123), (4299999998.125), (4300000000.123), (4300000000.125), (4300000002.123);
+SELECT count(*) FROM t1;
+count(*)
+5
+SELECT * FROM t1 WHERE id > 4300000000.123;
+id
+4300000000.125
+4300000002.123
+SELECT * FROM t1 WHERE id = 4300000000.123;
+id
+4300000000.123
+SELECT * FROM t1 WHERE id < 4300000000.123;
+id
+4299999998.123
+4299999998.125
+DROP TABLE t1;
+CREATE TABLE t1(id numeric(13,3), key(id));
+INSERT INTO t1 VALUES (4299999998.123), (4299999998.125), (4300000000.123), (4300000000.125), (4300000002.123);
+SELECT count(*) FROM t1;
+count(*)
+5
+SELECT * FROM t1 WHERE id > 4300000000.123;
+id
+4300000000.125
+4300000002.123
+SELECT * FROM t1 WHERE id = 4300000000.123;
+id
+4300000000.123
+SELECT * FROM t1 WHERE id < 4300000000.123;
+id
+4299999998.123
+4299999998.125
+DROP TABLE t1;
+CREATE TABLE t1(id decimal(7,2), key(id));
+INSERT INTO t1 VALUES (12.75), (13.10), (13.15), (13.27), (15.01);
+SELECT count(*) FROM t1;
+count(*)
+5
+SELECT * FROM t1 WHERE id > 13.15;
+id
+13.27
+15.01
+SELECT * FROM t1 WHERE id = 13.15;
+id
+13.15
+SELECT * FROM t1 WHERE id < 13.15;
+id
+12.75
+13.10
+DROP TABLE t1;
+CREATE TABLE t1(id numeric(7,2), key(id));
+INSERT INTO t1 VALUES (12.75), (13.10), (13.15), (13.27), (15.01);
+SELECT count(*) FROM t1;
+count(*)
+5
+SELECT * FROM t1 WHERE id > 13.15;
+id
+13.27
+15.01
+SELECT * FROM t1 WHERE id = 13.15;
+id
+13.15
+SELECT * FROM t1 WHERE id < 13.15;
+id
+12.75
+13.10
+SELECT count(*) FROM t1;
+count(*)
+5
+DROP TABLE t1;
=== added file 'mysql-test/suite/falcon/r/falcon_bug_42196.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_42196.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_42196.result 2009-01-21 16:48:25 +0000
@@ -0,0 +1,18 @@
+*** Bug #42196 ***
+SET @@storage_engine = 'Falcon';
+DROP TABLE IF EXISTS t1;
+DROP FUNCTION IF EXISTS f1;
+CREATE TABLE t1 (s1 bit(3), key(s1));
+CREATE FUNCTION f1() RETURNS int RETURN 1;
+INSERT INTO t1 VALUES (2*f1());
+SELECT s1+0 FROM t1 WHERE s1 = 2;
+s1+0
+2
+SELECT s1+0 from t1;
+s1+0
+2
+SELECT count(*) FROM t1;
+count(*)
+1
+DROP TABLE t1;
+DROP FUNCTION f1;
=== modified file 'mysql-test/suite/falcon/r/falcon_online_index.result'
--- a/mysql-test/suite/falcon/r/falcon_online_index.result 2008-10-15 06:12:14 +0000
+++ b/mysql-test/suite/falcon/r/falcon_online_index.result 2009-01-21 00:28:07 +0000
@@ -131,13 +131,12 @@ Table Non_unique Key_name Seq_in_index C
t1 0 PRIMARY 1 a NULL 10 NULL NULL BTREE
#-------- ONLINE: ALTER ADD/DROP PRIMARY KEY --------#
ALTER ONLINE TABLE t1 DROP PRIMARY KEY;
-ERROR 42000: This version of MySQL doesn't yet support 'ALTER ONLINE TABLE t1 DROP PRIMARY KEY'
-ALTER TABLE t1 DROP PRIMARY KEY;
-ALTER ONLINE TABLE t1 ADD PRIMARY KEY (c);
-ERROR 42000: This version of MySQL doesn't yet support 'ALTER ONLINE TABLE t1 ADD PRIMARY KEY (c)'
SHOW INDEXES FROM t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_Comment
-ALTER TABLE t1 ADD PRIMARY KEY (a);
+ALTER ONLINE TABLE t1 ADD PRIMARY KEY (a);
+SHOW INDEXES FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_Comment
+t1 0 PRIMARY 1 a NULL 10 NULL NULL BTREE
#-------- Test: UNIQUE --------#
ALTER ONLINE TABLE t2 ADD UNIQUE INDEX ix_unique_c (c);
EXPLAIN SELECT * FROM t2 WHERE c < 25 AND c > 20 ORDER BY c;
=== modified file 'mysql-test/suite/falcon/r/falcon_options.result'
--- a/mysql-test/suite/falcon/r/falcon_options.result 2008-12-10 21:45:53 +0000
+++ b/mysql-test/suite/falcon/r/falcon_options.result 2009-02-01 16:54:21 +0000
@@ -14,12 +14,12 @@ falcon_index_chill_threshold 4194304
falcon_io_threads 2
falcon_large_blob_threshold 160000
falcon_lock_wait_timeout 50
-falcon_page_cache_size 4194304
+falcon_page_cache_size 262144000
falcon_page_size 4096
falcon_record_chill_threshold 5242880
falcon_record_memory_max 262144000
-falcon_record_scavenge_floor 50
-falcon_record_scavenge_threshold 67
+falcon_record_scavenge_floor 80
+falcon_record_scavenge_threshold 90
falcon_scavenge_schedule 15,45 * * * * *
falcon_serial_log_block_size 0
falcon_serial_log_buffers 20
@@ -41,7 +41,7 @@ SET GLOBAL falcon_serial_log_dir = '/foo
ERROR HY000: Variable 'falcon_serial_log_dir' is a read only variable
SELECT @@GLOBAL.falcon_page_cache_size;
@@GLOBAL.falcon_page_cache_size
-4194304
+262144000
SET GLOBAL falcon_page_cache_size = 8M;
ERROR HY000: Variable 'falcon_page_cache_size' is a read only variable
SELECT @@GLOBAL.falcon_page_size;
@@ -95,12 +95,12 @@ FALCON_INDEX_CHILL_THRESHOLD 1073741824
FALCON_IO_THREADS 2
FALCON_LARGE_BLOB_THRESHOLD 160000
FALCON_LOCK_WAIT_TIMEOUT 50
-FALCON_PAGE_CACHE_SIZE 4194304
+FALCON_PAGE_CACHE_SIZE 262144000
FALCON_PAGE_SIZE 4096
FALCON_RECORD_CHILL_THRESHOLD 1073741824
FALCON_RECORD_MEMORY_MAX 536870912
-FALCON_RECORD_SCAVENGE_FLOOR 50
-FALCON_RECORD_SCAVENGE_THRESHOLD 67
+FALCON_RECORD_SCAVENGE_FLOOR 80
+FALCON_RECORD_SCAVENGE_THRESHOLD 90
FALCON_SCAVENGE_SCHEDULE 15,45 * * * * *
FALCON_SERIAL_LOG_BLOCK_SIZE 0
FALCON_SERIAL_LOG_BUFFERS 20
=== modified file 'mysql-test/suite/falcon/r/falcon_options2.result'
--- a/mysql-test/suite/falcon/r/falcon_options2.result 2008-12-10 21:45:53 +0000
+++ b/mysql-test/suite/falcon/r/falcon_options2.result 2009-02-01 16:54:21 +0000
@@ -14,12 +14,12 @@ FALCON_INDEX_CHILL_THRESHOLD 4194304
FALCON_IO_THREADS 2
FALCON_LARGE_BLOB_THRESHOLD 160000
FALCON_LOCK_WAIT_TIMEOUT 50
-FALCON_PAGE_CACHE_SIZE 4194304
+FALCON_PAGE_CACHE_SIZE 262144000
FALCON_PAGE_SIZE 4096
FALCON_RECORD_CHILL_THRESHOLD 5242880
FALCON_RECORD_MEMORY_MAX 262144000
-FALCON_RECORD_SCAVENGE_FLOOR 50
-FALCON_RECORD_SCAVENGE_THRESHOLD 67
+FALCON_RECORD_SCAVENGE_FLOOR 80
+FALCON_RECORD_SCAVENGE_THRESHOLD 90
FALCON_SCAVENGE_SCHEDULE 15,45 * * * * *
FALCON_SERIAL_LOG_BLOCK_SIZE 0
FALCON_SERIAL_LOG_BUFFERS 20
@@ -68,7 +68,7 @@ SELECT @@falcon_lock_wait_timeout;
50
SELECT @@falcon_page_cache_size;
@@falcon_page_cache_size
-4194304
+262144000
SELECT @@falcon_page_size;
@@falcon_page_size
4096
@@ -80,10 +80,10 @@ SELECT @@falcon_record_memory_max;
262144000
SELECT @@falcon_record_scavenge_floor;
@@falcon_record_scavenge_floor
-50
+80
SELECT @@falcon_record_scavenge_threshold;
@@falcon_record_scavenge_threshold
-67
+90
SELECT @@falcon_scavenge_schedule;
@@falcon_scavenge_schedule
15,45 * * * * *
=== added file 'mysql-test/suite/falcon/r/falcon_ps_repeatable_read.result'
--- a/mysql-test/suite/falcon/r/falcon_ps_repeatable_read.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/r/falcon_ps_repeatable_read.result 2009-02-03 20:46:05 +0000
@@ -0,0 +1,57 @@
+*** falcon_ps_03621 ***
+SET @@storage_engine = 'Falcon';
+DROP TABLE IF EXISTS t1;
+SET @@tx_isolation = 'REPEATABLE-READ';
+SET @@autocommit = 0;
+CREATE TABLE t1 (
+a char(3) character set latin1 collate latin1_bin NOT NULL default '000',
+b char(3) character set latin1 collate latin1_bin NOT NULL default '',
+c char(3) character set latin1 collate latin1_bin NOT NULL default '',
+d varchar(10) character set latin1 collate latin1_bin NOT NULL default '',
+e int(11) NOT NULL default '0',
+PRIMARY KEY (a,b,c),
+KEY i1 (b,d,e),
+KEY i2 (b,c)
+) DEFAULT CHARSET=latin1;
+COMMIT;
+SET @@storage_engine = 'Falcon';
+SET @@tx_isolation = 'REPEATABLE-READ';
+SET @@autocommit = 0;
+# Switch to connection default
+PREPARE stmt FROM
+'INSERT INTO t1 (a ,b ,c ,d ,e) VALUES ( ? , ? , ? , ? , ? )';
+SET @var1 = '000';
+SET @var2 = ' 0';
+SET @var3 = ' 0';
+SET @var4 = 'Text 001';
+SET @var5 = 0;
+EXECUTE stmt USING @var1, @var2, @var3, @var4, @var5;
+SET @var1 = '000';
+SET @var2 = ' 1';
+SET @var3 = ' 0';
+SET @var4 = 'Text 005';
+SET @var5 = 1;
+EXECUTE stmt USING @var1, @var2, @var3, @var4, @var5;
+DEALLOCATE PREPARE stmt ;
+COMMIT;
+BEGIN;
+PREPARE stmt FROM 'DELETE FROM t1 WHERE a = ? AND b = ?';
+SET @var1 = '000';
+SET @var2 = ' 0';
+EXECUTE stmt USING @var1, @var2;
+DEALLOCATE PREPARE stmt ;
+# Switch to connection conn1
+BEGIN;
+PREPARE stmt FROM 'UPDATE t1 SET d = ? WHERE a = ? AND b = ?';
+SET @var1 = 'error';
+SET @var2 = '000';
+SET @var3 = ' 1';
+EXECUTE stmt USING @var1, @var2, @var3;
+DEALLOCATE PREPARE stmt;
+COMMIT;
+# Switch to connection default
+COMMIT;
+SELECT count(*) FROM t1;
+count(*)
+1
+DROP TABLE t1;
=== modified file 'mysql-test/suite/falcon/t/disabled.def'
--- a/mysql-test/suite/falcon/t/disabled.def 2009-01-26 16:03:39 +0000
+++ b/mysql-test/suite/falcon/t/disabled.def 2009-02-09 10:33:13 +0000
@@ -10,6 +10,3 @@
#
##############################################################################
-falcon_bug_32398 : Bug#32398 2008-08-28 HF HF disabled until new fix for this bug is developed
-falcon_bug_28095 : Bug#40636 2008-12-10 hky Disabled until soft server restart works reliable
-falcon_bug_22173 : Bug#42079 2009-01-13 joro Falcon does not reset auto_increment on transactional truncate
=== modified file 'mysql-test/suite/falcon/t/falcon_bug.template'
--- a/mysql-test/suite/falcon/t/falcon_bug.template 2008-06-23 08:13:06 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug.template 2009-01-07 14:34:35 +0000
@@ -1,5 +1,10 @@
--source include/have_falcon.inc
+# If you use a "special" character set (such as ucs2, utf8, utf32),
+# then please source an appropriate include file to avoid test failure in
+# case of missing support for extra character sets in the binary, like this:
+# --source include/have_ucs2.inc
+
#
# Bug #<xyz>: <Bug description>
#
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_22180.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_22180.test 2007-09-29 04:30:42 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_22180.test 2009-01-07 10:41:07 +0000
@@ -1,4 +1,6 @@
--source include/have_falcon.inc
+--source include/have_utf8.inc
+
SET STORAGE_ENGINE = Falcon;
#
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_23689.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_23689.test 2007-09-29 04:30:42 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_23689.test 2009-01-07 10:41:07 +0000
@@ -1,4 +1,6 @@
--source include/have_falcon.inc
+--source include/have_utf8.inc
+
#
# Bug #23689: Falcon: searches fail if exotic collation and index exists
#
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_24511.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_24511.test 2007-09-29 04:30:42 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_24511.test 2009-01-07 10:41:07 +0000
@@ -1,4 +1,6 @@
--source include/have_falcon.inc
+--source include/have_utf8.inc
+
SET @@storage_engine = Falcon;
#
# Bug #24511: Falcon: BETWEEN fails with unicode field
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_24858.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_24858.test 2008-08-12 08:46:11 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_24858.test 2009-01-07 10:41:07 +0000
@@ -1,5 +1,7 @@
--source include/have_falcon.inc
--source include/have_ucs2.inc
+--source include/have_utf8.inc
+
SET storage_engine = Falcon;
#
# Bug #24858: Falcon: searches fail if partial index on utf8 column
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_24921.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_24921.test 2007-09-29 04:30:42 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_24921.test 2009-01-07 10:41:07 +0000
@@ -1,4 +1,6 @@
--source include/have_falcon.inc
+--source include/have_utf8.inc
+
SET @@storage_engine = Falcon;
#
# Bug #24921: LIKE searches fail if index on utf8 column
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_25555.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_25555.test 2007-09-29 04:30:42 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_25555.test 2009-01-07 10:41:07 +0000
@@ -1,4 +1,6 @@
--source include/have_falcon.inc
+--source include/have_utf8.inc
+
SET @@storage_engine = Falcon;
#
# Bug #25555 Falcon: crash if create index on nullable utf8 column
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_26057.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_26057.test 2007-09-29 04:30:42 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_26057.test 2009-01-07 10:41:07 +0000
@@ -1,4 +1,6 @@
--source include/have_falcon.inc
+--source include/have_utf8.inc
+
SET STORAGE_ENGINE = Falcon;
#
# Bug #26057: Falcon: UTF8 searches for accented character fail if index exists
=== added file 'mysql-test/suite/falcon/t/falcon_bug_26433-big.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_26433-big.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_26433-big.test 2008-12-18 22:35:43 +0000
@@ -0,0 +1,110 @@
+--source include/have_falcon.inc
+--source include/big_test.inc
+
+#
+# Bug #26433: Falcon: crash in procedure after error 1025
+#
+# Note: Big version with loop count of 2000.
+#
+--echo *** Bug #26433 ***
+
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP PROCEDURE IF EXISTS p1;
+--enable_warnings
+
+# Seed for rand() to get more predictable code path.
+# Seeds of 303 and 909 are producing a lot of warnings.
+#SET @a = 303;
+SET @a = 707;
+#SET @a = 909;
+
+DELIMITER //;
+CREATE PROCEDURE p1 ()
+BEGIN
+ DECLARE v int default 0;
+ DECLARE v500 int;
+ DECLARE v499 int;
+ DECLARE v255 int;
+ DECLARE v99 int;
+ DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+ BEGIN
+ DECLARE vx int;
+ SELECT 'error, probably 1025';
+ DROP TABLE t1;
+ SELECT '1';
+ CREATE TABLE t1 (
+ a int,
+ b varchar(500) character set latin1,
+ c varchar(500) character set latin2
+ );
+ SET vx = 0;
+ WHILE vx < 20 do
+ INSERT INTO t1 VALUES (vx, null, null);
+ SET vx = vx + 1;
+ END WHILE;
+ SELECT '2';
+ CREATE INDEX i1 ON t1 (b, a);
+ CREATE INDEX i2 ON t1 (c, a);
+ SELECT '3';
+ END;
+ SELECT 'a';
+ CREATE TABLE t1 (
+ a int,
+ b varchar(500) character set latin1,
+ c varchar(500) character set latin2
+ );
+ SELECT 'b';
+ SET v = 0;
+ WHILE v < 20 do
+ INSERT INTO t1 VALUES (v, null, null);
+ SET v = v + 1;
+ END WHILE;
+ SELECT 'c';
+ CREATE INDEX i1 ON t1 (b, a);
+ CREATE INDEX i2 ON t1 (c, a);
+ SELECT 'd';
+ SET v = 0;
+ WHILE v < 2000 DO
+ SET v500 = rand(@a) * 500;
+ SET v499 = rand(@a) * 499;
+ SET v255 = rand(@a) * 255;
+ SET v99 = rand(@a) * 99;
+ SET @x = concat('update t1 set b = repeat(0x', hex(v500),',',v499,'), a =', v,', c = repeat(0x', hex(v255), ',',v99,')');
+ /* SELECT v, @x; */
+ PREPARE stmt1 FROM @x;
+ EXECUTE stmt1;
+ IF v mod 2 = 0 THEN
+ ALTER TABLE t1 MODIFY COLUMN b varchar(500) character set latin2;
+ ALTER TABLE t1 MODIFY COLUMN c varchar(500) character set latin1;
+ ELSE
+ ALTER TABLE t1 MODIFY COLUMN b varchar(500) character set latin1;
+ ALTER TABLE t1 MODIFY COLUMN c varchar(500) character set latin2;
+ END IF;
+ SET v = v + 1;
+ END WHILE;
+END//
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+CALL p1()//
+
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+# Final sanity check not applicable here.
+#SELECT count(*) FROM t1;
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
+DELIMITER ;//
+DROP TABLE t1;
+DROP PROCEDURE p1;
=== renamed file 'mysql-test/suite/falcon_team/t/falcon_bug_26433.test' => 'mysql-test/suite/falcon/t/falcon_bug_26433.test'
--- a/mysql-test/suite/falcon_team/t/falcon_bug_26433.test 2008-04-24 04:09:39 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_26433.test 2008-12-18 22:35:43 +0000
@@ -1,26 +1,38 @@
--source include/have_falcon.inc
-SET @@storage_engine = Falcon;
+
#
# Bug #26433: Falcon: crash in procedure after error 1025
#
+# Note: Lowered loop count to 250 due to too long run time.
+# See corresponding -big test for long running version.
+#
--echo *** Bug #26433 ***
+
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
--disable_warnings
DROP TABLE IF EXISTS t1;
DROP PROCEDURE IF EXISTS p1;
--enable_warnings
# Seed for rand() to get more predictable code path.
-# Seed of 707 passes now.
-SET @a = 909;
+# Seeds of 303 and 909 are producing a lot of warnings.
+#SET @a = 303;
+SET @a = 707;
+#SET @a = 909;
DELIMITER //;
CREATE PROCEDURE p1 ()
BEGIN
DECLARE v int default 0;
DECLARE v500 int;
- DECLARE v499 int;
- DECLARE v255 int;
- DECLARE v99 int;
+ DECLARE v499 int;
+ DECLARE v255 int;
+ DECLARE v99 int;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
DECLARE vx int;
@@ -57,13 +69,13 @@ BEGIN
SELECT 'c';
CREATE INDEX i1 ON t1 (b, a);
CREATE INDEX i2 ON t1 (c, a);
- select 'd';
+ SELECT 'd';
SET v = 0;
- while v < 500 do
+ WHILE v < 250 DO
SET v500 = rand(@a) * 500;
- SET v499 = rand(@a) * 499;
- SET v255 = rand(@a) * 255;
- SET v99 = rand(@a) * 99;
+ SET v499 = rand(@a) * 499;
+ SET v255 = rand(@a) * 255;
+ SET v99 = rand(@a) * 99;
SET @x = concat('update t1 set b = repeat(0x', hex(v500),',',v499,'), a =', v,', c = repeat(0x', hex(v255), ',',v99,')');
/* SELECT v, @x; */
PREPARE stmt1 FROM @x;
@@ -79,9 +91,20 @@ BEGIN
END WHILE;
END//
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
CALL p1()//
-
-# Final cleanup.
DELIMITER ;//
+
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+# Final sanity check not applicable here.
+#SELECT count(*) FROM t1;
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
DROP TABLE t1;
DROP PROCEDURE p1;
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_27697.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_27697.test 2007-09-29 04:30:42 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_27697.test 2009-01-07 10:41:07 +0000
@@ -1,4 +1,6 @@
--source include/have_falcon.inc
+--source include/have_utf8.inc
+
#
# Bug #27697: Non-western-collation searches fail if index exists
#
=== renamed file 'mysql-test/suite/falcon_team/t/falcon_bug_28048.test' => 'mysql-test/suite/falcon/t/falcon_bug_28048.test'
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_29246.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_29246.test 2008-12-04 11:00:12 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_29246.test 2008-12-16 21:11:25 +0000
@@ -1,8 +1,8 @@
--source include/have_falcon.inc
#
-# Bug #29246: Falcon: searches fail if prefix index on latin1_german2_ci
-# column
+# Bug #29246: Falcon: searches fail if prefix index on
+# latin1_german2_ci column
#
--echo *** Bug #29246 ***
@@ -19,10 +19,11 @@ DROP TABLE IF EXISTS t1;
# ----------------------------------------------------- #
# --- Test --- #
# ----------------------------------------------------- #
-CREATE TABLE t1 (s1 VARCHAR(2) CHARACTER SET latin1 COLLATE latin1_german2_ci, KEY (s1(1))) ENGINE=falcon;
+CREATE TABLE t1 (s1 VARCHAR(2) CHARACTER SET latin1 COLLATE latin1_german2_ci, KEY (s1(1)));
INSERT INTO t1 VALUES(0xdc),('ue');
SELECT COUNT(*) FROM t1 WHERE s1 = 0xdc;
SELECT COUNT(*) FROM t1 WHERE s1 = 'ue';
+SELECT COUNT(*) FROM t1 WHERE s1 = 'UE';
# ----------------------------------------------------- #
# --- Check --- #
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_30480_A.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_30480_A.test 2008-09-15 01:36:19 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_30480_A.test 2009-01-07 10:41:07 +0000
@@ -1,5 +1,6 @@
--source include/have_falcon.inc
--source include/have_partition.inc
+--source include/have_utf8.inc
#
# Bug #30480: Falcon: searches fail if LIKE and key partition
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_30480_B.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_30480_B.test 2008-09-15 01:36:19 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_30480_B.test 2009-01-07 10:41:07 +0000
@@ -1,5 +1,6 @@
--source include/have_falcon.inc
--source include/have_partition.inc
+--source include/have_ucs2.inc
#
# Bug #30480: Falcon: searches fail if LIKE and key partition
=== renamed file 'mysql-test/suite/falcon_team/t/falcon_bug_31296.test' => 'mysql-test/suite/falcon/t/falcon_bug_31296.test'
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_32398.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_32398.test 2008-07-23 17:58:12 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_32398.test 2009-02-02 12:07:20 +0000
@@ -1,16 +1,35 @@
--source include/have_falcon.inc
#
-# BUG#32398 - Falcon: tablespace file can be table file
+# Bug #32398: Falcon: tablespace file can be table file
#
-#CREATE TABLE t1(a INT) DATA DIRECTORY='mysql';
---error ER_WRONG_ARGUMENTS
-CREATE TABLESPACE ts1 ADD DATAFILE 'test/ts1.fts' ENGINE=falcon;
+--echo *** Bug #32398 ***
-let $MYSQLD_DATADIR= `SELECT @@datadir`;
---replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
---error ER_WRONG_ARGUMENTS
-eval CREATE TABLESPACE ts1 ADD DATAFILE '$MYSQLD_DATADIR/test/ts1.fts'
-ENGINE=falcon;
-CREATE TABLESPACE ts1 ADD DATAFILE 'ts1.fts' ENGINE=falcon;
-DROP TABLESPACE ts1 ENGINE=falcon;
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+eval CREATE TABLESPACE ts1 ADD DATAFILE 'ts1.fts' ENGINE=$engine;
+eval CREATE TABLESPACE ts2 ADD DATAFILE 'ts2.MYD' ENGINE=$engine;
+eval CREATE TABLESPACE ts3 ADD DATAFILE 'ts3' ENGINE=$engine;
+eval CREATE TABLESPACE ts4 ADD DATAFILE 'ts4test' ENGINE=$engine;
+--error ER_BAD_PATH
+eval CREATE TABLESPACE ts5 ADD DATAFILE '' ENGINE=$engine;
+
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+SELECT TABLESPACE_NAME, FILE_NAME FROM INFORMATION_SCHEMA.FILES;
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
+eval DROP TABLESPACE ts1 ENGINE=$engine;
+eval DROP TABLESPACE ts2 ENGINE=$engine;
+eval DROP TABLESPACE ts3 ENGINE=$engine;
+eval DROP TABLESPACE ts4 ENGINE=$engine;
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_32833.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_32833.test 2007-12-19 18:55:35 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_32833.test 2009-01-07 10:41:07 +0000
@@ -1,12 +1,19 @@
--source include/have_falcon.inc
--source include/have_partition.inc
+--source include/have_utf32.inc
+--source include/have_utf8.inc
-SET STORAGE_ENGINE = Falcon;
#
# Bug #32833: : Falcon: crash creating utf8 index
#
--echo *** Bug #32833 ***
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
--disable_warnings
DROP TABLE IF EXISTS t1;
DROP PROCEDURE IF EXISTS p1;
@@ -16,7 +23,7 @@ DROP PROCEDURE IF EXISTS p1;
CREATE TABLE t1 (int_column INT, char_column CHAR(5) CHARACTER SET UTF32)
PARTITION BY KEY(char_column);
---echo # Create and call procedure
+--echo # Create and call procedure for populating table
SET @@autocommit=0;
delimiter //;
CREATE PROCEDURE p1 ()
@@ -49,10 +56,24 @@ ALTER TABLE t1 MODIFY COLUMN char_column
# SELECT int_column, hex(char_column) FROM t1;
--enable_warnings
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+
--echo # Add index to UTF8 column
CREATE INDEX i ON t1 (char_column);
# SELECT int_column, hex(char_column) FROM t1;
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+SELECT count(*) FROM t1;
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
+
--echo # Final cleanup
DROP TABLE t1;
DROP PROCEDURE p1;
=== added file 'mysql-test/suite/falcon/t/falcon_bug_33148.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_33148.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_33148.test 2008-12-18 07:30:35 +0000
@@ -0,0 +1,34 @@
+--source include/have_falcon.inc
+--source include/not_embedded.inc
+
+#
+# Bug #33148: falcon mysqldump does not include tablespace info
+#
+--echo *** Bug #33148 ***
+
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+CREATE TABLESPACE ts1 ADD DATAFILE 'ts1.fts' ENGINE=Falcon;
+CREATE TABLE t1(a INT) ENGINE=Falcon TABLESPACE ts1;
+
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+--exec $MYSQL_DUMP --compact test t1
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
+DROP TABLE t1;
+DROP TABLESPACE ts1 ENGINE=Falcon;
=== added file 'mysql-test/suite/falcon/t/falcon_bug_33720.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_33720.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_33720.test 2008-12-19 10:47:17 +0000
@@ -0,0 +1,31 @@
+--source include/have_falcon.inc
+
+#
+# Bug #33720: Falcon allows FALCON_TEMPORARY to be manually specified as a
+# tablespace
+#
+--echo *** Bug #33720 ***
+
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+--error ER_ILLEGAL_HA_CREATE_OPTION
+CREATE TABLE t1(a INT) TABLESPACE FALCON_TEMPORARY;
+
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
=== added file 'mysql-test/suite/falcon/t/falcon_bug_35257.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_35257.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_35257.test 2008-12-10 13:25:17 +0000
@@ -0,0 +1,28 @@
+--source include/have_falcon.inc
+
+#
+# Bug #35257: Falcon: tablespace names are case sensitive
+#
+--echo *** Bug #35257 ***
+
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+CREATE TABLESPACE ts1 ADD DATAFILE 'ts1.fts' ENGINE=Falcon;
+--error ER_TABLESPACE_EXIST
+CREATE TABLESPACE TS1 ADD DATAFILE 'ts2.fts' ENGINE=Falcon;
+
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
+DROP TABLESPACE ts1 ENGINE=Falcon;
=== added file 'mysql-test/suite/falcon/t/falcon_bug_36186.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_36186.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_36186.test 2009-01-13 19:14:09 +0000
@@ -0,0 +1,35 @@
+--source include/have_falcon.inc
+--source include/have_utf32.inc
+
+#
+# Bug #36186: Falcon: searches fail if value < 'a', length>1, index, utf32
+#
+--echo *** Bug #36186 ***
+
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+CREATE TABLE t1 (s1 varchar(2) character set utf32);
+CREATE INDEX i ON t1 (s1);
+INSERT INTO t1 VALUES ('$$'),('00'),('>>');
+SELECT * FROM t1 WHERE s1 < 'a';
+
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+SELECT count(*) FROM t1;
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
+DROP TABLE t1;
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_38304.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_38304.test 2008-09-08 11:51:19 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_38304.test 2009-01-07 10:41:07 +0000
@@ -1,4 +1,5 @@
--source include/have_falcon.inc
+--source include/have_utf8.inc
#
# Bug #<38304>: <Data contents becomes NULL if column name in Falcon table uses accented letters>
@@ -537,4 +538,4 @@ SELECT count(*) FROM t1;
# ----------------------------------------------------- #
# --- Final cleanup --- #
# ----------------------------------------------------- #
-DROP TABLE t1;
\ No newline at end of file
+DROP TABLE t1;
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_39708.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_39708.test 2008-11-27 08:45:16 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_39708.test 2009-01-07 10:41:07 +0000
@@ -1,4 +1,5 @@
--source include/have_falcon.inc
+--source include/have_utf8.inc
#
# Bug #39708: Falcon: non-descriptive error message when creating a big key
=== added file 'mysql-test/suite/falcon/t/falcon_bug_40607.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_40607.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_40607.test 2009-01-20 08:09:02 +0000
@@ -0,0 +1,35 @@
+--source include/have_falcon.inc
+
+#
+# Bug #40607: Falcon unsigned indexes broken
+#
+--echo *** Bug #40607 ***
+
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+CREATE TABLE t1 (id decimal unsigned, key (id));
+INSERT INTO t1 VALUES (5),(6),(7), (8), (9);
+SELECT * FROM t1 WHERE id < 7;
+SELECT * FROM t1 WHERE id = 7;
+SELECT * FROM t1 WHERE id > 7;
+
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+SELECT count(*) FROM t1;
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
+DROP TABLE t1;
=== added file 'mysql-test/suite/falcon/t/falcon_bug_40801.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_40801.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_40801.test 2009-01-23 06:07:36 +0000
@@ -0,0 +1,146 @@
+# Bug#40801 - Falcon garbage collection can erase valid key values
+# Note: This test creates a second file that is used just to start
+# a scavenge cycle in which records will get pruned.
+# This file is sized to force a scavenge cycle for pruning
+# using the current scavenger design and the default setting
+# for record cache size. This test will not cause a scavenge
+# with the old scavenger. See the bug for a script that
+# reproduces this with the old scavenger.
+
+--echo #---- Bug 40801 ----
+
+--source include/have_falcon.inc
+
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+--enable_warnings
+
+# Create a table to control scavenge cycles.
+# The new scavenger will scavenge for every (250Mb / 50) = 5Mb of record data.
+
+CREATE TABLE t1 (a varchar(1000));
+INSERT INTO t1 VALUES (repeat('-', 1000));
+INSERT INTO t1 SELECT * FROM t1; # 2,000
+INSERT INTO t1 SELECT * FROM t1; # 4,000
+INSERT INTO t1 SELECT * FROM t1; # 8,000
+INSERT INTO t1 SELECT * FROM t1; # 16,000
+INSERT INTO t1 SELECT * FROM t1; # 32,000
+INSERT INTO t1 SELECT * FROM t1; # 64,000
+INSERT INTO t1 SELECT * FROM t1; # 128,000
+INSERT INTO t1 SELECT * FROM t1; # 256,000
+INSERT INTO t1 SELECT * FROM t1; # 512,000
+INSERT INTO t1 SELECT * FROM t1; # 1,024,000
+INSERT INTO t1 SELECT * FROM t1; # 2,048,000
+INSERT INTO t1 SELECT * FROM t1; # 4,096,000
+INSERT INTO t1 SELECT * FROM t1; # 8,192,000
+# That should have caused at least one scavenge
+
+# Create a second table for the test.
+CREATE TABLE t2 (f1 CHAR(10) PRIMARY KEY);
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+
+INSERT INTO t2 VALUES ('-');
+UPDATE t2 SET f1 = 'A';
+UPDATE t2 SET f1 = 'B';
+UPDATE t2 SET f1 = 'C';
+UPDATE t2 SET f1 = 'D';
+
+--echo # Establish connection con1 (user=root)
+connect (con1,localhost,root,,);
+# Con1 - Should see 'D'
+BEGIN;
+SELECT * FROM t2;
+SELECT * FROM t2 WHERE f1 = 'D';
+
+--echo # Use default client to commit an update;
+--echo # Change the field value to 'A'
+connection default;
+UPDATE t2 SET f1 = 'A';
+
+--echo # Establish connection con2 (user=root)
+connect (con2,localhost,root,,);
+# Con2 - Should see 'A'
+BEGIN;
+SELECT * FROM t2;
+SELECT * FROM t2 WHERE f1 = 'A';
+
+--echo # Use default client to commit an update;
+--echo # Change the field value back to 'B'
+--echo # and then 'C' in a second savepoint, then commit.
+connection default;
+BEGIN;
+UPDATE t2 SET f1 = 'B';
+SAVEPOINT sp1;
+UPDATE t2 SET f1 = 'C';
+RELEASE SAVEPOINT sp1;
+COMMIT;
+
+--echo # Establish connection con3 (user=root)
+connect (con3,localhost,root,,);
+# Con3 - Should see 'C'
+BEGIN;
+SELECT * FROM t2;
+SELECT * FROM t2 WHERE f1 = 'C';
+
+--echo # Use default client to update value back to '-'
+connection default;
+UPDATE t2 SET f1 = '-';
+SELECT * FROM t2;
+SELECT * FROM t2 WHERE f1 = '-';
+
+--echo # There are now two record versions with 'A' and two with 'C'
+--echo # This update should cause a scavenge to prune old records.
+UPDATE t1 SET a = repeat('a',1000);
+
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+
+# con1 - Should still see 'D'
+connection con1;
+SELECT * FROM t2;
+SELECT * FROM t2 WHERE f1 = 'D';
+COMMIT;
+
+# con2 - Should still see 'A'
+connection con2;
+SELECT * FROM t2;
+SELECT * FROM t2 WHERE f1 = 'A';
+COMMIT;
+
+# con3 - Should see 'C'
+connection con3;
+SELECT * FROM t2;
+SELECT * FROM t2 WHERE f1 = 'C';
+COMMIT;
+
+# commit con1
+connection con1;
+COMMIT;
+
+# commit con2
+connection con2;
+COMMIT;
+
+# commit con3
+connection con3;
+COMMIT;
+
+#disconnect
+connection default;
+disconnect con1;
+disconnect con2;
+disconnect con3;
+
+DROP TABLE t1;
+DROP TABLE t2;
=== added file 'mysql-test/suite/falcon/t/falcon_bug_41548.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_41548.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_41548.test 2008-12-29 09:57:26 +0000
@@ -0,0 +1,37 @@
+--source include/have_falcon.inc
+
+#
+# Bug #41548: ALTER TABLESPACE does not work.
+#
+--echo *** Bug #41548 ***
+
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+--error ER_COM_UNSUPPORTED
+ALTER TABLESPACE ts1 ADD DATAFILE 'test.txt' ENGINE=Falcon;
+--error ER_COM_UNSUPPORTED
+CREATE LOGFILE GROUP lg1 ADD UNDOFILE 'test.txt' ENGINE=Falcon;
+--error ER_COM_UNSUPPORTED
+ALTER LOGFILE GROUP lg1 ADD UNDOFILE 'test.txt' ENGINE=Falcon;
+--error ER_COM_UNSUPPORTED
+DROP LOGFILE GROUP lg1 ENGINE=Falcon;
+--error ER_COM_UNSUPPORTED
+ALTER TABLESPACE ts1 CHANGE DATAFILE 'test.txt' INITIAL_SIZE=1;
+--error ER_COM_UNSUPPORTED
+ALTER TABLESPACE ts1 READ_ONLY;
+
+
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
=== added file 'mysql-test/suite/falcon/t/falcon_bug_41582.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_41582.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_41582.test 2009-01-20 08:09:02 +0000
@@ -0,0 +1,107 @@
+--source include/have_falcon.inc
+
+#
+# Bug #41582: Falcon index access returns no result for indexes with
+# numeric datatype
+#
+--echo *** Bug #41582 ***
+
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+
+# Testing first for the decimal type, then for the numeric type, which both map
+# the same internal type.
+
+# Using values with a precision greater than 9, because these will
+# not fit within a group of 4 bytes. For more information about the
+# storage representation of the decimal type, please see:
+#
+# http://dev.mysql.com/doc/refman/6.0/en/precision-math-decimal-changes.html
+#
+CREATE TABLE t1(id decimal(11,0), key(id));
+INSERT INTO t1 VALUES (4299999998), (4299999999), (4300000000), (4300000001), (4300000002);
+SELECT count(*) FROM t1;
+SELECT * FROM t1 WHERE id > 4300000000;
+SELECT * FROM t1 WHERE id = 4300000000;
+SELECT * FROM t1 WHERE id < 4300000000;
+DROP TABLE t1;
+
+CREATE TABLE t1(id numeric(11), key(id));
+INSERT INTO t1 VALUES (4299999998), (4299999999), (4300000000), (4300000001), (4300000002);
+SELECT count(*) FROM t1;
+SELECT * FROM t1 WHERE id > 4300000000;
+SELECT * FROM t1 WHERE id = 4300000000;
+SELECT * FROM t1 WHERE id < 4300000000;
+DROP TABLE t1;
+
+# Testing again using values with a precision less than 9
+CREATE TABLE t1(id decimal(11,0), key(id));
+INSERT INTO t1 VALUES (11), (12), (13), (14), (15);
+SELECT count(*) FROM t1;
+SELECT * FROM t1 WHERE id > 13;
+SELECT * FROM t1 WHERE id = 13;
+SELECT * FROM t1 WHERE id < 13;
+DROP TABLE t1;
+
+CREATE TABLE t1(id numeric(11), key(id));
+INSERT INTO t1 VALUES (11), (12), (13), (14), (15);
+SELECT count(*) FROM t1;
+SELECT * FROM t1 WHERE id > 13;
+SELECT * FROM t1 WHERE id = 13;
+SELECT * FROM t1 WHERE id < 13;
+DROP TABLE t1;
+
+# We also check some numbers with a scale different than 0 just to be
+# on the safe side. We do this for precision both greater than and
+# less than 9
+CREATE TABLE t1(id decimal(13,3), key(id));
+INSERT INTO t1 VALUES (4299999998.123), (4299999998.125), (4300000000.123), (4300000000.125), (4300000002.123);
+SELECT count(*) FROM t1;
+SELECT * FROM t1 WHERE id > 4300000000.123;
+SELECT * FROM t1 WHERE id = 4300000000.123;
+SELECT * FROM t1 WHERE id < 4300000000.123;
+DROP TABLE t1;
+
+CREATE TABLE t1(id numeric(13,3), key(id));
+INSERT INTO t1 VALUES (4299999998.123), (4299999998.125), (4300000000.123), (4300000000.125), (4300000002.123);
+SELECT count(*) FROM t1;
+SELECT * FROM t1 WHERE id > 4300000000.123;
+SELECT * FROM t1 WHERE id = 4300000000.123;
+SELECT * FROM t1 WHERE id < 4300000000.123;
+DROP TABLE t1;
+
+CREATE TABLE t1(id decimal(7,2), key(id));
+INSERT INTO t1 VALUES (12.75), (13.10), (13.15), (13.27), (15.01);
+SELECT count(*) FROM t1;
+SELECT * FROM t1 WHERE id > 13.15;
+SELECT * FROM t1 WHERE id = 13.15;
+SELECT * FROM t1 WHERE id < 13.15;
+DROP TABLE t1;
+
+CREATE TABLE t1(id numeric(7,2), key(id));
+INSERT INTO t1 VALUES (12.75), (13.10), (13.15), (13.27), (15.01);
+SELECT count(*) FROM t1;
+SELECT * FROM t1 WHERE id > 13.15;
+SELECT * FROM t1 WHERE id = 13.15;
+SELECT * FROM t1 WHERE id < 13.15;
+
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+SELECT count(*) FROM t1;
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
+DROP TABLE t1;
=== added file 'mysql-test/suite/falcon/t/falcon_bug_42196.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_42196.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_42196.test 2009-01-21 16:48:25 +0000
@@ -0,0 +1,42 @@
+--source include/have_falcon.inc
+
+#
+# Bug #42196: Issue with key look up for bit field in Falcon table after insert + stored func
+#
+--echo *** Bug #42196 ***
+
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP FUNCTION IF EXISTS f1;
+--enable_warnings
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+
+CREATE TABLE t1 (s1 bit(3), key(s1));
+CREATE FUNCTION f1() RETURNS int RETURN 1;
+INSERT INTO t1 VALUES (2*f1());
+
+# Following tatement failed to return any rows
+SELECT s1+0 FROM t1 WHERE s1 = 2;
+
+# Following statement returns row with value '2'
+SELECT s1+0 from t1;
+
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+SELECT count(*) FROM t1;
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
+DROP TABLE t1;
+DROP FUNCTION f1;
=== modified file 'mysql-test/suite/falcon/t/falcon_bugs.test'
--- a/mysql-test/suite/falcon/t/falcon_bugs.test 2008-11-26 12:58:17 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bugs.test 2009-01-06 09:09:27 +0000
@@ -10,6 +10,7 @@ DROP TABLE IF EXISTS t1;
--source include/have_falcon.inc
--source include/have_partition.inc
+--source include/have_ucs2.inc
SET @@storage_engine = Falcon;
=== modified file 'mysql-test/suite/falcon/t/falcon_bugs2.test'
--- a/mysql-test/suite/falcon/t/falcon_bugs2.test 2008-10-16 11:24:33 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bugs2.test 2009-01-07 10:41:07 +0000
@@ -5,6 +5,8 @@ DROP TABLE IF EXISTS t2;
--source include/have_falcon.inc
--source include/have_ucs2.inc
+--source include/have_utf8.inc
+
SET storage_engine=falcon;
# Verify that setting storage engine worked
=== modified file 'mysql-test/suite/falcon/t/falcon_deadlock_collection.test'
--- a/mysql-test/suite/falcon/t/falcon_deadlock_collection.test 2008-01-30 00:01:08 +0000
+++ b/mysql-test/suite/falcon/t/falcon_deadlock_collection.test 2008-12-18 10:49:29 +0000
@@ -1,4 +1,5 @@
--source include/have_falcon.inc
+
#
# Collection of deadlock related tests for Falcon.
#
=== modified file 'mysql-test/suite/falcon/t/falcon_online_index.test'
--- a/mysql-test/suite/falcon/t/falcon_online_index.test 2008-10-29 08:45:14 +0000
+++ b/mysql-test/suite/falcon/t/falcon_online_index.test 2009-02-02 11:17:53 +0000
@@ -194,16 +194,11 @@ SHOW INDEXES FROM t1;
--echo #-------- ONLINE: ALTER ADD/DROP PRIMARY KEY --------#
-# Adding/dropping PRIMARY KEY is not supposed to work ONLINE
---error ER_NOT_SUPPORTED_YET
ALTER ONLINE TABLE t1 DROP PRIMARY KEY;
-# Now drop primary key (offline) on 'a' temporarily in order to try adding one online
-ALTER TABLE t1 DROP PRIMARY KEY;
---error ER_NOT_SUPPORTED_YET
-ALTER ONLINE TABLE t1 ADD PRIMARY KEY (c);
SHOW INDEXES FROM t1;
# Re-set primary key on 'a'
-ALTER TABLE t1 ADD PRIMARY KEY (a);
+ALTER ONLINE TABLE t1 ADD PRIMARY KEY (a);
+SHOW INDEXES FROM t1;
##
## Testing some statement variations using ADD/DROP INDEX
=== added file 'mysql-test/suite/falcon/t/falcon_ps_repeatable_read.test'
--- a/mysql-test/suite/falcon/t/falcon_ps_repeatable_read.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/t/falcon_ps_repeatable_read.test 2009-02-03 20:46:05 +0000
@@ -0,0 +1,115 @@
+--source include/have_falcon.inc
+
+#
+# Prepared statement test with concurrent transaction.
+#
+# This test was designed for InnoDB's next key locking
+# behaviour in concurrent transactions. Falcon does not
+# have something like next key locking. We test to update
+# a record in $other_connection, while the active connection
+# has an open transaction.
+#
+--echo *** falcon_ps_03621 ***
+
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+SET @@tx_isolation = 'REPEATABLE-READ';
+SET @@autocommit = 0;
+
+CREATE TABLE t1 (
+ a char(3) character set latin1 collate latin1_bin NOT NULL default '000',
+ b char(3) character set latin1 collate latin1_bin NOT NULL default '',
+ c char(3) character set latin1 collate latin1_bin NOT NULL default '',
+ d varchar(10) character set latin1 collate latin1_bin NOT NULL default '',
+ e int(11) NOT NULL default '0',
+ PRIMARY KEY (a,b,c),
+ KEY i1 (b,d,e),
+ KEY i2 (b,c)
+) DEFAULT CHARSET=latin1;
+
+COMMIT;
+
+connect (conn1,localhost,root,,);
+eval SET @@storage_engine = $engine;
+SET @@tx_isolation = 'REPEATABLE-READ';
+SET @@autocommit = 0;
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+--echo # Switch to connection default
+connection default;
+PREPARE stmt FROM
+'INSERT INTO t1 (a ,b ,c ,d ,e) VALUES ( ? , ? , ? , ? , ? )';
+
+SET @var1 = '000';
+SET @var2 = ' 0';
+SET @var3 = ' 0';
+SET @var4 = 'Text 001';
+SET @var5 = 0;
+
+EXECUTE stmt USING @var1, @var2, @var3, @var4, @var5;
+
+SET @var1 = '000';
+SET @var2 = ' 1';
+SET @var3 = ' 0';
+SET @var4 = 'Text 005';
+SET @var5 = 1;
+
+EXECUTE stmt USING @var1, @var2, @var3, @var4, @var5;
+
+DEALLOCATE PREPARE stmt ;
+
+COMMIT;
+
+BEGIN;
+
+PREPARE stmt FROM 'DELETE FROM t1 WHERE a = ? AND b = ?';
+
+# SET vars
+SET @var1 = '000';
+SET @var2 = ' 0';
+
+EXECUTE stmt USING @var1, @var2;
+
+DEALLOCATE PREPARE stmt ;
+# No commit here!
+
+--echo # Switch to connection conn1
+connection conn1;
+BEGIN;
+
+PREPARE stmt FROM 'UPDATE t1 SET d = ? WHERE a = ? AND b = ?';
+
+SET @var1 = 'error';
+SET @var2 = '000';
+SET @var3 = ' 1';
+
+EXECUTE stmt USING @var1, @var2, @var3;
+
+DEALLOCATE PREPARE stmt;
+
+COMMIT;
+
+--echo # Switch to connection default
+connection default;
+COMMIT;
+
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+SELECT count(*) FROM t1;
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
+disconnect conn1;
+DROP TABLE t1;
=== modified file 'mysql-test/suite/falcon/t/falcon_select.test'
--- a/mysql-test/suite/falcon/t/falcon_select.test 2008-05-08 22:38:06 +0000
+++ b/mysql-test/suite/falcon/t/falcon_select.test 2009-01-07 10:41:07 +0000
@@ -3,6 +3,7 @@
#
--source include/have_falcon.inc
+--source include/have_utf8.inc
#
# Simple select test
=== modified file 'mysql-test/suite/falcon/t/falcon_unicode-big.test'
--- a/mysql-test/suite/falcon/t/falcon_unicode-big.test 2008-12-10 22:10:18 +0000
+++ b/mysql-test/suite/falcon/t/falcon_unicode-big.test 2009-01-07 10:41:07 +0000
@@ -1,5 +1,6 @@
--source include/have_falcon.inc
--source include/big_test.inc
+--source include/have_utf8.inc
#
# Unicode related tests for Falcon
=== removed file 'mysql-test/suite/falcon_team/r/falcon_bug_29246.result'
--- a/mysql-test/suite/falcon_team/r/falcon_bug_29246.result 2008-04-20 00:05:17 +0000
+++ b/mysql-test/suite/falcon_team/r/falcon_bug_29246.result 1970-01-01 00:00:00 +0000
@@ -1,13 +0,0 @@
-*** Bug #29246 ***
-SET @@storage_engine = 'Falcon';
-DROP TABLE IF EXISTS t1;
-CREATE TABLE t1 (a varchar(2) CHARACTER SET latin1 COLLATE latin1_german2_ci);
-INSERT INTO t1 VALUES (0xdc);
-CREATE INDEX i1 ON t1 (a(1));
-SELECT count(*) FROM t1 WHERE a = 'ue';
-count(*)
-1
-SELECT count(*) FROM t1;
-count(*)
-1
-DROP TABLE t1;
=== renamed file 'mysql-test/suite/falcon/r/falcon_bug_34351_C.result' => 'mysql-test/suite/falcon_team/r/falcon_bug_34351_C.result'
=== renamed file 'mysql-test/suite/falcon_team/r/falcon_bug_36294.result' => 'mysql-test/suite/falcon_team/r/falcon_bug_36294-big.result'
=== modified file 'mysql-test/suite/falcon_team/r/falcon_deadlock.result'
--- a/mysql-test/suite/falcon_team/r/falcon_deadlock.result 2008-04-20 00:05:17 +0000
+++ b/mysql-test/suite/falcon_team/r/falcon_deadlock.result 2009-02-05 13:23:27 +0000
@@ -1,8 +1,12 @@
-# Establish connection con1 (user=root)
-# Establish connection con2 (user=root)
+*** falcon_deadlock ***
+SET @@storage_engine = 'Falcon';
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
-# Switch to connection con1
+# Establish connection conn1 (user=root)
+SET @@storage_engine = 'Falcon';
+# Establish connection conn2 (user=root)
+SET @@storage_engine = 'Falcon';
+# Switch to connection conn1
CREATE TABLE t1 (
id integer,
x integer
@@ -12,43 +16,44 @@ SET @@autocommit = 0;
SELECT * FROM t1 WHERE id = 0 FOR UPDATE;
id x
0 0
-# Switch to connection con2
+# Switch to connection conn2
SET @@autocommit = 0;
UPDATE t1 SET x = 2 WHERE id = 0;
-# Switch to connection con1
+# Switch to connection conn1
UPDATE t1 SET x = 1 WHERE id = 0;
SELECT * FROM t1;
id x
0 1
COMMIT;
-# Switch to connection con2
-COMMIT;
-# Switch to connection con1
+# Switch to connection conn2
+ERROR HY000: Record has changed since last read in table 't1'
+ROLLBACK;
+# Switch to connection conn1
SELECT * FROM t1;
id x
-0 2
+0 1
COMMIT;
DROP TABLE t1;
-# Switch to connection con1
+# Switch to connection conn1
CREATE TABLE t1 (
id integer,
x integer
);
CREATE TABLE t2 (
-b integer,
-a integer
+a integer,
+b integer
);
INSERT INTO t1 VALUES (0, 0), (300, 300);
INSERT INTO t2 VALUES (0, 10), (1, 20), (2, 30);
COMMIT;
SELECT * FROM t2;
-b a
+a b
0 10
1 20
2 30
-UPDATE t2 SET a = 100 WHERE b = (SELECT x FROM t1 WHERE id = b FOR UPDATE);
+UPDATE t2 SET b = 100 WHERE a = (SELECT x FROM t1 WHERE id = a FOR UPDATE);
SELECT * FROM t2;
-b a
+a b
0 100
1 20
2 30
@@ -56,21 +61,22 @@ SELECT * FROM t1;
id x
0 0
300 300
-# Switch to connection con2
+# Switch to connection conn2
UPDATE t1 SET x = 2 WHERE id = 0;
-# Switch to connection con1
+# Switch to connection conn1
UPDATE t1 SET x = 1 WHERE id = 0;
SELECT * FROM t1;
id x
0 1
300 300
COMMIT;
-# Switch to connection con2
+# Switch to connection conn2
+ERROR HY000: Record has changed since last read in table 't1'
COMMIT;
-# Switch to connection con1
+# Switch to connection conn1
SELECT * FROM t1;
id x
-0 2
+0 1
300 300
COMMIT;
DROP TABLE t1;
@@ -80,21 +86,20 @@ id integer,
x integer
);
CREATE TABLE t2 (
-b integer,
-a integer
+a integer,
+b integer
);
INSERT INTO t1 VALUES (0, 0), (300, 300);
INSERT INTO t2 VALUES (0, 0), (1, 20), (2, 30);
COMMIT;
-# Switch to connection con1
SELECT a, b FROM t2 UNION SELECT id, x FROM t1 FOR UPDATE;
a b
0 0
-20 1
-30 2
+1 20
+2 30
300 300
SELECT * FROM t2;
-b a
+a b
0 0
1 20
2 30
@@ -102,29 +107,33 @@ SELECT * FROM t1;
id x
0 0
300 300
-# Switch to connection con2
+# Switch to connection conn2
UPDATE t2 SET a = 2 WHERE b = 0;
SELECT * FROM t2;
-b a
-0 2
+a b
+2 0
1 20
2 30
UPDATE t1 SET x = 2 WHERE id = 0;
-# Switch to connection con1
+# Switch to connection conn1
UPDATE t1 SET x = 1 WHERE id = 0;
SELECT * FROM t1;
id x
0 1
300 300
COMMIT;
-# Switch to connection con2
+# Switch to connection conn2
+ERROR HY000: Record has changed since last read in table 't1'
COMMIT;
-# Switch to connection con1
+# Switch to connection conn1
SELECT * FROM t1;
id x
-0 2
+0 1
300 300
COMMIT;
-# Switch to connection default + disconnect con1 and con2
+SELECT count(*) FROM t1;
+count(*)
+2
+# Switch to connection default + disconnect conn1 and conn2
DROP TABLE t1;
DROP TABLE t2;
=== removed file 'mysql-test/suite/falcon_team/t/falcon_bug_29246.test'
--- a/mysql-test/suite/falcon_team/t/falcon_bug_29246.test 2008-04-20 00:05:17 +0000
+++ b/mysql-test/suite/falcon_team/t/falcon_bug_29246.test 1970-01-01 00:00:00 +0000
@@ -1,34 +0,0 @@
---source include/have_falcon.inc
-#
-# Bug #29246: Falcon: searches fail if prefix index on latin1_german2_ci column
-#
---echo *** Bug #29246 ***
-
-# ----------------------------------------------------- #
-# --- Initialisation --- #
-# ----------------------------------------------------- #
-let $engine = 'Falcon';
-eval SET @@storage_engine = $engine;
-
---disable_warnings
-DROP TABLE IF EXISTS t1;
---enable_warnings
-
-CREATE TABLE t1 (a varchar(2) CHARACTER SET latin1 COLLATE latin1_german2_ci);
-INSERT INTO t1 VALUES (0xdc);
-CREATE INDEX i1 ON t1 (a(1));
-
-# ----------------------------------------------------- #
-# --- Test --- #
-# ----------------------------------------------------- #
-SELECT count(*) FROM t1 WHERE a = 'ue';
-
-# ----------------------------------------------------- #
-# --- Check --- #
-# ----------------------------------------------------- #
-SELECT count(*) FROM t1;
-
-# ----------------------------------------------------- #
-# --- Final cleanup --- #
-# ----------------------------------------------------- #
-DROP TABLE t1;
=== modified file 'mysql-test/suite/falcon_team/t/falcon_bug_34174.test'
--- a/mysql-test/suite/falcon_team/t/falcon_bug_34174.test 2008-07-22 14:16:22 +0000
+++ b/mysql-test/suite/falcon_team/t/falcon_bug_34174.test 2009-02-02 11:17:53 +0000
@@ -1,4 +1,5 @@
--source include/have_falcon.inc
+
#
# Bug #34174 - Infinite loop checking rolled back record in select for update
#
@@ -34,8 +35,8 @@ START TRANSACTION;
SELECT * FROM t1;
INSERT INTO t1 VALUES (1,1);
--send INSERT INTO t1 VALUES (0,3)
-#UPDATE t1 SET f1 = 0, f2 = 5;
-#INSERT INTO t1 VALUES (0,6);
+
+--real_sleep 1
--echo # switching to default connection
connection default;
@@ -62,4 +63,3 @@ SELECT * FROM t1;
connection default;
disconnect conn1;
DROP TABLE t1;
-
=== modified file 'mysql-test/suite/falcon_team/t/falcon_bug_34351_B.test'
--- a/mysql-test/suite/falcon_team/t/falcon_bug_34351_B.test 2008-07-22 14:16:22 +0000
+++ b/mysql-test/suite/falcon_team/t/falcon_bug_34351_B.test 2009-02-10 13:32:02 +0000
@@ -1,5 +1,5 @@
--source include/have_falcon.inc
-#--disable_abort_on_error
+
#
# Bug #34351_B: Update Conflict on non-overlapping transactions
#
@@ -46,6 +46,7 @@ SET @conn1_uuid = UUID();
SELECT t1_autoinc FROM t1 ORDER BY t1_autoinc;
INSERT INTO t1 (t1_uuid) VALUES (@conn1_uuid);
SELECT t1_autoinc FROM t1 ORDER BY t1_autoinc;
+--real_sleep 1
--send DELETE FROM t1 WHERE t1_uuid = (@conn1_uuid)
--echo # Switch to connection default
=== renamed file 'mysql-test/suite/falcon/t/falcon_bug_34351_C.test' => 'mysql-test/suite/falcon_team/t/falcon_bug_34351_C.test'
=== renamed file 'mysql-test/suite/falcon_team/t/falcon_bug_36294.test' => 'mysql-test/suite/falcon_team/t/falcon_bug_36294-big.test'
--- a/mysql-test/suite/falcon_team/t/falcon_bug_36294.test 2008-09-27 22:01:35 +0000
+++ b/mysql-test/suite/falcon_team/t/falcon_bug_36294-big.test 2008-12-16 21:11:25 +0000
@@ -1,4 +1,5 @@
--source include/have_falcon.inc
+--source include/big_test.inc
#
# Bug#36294: Assertion in Cache::writePage
=== modified file 'mysql-test/suite/falcon_team/t/falcon_deadlock.test'
--- a/mysql-test/suite/falcon_team/t/falcon_deadlock.test 2008-04-20 00:05:17 +0000
+++ b/mysql-test/suite/falcon_team/t/falcon_deadlock.test 2009-02-05 13:23:27 +0000
@@ -1,5 +1,6 @@
-- source include/have_falcon.inc
-- source include/not_embedded.inc
+
#
# This test was derived from innodb_deadlock.test,
# which sources in include/deadlock.inc.
@@ -7,15 +8,12 @@
# As Falcon has different behavior than InnoDB,
# we rewrote the parts in question.
#
-let $engine = Falcon;
-eval SET @@storage_engine = $engine;
-
---echo # Establish connection con1 (user=root)
-connect (con1,localhost,root,,);
-eval SET @@storage_engine = $engine;
+--echo *** falcon_deadlock ***
---echo # Establish connection con2 (user=root)
-connect (con2,localhost,root,,);
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
eval SET @@storage_engine = $engine;
--disable_warnings
@@ -23,62 +21,76 @@ DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
--enable_warnings
+--echo # Establish connection conn1 (user=root)
+connect (conn1,localhost,root,,);
+eval SET @@storage_engine = $engine;
+
+--echo # Establish connection conn2 (user=root)
+connect (conn2,localhost,root,,);
+eval SET @@storage_engine = $engine;
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+# Testing of SELECT ... FOR UPDATE, first take.
#
-# Testing of FOR UPDATE, first take.
-#
---echo # Switch to connection con1
-connection con1;
+--echo # Switch to connection conn1
+connection conn1;
CREATE TABLE t1 (
id integer,
x integer
);
-
INSERT INTO t1 VALUES (0, 0);
SET @@autocommit = 0;
SELECT * FROM t1 WHERE id = 0 FOR UPDATE;
---echo # Switch to connection con2
-connection con2;
+--echo # Switch to connection conn2
+connection conn2;
SET @@autocommit = 0;
-# The following query should hang because con1 is locking the record
---send UPDATE t1 SET x = 2 WHERE id = 0;
---real_sleep 2
+# The following query should hang because conn1 is locking the record
+--real_sleep 1
+--send UPDATE t1 SET x = 2 WHERE id = 0
---echo # Switch to connection con1
-connection con1;
+--echo # Switch to connection conn1
+connection conn1;
UPDATE t1 SET x = 1 WHERE id = 0;
SELECT * FROM t1;
COMMIT;
---echo # Switch to connection con2
-connection con2;
-# With Falcon we should get a
-# Record has changed since last read in table 't1' here.
+--echo # Switch to connection conn2
+connection conn2;
+# If we set Falcon to
+# falcon_consistent_read = off
+#
+# we should get a
+# Record has changed since last read in table 't1'
+# here. Please note that falcon_consistent_read = off
+# is the default setting.
--error ER_CHECKREAD
--reap
ROLLBACK;
---echo # Switch to connection con1
-connection con1;
+--echo # Switch to connection conn1
+connection conn1;
SELECT * FROM t1;
COMMIT;
DROP TABLE t1;
#
-# Testing of FOR UPDATE, second take.
+# Testing of SELECT ... FOR UPDATE, second take.
#
---echo # Switch to connection con1
-connection con1;
+--echo # Switch to connection conn1
+connection conn1;
CREATE TABLE t1 (
id integer,
x integer
);
CREATE TABLE t2 (
- b integer,
- a integer
+ a integer,
+ b integer
);
INSERT INTO t1 VALUES (0, 0), (300, 300);
@@ -86,44 +98,55 @@ INSERT INTO t2 VALUES (0, 10), (1, 20),
COMMIT;
SELECT * FROM t2;
-UPDATE t2 SET a = 100 WHERE b = (SELECT x FROM t1 WHERE id = b FOR UPDATE);
+UPDATE t2 SET b = 100 WHERE a = (SELECT x FROM t1 WHERE id = a FOR UPDATE);
SELECT * FROM t2;
SELECT * FROM t1;
---echo # Switch to connection con2
-connection con2;
+--echo # Switch to connection conn2
+connection conn2;
-# The following query should hang because con1 is locking the record
---send UPDATE t1 SET x = 2 WHERE id = 0;
---real_sleep 2
+# The following query should hang because conn1 is locking the record
+--real_sleep 1
+--send UPDATE t1 SET x = 2 WHERE id = 0
---echo # Switch to connection con1
-connection con1;
+--echo # Switch to connection conn1
+connection conn1;
UPDATE t1 SET x = 1 WHERE id = 0;
SELECT * FROM t1;
COMMIT;
---echo # Switch to connection con2
-connection con2;
+--echo # Switch to connection conn2
+connection conn2;
+# If we set Falcon to
+# falcon_consistent_read = off
+#
+# we should get a
+# Record has changed since last read in table 't1'
+# here. Please note that falcon_consistent_read = off
+# is the default setting.
+--error ER_CHECKREAD
--reap
COMMIT;
---echo # Switch to connection con1
-connection con1;
+--echo # Switch to connection conn1
+connection conn1;
SELECT * FROM t1;
COMMIT;
DROP TABLE t1;
DROP TABLE t2;
+#
+# Testing of SELECT ... FOR UPDATE, third take.
+#
CREATE TABLE t1 (
id integer,
x integer
);
CREATE TABLE t2 (
- b integer,
- a integer
+ a integer,
+ b integer
);
INSERT INTO t1 VALUES (0, 0), (300, 300);
@@ -134,35 +157,50 @@ SELECT a, b FROM t2 UNION SELECT id, x F
SELECT * FROM t2;
SELECT * FROM t1;
---echo # Switch to connection con2
-connection con2;
+--echo # Switch to connection conn2
+connection conn2;
-# The following query should hang because con1 is locking the record
+# The following query should hang because conn1 is locking the record
UPDATE t2 SET a = 2 WHERE b = 0;
SELECT * FROM t2;
---send UPDATE t1 SET x = 2 WHERE id = 0;
---real_sleep 2
+--real_sleep 1
+--send UPDATE t1 SET x = 2 WHERE id = 0
---echo # Switch to connection con1
-connection con1;
+--echo # Switch to connection conn1
+connection conn1;
UPDATE t1 SET x = 1 WHERE id = 0;
SELECT * FROM t1;
COMMIT;
---echo # Switch to connection con2
-connection con2;
+--echo # Switch to connection conn2
+connection conn2;
+# If we set Falcon to
+# falcon_consistent_read = off
+#
+# we should get a
+# Record has changed since last read in table 't1'
+# here. Please note that falcon_consistent_read = off
+# is the default setting.
+--error ER_CHECKREAD
--reap
COMMIT;
---echo # Switch to connection con1
-connection con1;
+--echo # Switch to connection conn1
+connection conn1;
SELECT * FROM t1;
COMMIT;
-# Cleanup
---echo # Switch to connection default + disconnect con1 and con2
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+SELECT count(*) FROM t1;
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
+--echo # Switch to connection default + disconnect conn1 and conn2
connection default;
-disconnect con1;
-disconnect con2;
-DROP TABLE t1,
+disconnect conn1;
+disconnect conn2;
+DROP TABLE t1;
DROP TABLE t2;
=== modified file 'mysql-test/suite/falcon_team/t/test2bug.def'
--- a/mysql-test/suite/falcon_team/t/test2bug.def 2008-10-02 10:37:27 +0000
+++ b/mysql-test/suite/falcon_team/t/test2bug.def 2009-02-10 13:32:02 +0000
@@ -17,7 +17,8 @@
# Keep the list sorted by test name.
#
-falcon_bug_23945: Bug#34892 - Transaction handling in select_create::abort let's Falcon fail
-falcon_bug_26433: Bug#39314 - falcon_bug_26433 fails with an offset of 1 in row numbers in expected warnings
-falcon_bug_28048: Bug#36700 - Running falcon_bug_28048 shows increasing memory usage and run time
+falcon_bug_34174 : Bug#34174 - Infinite loop checking rolled back record in select for update
+falcon_bug_36294-big: Bug#36631 - Assertion in SerialLogControl::nextRecord, sometimes.
falcon_deadlock: Bug#34182 - SELECT ... FOR UPDATE does not lock when in subquery
+falcon_bug_34351_B: Bug#42140 - falcon_bug_34351_B fails; sometimes
+falcon_bug_34351_C: Bug#41357 - falcon.falcon_bug_34351_C fails with assertion IS_CONSISTENT_READ
=== modified file 'scripts/make_win_bin_dist'
--- a/scripts/make_win_bin_dist 2008-11-11 12:44:05 +0000
+++ b/scripts/make_win_bin_dist 2009-01-09 16:41:06 +0000
@@ -165,12 +165,14 @@ cp libmysql/$TARGET/libmysql.dll
cp sql/$TARGET/mysqld.exe $DESTDIR/bin/mysqld$EXE_SUFFIX.exe
if [ x"$TARGET" != x"release" ] ; then
cp sql/$TARGET/mysqld.pdb $DESTDIR/bin/mysqld$EXE_SUFFIX.pdb
+ cp sql/$TARGET/mysqld.map $DESTDIR/bin/mysqld$EXE_SUFFIX.map
fi
if [ x"$PACK_DEBUG" = x"" -a -f "sql/debug/mysqld.exe" -o \
x"$PACK_DEBUG" = x"yes" ] ; then
cp sql/debug/mysqld.exe $DESTDIR/bin/mysqld-debug.exe
cp sql/debug/mysqld.pdb $DESTDIR/bin/mysqld-debug.pdb
+ cp sql/debug/mysqld.map $DESTDIR/bin/mysqld-debug.map
fi
# ----------------------------------------------------------------------
=== modified file 'sql/CMakeLists.txt'
--- a/sql/CMakeLists.txt 2009-01-26 16:03:39 +0000
+++ b/sql/CMakeLists.txt 2009-02-02 11:17:53 +0000
@@ -14,6 +14,12 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake")
+IF(MSVC)
+ #Innodb plugin needs linker-generated map file to locate server exports
+ #see bug#42001
+ SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MAP /MAPINFO:EXPORTS")
+ENDIF(MSVC)
+
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/extra/yassl/include
${CMAKE_SOURCE_DIR}/sql
=== modified file 'sql/share/errmsg.txt'
--- a/sql/share/errmsg.txt 2009-02-04 12:34:03 +0000
+++ b/sql/share/errmsg.txt 2009-02-10 22:07:35 +0000
@@ -6452,6 +6452,8 @@ ER_BACKUP_RESTORE_DBS
ER_WARN_ENGINE_TRANSACTION_ROLLBACK
eng "Storage engine %s does not support rollback for this statement. Transaction rolled back and must be restarted"
+ER_COM_UNSUPPORTED
+ eng "%s doesn't support %s"
ER_BACKUP_SYNCHRONIZE
eng "Backup failed to synchronize table images."
@@ -6461,3 +6463,4 @@ ER_OPERATION_ABORTED
eng "Operation aborted"
ER_OPERATION_ABORTED_CORRUPTED
eng "Operation aborted - data might be corrupted"
+
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2009-02-05 12:49:39 +0000
+++ b/sql/sql_select.cc 2009-02-10 22:07:35 +0000
@@ -2648,14 +2648,19 @@ JOIN::exec()
tmp_fields_list2, tmp_all_fields2,
fields_list.elements, tmp_all_fields1))
DBUG_VOID_RETURN;
- curr_join->tmp_fields_list2= tmp_fields_list2;
- curr_join->tmp_all_fields2= tmp_all_fields2;
+
+ if (curr_join != this)
+ {
+ curr_join->tmp_fields_list2= tmp_fields_list2;
+ curr_join->tmp_all_fields2= tmp_all_fields2;
+ }
+
}
curr_fields_list= &curr_join->tmp_fields_list2;
curr_all_fields= &curr_join->tmp_all_fields2;
curr_join->set_items_ref_array(items2);
curr_join->tmp_table_param.field_count+=
- curr_join->tmp_table_param.sum_func_count;
+ curr_join->tmp_table_param.sum_func_count;
curr_join->tmp_table_param.sum_func_count= 0;
}
if (curr_tmp_table->distinct)
=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc 2009-02-02 15:58:48 +0000
+++ b/sql/sql_show.cc 2009-02-10 22:07:35 +0000
@@ -5243,19 +5243,20 @@ static void store_schema_partitions_reco
else
table->field[23]->store(STRING_WITH_LEN("default"), cs);
- table->field[24]->set_notnull();
if (part_elem->tablespace_name)
+ {
+ table->field[24]->set_notnull();
table->field[24]->store(part_elem->tablespace_name,
strlen(part_elem->tablespace_name), cs);
- else
+ }
+ }
+ if (!part_elem || !part_elem->tablespace_name)
+ {
+ const char *ts= showing_table->file->get_tablespace_name();
+ if (ts)
{
- const char *ts= showing_table->file->get_tablespace_name();
- if(ts)
- {
- table->field[24]->store(ts, strlen(ts), cs);
- }
- else
- table->field[24]->set_null();
+ table->field[24]->set_notnull();
+ table->field[24]->store(ts, strlen(ts), cs);
}
}
return;
=== modified file 'sql/sql_tablespace.cc'
--- a/sql/sql_tablespace.cc 2008-07-14 12:49:19 +0000
+++ b/sql/sql_tablespace.cc 2008-12-29 09:57:26 +0000
@@ -17,6 +17,29 @@
#include "mysql_priv.h"
+
+static const char *str_ts_command_type[]=
+{
+ "UNKNOWN",
+ "CREATE TABLESPACE",
+ "ALTER TABLESPACE",
+ "CREATE LOGFILE GROUP",
+ "ALTER LOGFILE GROUP",
+ "DROP TABLESPACE",
+ "DROP LOGFILE GROUP",
+ "CHANGE FILE TABLESPACE",
+ "ALTER ACCESS MODE TABLESPACE"
+};
+
+
+static const char* get_str_ts_command_type(enum ts_command_type ts_cmd_type)
+{
+ if (ts_cmd_type < -1 || ts_cmd_type > 7)
+ ts_cmd_type= TS_CMD_NOT_DEFINED;
+ return str_ts_command_type[ts_cmd_type + 1];
+}
+
+
int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
{
int error= HA_ADMIN_NOT_IMPLEMENTED;
@@ -47,8 +70,8 @@ int mysql_alter_tablespace(THD *thd, st_
case 1:
DBUG_RETURN(1);
case HA_ADMIN_NOT_IMPLEMENTED:
-
- my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "");
+ my_error(ER_COM_UNSUPPORTED, MYF(0), hton_name(hton)->str,
+ get_str_ts_command_type(ts_info->ts_cmd_type));
break;
case HA_ERR_TABLESPACE_EXIST:
my_error(ER_TABLESPACE_EXIST, MYF(0), ts_info->tablespace_name);
=== modified file 'storage/falcon/BackLog.cpp'
--- a/storage/falcon/BackLog.cpp 2008-08-18 20:17:15 +0000
+++ b/storage/falcon/BackLog.cpp 2009-02-09 05:01:44 +0000
@@ -16,6 +16,7 @@
#include "Engine.h"
#include "BackLog.h"
#include "Database.h"
+#include "TableSpaceManager.h"
#include "Dbb.h"
#include "Section.h"
#include "Index.h"
@@ -33,16 +34,15 @@
static const char THIS_FILE[]=__FILE__;
#endif
-BackLog::BackLog(Database *db, const char *fileName)
+BackLog::BackLog(Database *db, const char *fileName) : database(db)
{
- database = db;
dbb = new Dbb(database->dbb, 0);
#ifndef FALCONDB
dbb->createPath(fileName);
#endif
dbb->create(fileName, dbb->pageSize, 0, HdrTableSpace, 0, NULL);
dbb->noLog = true;
- dbb->tableSpaceId = -1;
+ dbb->tableSpaceId = TABLESPACE_ID_BACKLOG; // reserved for internal use
int32 sectionId = Section::createSection (dbb, NO_TRANSACTION);
section = new Section(dbb, sectionId, NO_TRANSACTION);
recordsBacklogged = 0;
@@ -105,7 +105,7 @@ void BackLog::rollbackRecords(Bitmap* re
Table *table = record->format->table;
- if (!table->insert(record, NULL, record->recordNumber))
+ if (!table->insertIntoTree(record, NULL, record->recordNumber))
{
record->release();
int32 recordNumber = record->recordNumber;
=== removed file 'storage/falcon/Blob.cpp'
--- a/storage/falcon/Blob.cpp 2007-09-20 15:44:25 +0000
+++ b/storage/falcon/Blob.cpp 1970-01-01 00:00:00 +0000
@@ -1,34 +0,0 @@
-/* Copyright (C) 2006 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-
-// Blob.cpp: implementation of the Blob class.
-//
-//////////////////////////////////////////////////////////////////////
-
-#include <stdio.h>
-#include <string.h>
-#include "Engine.h"
-#include "Blob.h"
-
-#ifdef _DEBUG
-#undef THIS_FILE
-static const char THIS_FILE[]=__FILE__;
-#endif
-
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
=== modified file 'storage/falcon/CMakeLists.txt'
--- a/storage/falcon/CMakeLists.txt 2008-10-31 18:02:34 +0000
+++ b/storage/falcon/CMakeLists.txt 2009-01-28 06:52:48 +0000
@@ -39,7 +39,6 @@ SET(FALCON_SOURCES
BigInteger.cpp
BinaryBlob.cpp
Bitmap.cpp
- Blob.cpp
BlobReference.cpp
Btn.cpp
Cache.cpp
@@ -151,7 +150,6 @@ SET(FALCON_SOURCES
NStat.cpp
NUpdate.cpp
OpSys.cpp
- Page.cpp
PageInventoryPage.cpp
PagePrecedence.cpp
PageWriter.cpp
@@ -242,6 +240,7 @@ SET(FALCON_SOURCES
SRLIndexDelete.cpp
SRLIndexPage.cpp
SRLIndexUpdate.cpp
+ SRLInventoryPage.cpp
SRLInversionPage.cpp
SRLOverflowPages.cpp
SRLPrepare.cpp
@@ -276,7 +275,6 @@ SET(FALCON_SOURCES
SyncHandler.cpp
SyncObject.cpp
SyncTest.cpp
- SyncWait.cpp
Syntax.cpp
TableAttachment.cpp
Table.cpp
@@ -522,6 +520,7 @@ SET(FALCON_SOURCES
SRLIndexAdd.h
SRLIndexDelete.h
SRLIndexPage.h
+ SRLInventoryPage.h
SRLInversionPage.h
SRLIndexUpdate.h
SRLOverflowPages.h
=== modified file 'storage/falcon/Connection.cpp'
--- a/storage/falcon/Connection.cpp 2008-07-24 08:45:03 +0000
+++ b/storage/falcon/Connection.cpp 2009-01-27 17:26:16 +0000
@@ -376,7 +376,6 @@ void Connection::shutdownDatabases()
{
unlink(database);
database->shutdown();
- database->shutdown();
database->release();
}
}
=== modified file 'storage/falcon/DataPage.h'
--- a/storage/falcon/DataPage.h 2008-09-27 18:37:54 +0000
+++ b/storage/falcon/DataPage.h 2009-01-30 01:28:53 +0000
@@ -61,4 +61,7 @@ public:
LineIndex lineIndex [1];
};
+/* Maximal length of data that can be stored in a page */
+#define DATA_PAGE_MAX_AVAILABLE_SPACE(pageSize) (pageSize - sizeof(DataPage))
+
#endif // !defined(AFX_DATAPAGE_H__6A019C29_A340_11D2_AB5A_0000C01D2301__INCLUDED_)
=== modified file 'storage/falcon/Database.cpp'
--- a/storage/falcon/Database.cpp 2008-11-20 17:05:50 +0000
+++ b/storage/falcon/Database.cpp 2009-02-03 02:53:42 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -420,7 +420,10 @@ Database::Database(const char *dbName, C
recordMemoryMax = configuration->recordMemoryMax;
recordScavengeFloor = configuration->recordScavengeFloor;
recordScavengeThreshold = configuration->recordScavengeThreshold;
- lastRecordMemory = 0;
+ recordScavengeMaxGroupSize = recordMemoryMax / AGE_GROUPS_IN_CACHE;
+ recordPoolAllocCount = 0;
+ lastGenerationMemory = 0;
+ lastActiveMemoryChecked = 0;
utf8 = false;
stepNumber = 0;
shuttingDown = false;
@@ -452,7 +455,9 @@ Database::Database(const char *dbName, C
scheduler = NULL;
internalScheduler = NULL;
scavenger = NULL;
+#ifndef STORAGE_ENGINE
garbageCollector = NULL;
+#endif
sequenceManager = NULL;
repositoryManager = NULL;
sessionManager = NULL;
@@ -460,6 +465,14 @@ Database::Database(const char *dbName, C
tableSpaceManager = NULL;
timestamp = time (NULL);
tickerThread = NULL;
+ cardinalityThread = NULL;
+ cardinalityThreadSleeping = 0;
+ cardinalityThreadSignaled = 0;
+ scavengerThread = NULL;
+ scavengerThreadSleeping = 0;
+ scavengerThreadSignaled = 0;
+ scavengeForced = 0;
+ scavengeCount = 0;
serialLog = NULL;
pageWriter = NULL;
zombieTables = NULL;
@@ -480,8 +493,8 @@ Database::Database(const char *dbName, C
syncResultSets.setName("Database::syncResultSets");
syncConnectionStatements.setName("Database::syncConnectionStatements");
syncScavenge.setName("Database::syncScavenge");
- IO::deleteFile(BACKLOG_FILE);
syncSysDDL.setName("Database::syncSysDDL");
+ IO::deleteFile(BACKLOG_FILE);
}
@@ -513,7 +526,9 @@ void Database::start()
scheduler = new Scheduler(this);
internalScheduler = new Scheduler(this);
scavenger = new Scavenger(this, scvRecords, configuration->scavengeSchedule);
+#ifndef STORAGE_ENGINE
garbageCollector = new Scavenger(this, scvJava, configuration->gcSchedule);
+#endif
sequenceManager = new SequenceManager(this);
repositoryManager = new RepositoryManager(this);
transactionManager = new TransactionManager(this);
@@ -521,8 +536,12 @@ void Database::start()
filterSetManager = new FilterSetManager(this);
timestamp = time(NULL);
tickerThread = threads->start("Database::Database", &Database::ticker, this);
+ cardinalityThread = threads->start("Database::cardinalityThreadMain", &Database::cardinalityThreadMain, this);
+ scavengerThread = threads->start("Database::scavengerThreadMain", &Database::scavengerThreadMain, this);
internalScheduler->addEvent(scavenger);
+#ifndef STORAGE_ENGINE
internalScheduler->addEvent(garbageCollector);
+#endif
internalScheduler->addEvent(serialLog);
pageWriter->start();
cache->setPageWriter(pageWriter);
@@ -574,9 +593,10 @@ Database::~Database()
if (scavenger)
scavenger->release();
+#ifndef STORAGE_ENGINE
if (garbageCollector)
garbageCollector->release();
-
+#endif
if (threads)
{
threads->shutdownAll();
@@ -758,7 +778,9 @@ void Database::openDatabase(const char *
table->setDataSection (sectionId++);
table->setBlobSection (sectionId++);
- FOR_INDEXES (index, table)
+ // Iterate all indexes, set indexIDs
+
+ FOR_ALL_INDEXES (index, table)
index->setIndex (indexId++);
END_FOR;
}
@@ -1472,8 +1494,7 @@ void Database::truncateTable(Table *tabl
syncDDLLock.lock(Exclusive);
// Lock syncScavenge before locking syncTables, or table->syncObject.
- // The scavenger locks syncScavenge and then syncTables
- // If we run out of record memory, forceRecordScavenge will eventually call table->syncObject.
+ // The scavenger locks syncScavenge, then syncTables, then table->syncObject
Sync syncScavengeLock(&syncScavenge, "Database::truncateTable(scavenge)");
syncScavengeLock.lock(Exclusive);
@@ -1711,9 +1732,17 @@ void Database::validate(int optionMask)
Log::debug ("Database::validate: validation complete\n");
}
-void Database::scavenge()
+void Database::scavenge(bool forced)
{
- updateCardinalities();
+ // Signal the cardinality task unless a forced scavenge is pending
+
+ if (!forced &&
+ ++scavengeCount % CARDINALITY_FREQUENCY == 0)
+ {
+ signalCardinality();
+ }
+
+ scavengeForced = 0;
// Start by scavenging compiled statements. If they're moldy and not in use,
// off with their heads!
@@ -1735,9 +1764,16 @@ void Database::scavenge()
syncStmt.unlock();
- // Next, scavenge tables
+ // purgeTransactions will release records that are attached to old
+ // transactions, thus freeing up old invisible records to be pruned
+ // and actually released. It is not likely that the scavenger will
+ // retire these freshly released base records, but disconnecting
+ // pruneable records from their transactions is definitely needed.
+
+ transactionManager->purgeTransactions();
- retireRecords(false); // age group based scavenger
+ // Scavenge the record cache
+ scavengeRecords(forced);
// Scavenge expired licenses
@@ -1765,109 +1801,110 @@ void Database::scavenge()
backLog->reportStatistics();
}
-
-void Database::retireRecords(bool forced)
+void Database::scavengeRecords(bool forced)
{
- int cycle = scavengeCycle;
-
- Sync syncScavenger(&syncScavenge, "Database::retireRecords(1)");
+ Sync syncScavenger(&syncScavenge, "Database::scavengeRecords(Scavenge)");
syncScavenger.lock(Exclusive);
- if (forced && scavengeCycle > cycle)
- return;
-
- // Commit pending system transactions before proceeding
-
- if (!forced && systemConnection->transaction)
- commitSystemTransaction();
+ // Create an object to track this record scavenge cycle. Scavenge up to and
+ // including the current generation.
- if (forced)
- Log::log("Forced record scavenge cycle\n");
-
- transactionManager->purgeTransactions();
- TransId oldestActiveTransaction = transactionManager->findOldestActive();
- uint64 total = recordDataPool->activeMemory;
- RecordScavenge recordScavenge(this, oldestActiveTransaction, forced);
+ RecordScavenge recordScavenge(this, currentGeneration, forced);
- // If we passed the upper limit, scavenge. If we didn't pick up
- // a significant amount of memory since the last cycle, don't bother
- // bumping the age group.
+ // Take inventory of the record cache and prune invisible record versions
+
+ pruneRecords(&recordScavenge);
+ recordScavenge.prunedActiveMemory = recordDataPool->activeMemory;
+ recordScavenge.pruneStop = deltaTime;
+ syncScavenger.unlock(); // take a breath!
+
+ // Retire visible records with no dependencies in the oldest age groups
+
+ syncScavenger.lock(Exclusive);
+ retireRecords(&recordScavenge);
+ recordScavenge.retiredActiveMemory = recordDataPool->activeMemory;
+ recordScavenge.retireStop = deltaTime;
+
+ // Enable backlogging if memory is low
+
+ if (recordScavenge.retiredActiveMemory > recordScavengeFloor)
+ setLowMemory();
+ else
+ clearLowMemory();
+
+ recordScavenge.print();
+ // Log::log(analyze(analyzeRecordLeafs));
- if (forced || total > recordScavengeThreshold)
+ // syncmemory is used to protect lastActiveMemoryChecked
+ // and lastGenerationMemory. In addition, it is used to
+ // serialize signaling of the scavenger thread by allowing
+ // only one thread at a time to check and change
+ // scavengerThreadSignaled. It is a Mutex instead of a
+ // SyncObject because it is only locked exclusively, no
+ // shared locks. It does not need any of the other
+ // features of SyncObject. And a Mutex is faster.
+
+ Sync syncMem(&syncMemory, "Database::checkRecordScavenge");
+ syncMem.lock(Exclusive);
+
+ lastActiveMemoryChecked = lastGenerationMemory = recordDataPool->activeMemory;
+}
+
+// Take inventory of the record cache and prune invisible record versions
+
+void Database::pruneRecords(RecordScavenge *recordScavenge)
+{
+ //Log::log(analyze(analyzeRecordLeafs));
+ //LogStream stream;
+ //recordDataPool->analyze(0, &stream, NULL, NULL);
+
+ Sync syncTbl(&syncTables, "Database::pruneRecords(tables)");
+ syncTbl.lock(Shared);
+
+ for (Table *table = tableList; table; table = table->next)
{
- //LogStream stream;
- //recordDataPool->analyze(0, &stream, NULL, NULL);
-
- Sync syncTbl(&syncTables, "Database::retireRecords(2)");
- syncTbl.lock(Shared);
-
- Table *table;
- time_t scavengeStart = deltaTime;
-
- if (!forced)
- for (table = tableList; table; table = table->next)
- table->inventoryRecords(&recordScavenge);
-
- recordScavenge.computeThreshold(recordScavengeFloor);
- recordScavenge.printRecordMemory();
- int count = 0;
- int skipped = 0;
-
- for (table = tableList; table; table = table->next)
+ try
{
- try
- {
- int n = table->retireRecords(&recordScavenge);
-
- if (n >= 0)
- count += n;
- else
- ++skipped;
- }
- catch (SQLException &exception)
- {
- //syncTbl.unlock();
- Log::debug ("Exception during scavenge of table %s.%s: %s\n",
- table->schemaName, table->name, exception.getText());
- }
+ table->pruneRecords(recordScavenge);
+ }
+ catch (SQLException &exception)
+ {
+ Log::debug ("Exception during pruning of table %s.%s: %s\n",
+ table->schemaName, table->name, exception.getText());
}
-
- syncTbl.unlock();
-
-
- // Check for low memory
-
- if (recordScavenge.spaceRemaining > recordScavengeFloor)
- setLowMemory();
- /***
- else
- lowMemory = false;
- ***/
-
- Log::log(LogScavenge, "%d: Scavenged %d records, " I64FORMAT " bytes in %d seconds\n",
- deltaTime, recordScavenge.recordsReclaimed, recordScavenge.spaceReclaimed, deltaTime - scavengeStart);
-
- total = recordScavenge.spaceRemaining;
}
- else if ((total - lastRecordMemory) < recordScavengeThreshold / AGE_GROUPS)
- {
- recordScavenge.scavengeGeneration = UNDEFINED;
- cleanupRecords (&recordScavenge);
+}
- ++scavengeCycle;
-
+void Database::retireRecords(RecordScavenge *recordScavenge)
+{
+ // Scavenge if we passed the upper limit or if a forced scavenge
+ // was requested.
+
+ if (recordDataPool->activeMemory < recordScavengeThreshold
+ && !recordScavenge->forced)
return;
- }
- else
+
+ //LogStream stream;
+ //recordDataPool->analyze(0, &stream, NULL, NULL);
+
+ Sync syncTbl(&syncTables, "Database::retireRecords(2)");
+ syncTbl.lock(Shared);
+
+ uint64 spaceToRetire = recordDataPool->activeMemory - recordScavengeFloor;
+ recordScavenge->computeThreshold(spaceToRetire);
+
+ for (Table *table = tableList; table; table = table->next)
{
- recordScavenge.scavengeGeneration = UNDEFINED;
- cleanupRecords (&recordScavenge);
+ try
+ {
+ table->retireRecords(recordScavenge);
+ }
+ catch (SQLException &exception)
+ {
+ Log::debug ("Exception during scavenge of table %s.%s: %s\n",
+ table->schemaName, table->name, exception.getText());
+ }
}
-
- ++scavengeCycle;
-
- lastRecordMemory = recordDataPool->activeMemory;
- INTERLOCKED_INCREMENT (currentGeneration);
}
void Database::ticker(void * database)
@@ -1892,6 +1929,37 @@ void Database::ticker()
}
}
+void Database::scavengerThreadMain(void * database)
+{
+ ((Database*) database)->scavengerThreadMain();
+}
+
+void Database::scavengerThreadMain(void)
+{
+ Thread *thread = Thread::getThread("Database::scavengerThreadMain");
+
+ thread->sleep(1000);
+
+ while (!thread->shutdownInProgress)
+ {
+ scavenge((scavengeForced > 0));
+
+ if (recordDataPool->activeMemory < recordScavengeThreshold)
+ {
+ INTERLOCKED_INCREMENT(scavengerThreadSleeping);
+ thread->sleep();
+ scavengerThreadSignaled = 0;
+ INTERLOCKED_DECREMENT(scavengerThreadSleeping);
+ }
+ }
+}
+
+void Database::scavengerThreadWakeup(void)
+{
+ if (scavengerThread)
+ scavengerThread->wake();
+}
+
int Database::createSequence(int64 initialValue)
{
Transaction *transaction = getSystemTransaction();
@@ -2169,25 +2237,6 @@ int Database::getMemorySize(const char *
}
-void Database::cleanupRecords(RecordScavenge *recordScavenge)
-{
- Sync sync (&syncTables, "Database::cleanupRecords");
- sync.lock (Shared);
-
- for (Table *table = tableList; table; table = table->next)
- {
- try
- {
- table->cleanupRecords(recordScavenge);
- }
- catch (SQLException &exception)
- {
- Log::debug ("Exception during cleanupRecords of table %s.%s: %s\n",
- table->schemaName, table->name, exception.getText());
- }
- }
-}
-
void Database::licenseCheck()
{
#ifdef LICENSE
@@ -2251,16 +2300,6 @@ void Database::deleteRepositoryBlob(cons
repository->deleteBlob (volume, blobId, transaction);
}
-void Database::commit(Transaction *transaction)
-{
- dbb->commit(transaction);
-}
-
-void Database::rollback(Transaction *transaction)
-{
- dbb->rollback(transaction->transactionId, transaction->hasUpdates);
-}
-
void Database::renameTable(Table* table, const char* newSchema, const char* newName)
{
newSchema = getSymbol(newSchema);
@@ -2392,6 +2431,45 @@ void Database::getTableSpaceFilesInfo(In
tableSpaceManager->getTableSpaceFilesInfo(infoTable);
}
+void Database::cardinalityThreadMain(void * database)
+{
+ ((Database*) database)->cardinalityThreadMain();
+}
+
+void Database::cardinalityThreadMain(void)
+{
+ Thread *thread = Thread::getThread("Database::cardinalityThreadMain");
+
+ thread->sleep(1000);
+
+ while (!thread->shutdownInProgress)
+ {
+ updateCardinalities();
+ INTERLOCKED_INCREMENT(cardinalityThreadSleeping);
+ thread->sleep();
+ cardinalityThreadSignaled = 0;
+ INTERLOCKED_DECREMENT(cardinalityThreadSleeping);
+ }
+}
+
+void Database::signalCardinality(void)
+{
+ Sync syncCard(&syncCardinality, "Database::signalCardinality");
+ syncCard.lock(Exclusive);
+
+ if (cardinalityThreadSleeping && !cardinalityThreadSignaled)
+ {
+ INTERLOCKED_INCREMENT(cardinalityThreadSignaled);
+ cardinalityThreadWakeup();
+ }
+}
+
+void Database::cardinalityThreadWakeup(void)
+{
+ if (cardinalityThread)
+ cardinalityThread->wake();
+}
+
void Database::updateCardinalities(void)
{
Sync syncDDL(&syncSysDDL, "Database::updateCardinalities(1)");
@@ -2400,11 +2478,16 @@ void Database::updateCardinalities(void)
Sync syncTbl(&syncTables, "Database::updateCardinalities(2)");
syncTbl.lock(Shared);
+ Log::log("Update cardinalities\n");
bool hit = false;
try
{
- for (Table *table = tableList; table; table = table->next)
+
+ // Establish the record cardinality for each table. Abandon the effort
+ // if a forced scavenge operation is pending.
+
+ for (Table *table = tableList; (table && scavengeForced == 0); table = table->next)
{
uint64 cardinality = table->cardinality;
@@ -2506,9 +2589,62 @@ void Database::setRecordScavengeFloor(in
}
}
-void Database::forceRecordScavenge(void)
+void Database::checkRecordScavenge(void)
+{
+ // Signal a load-based scavenge if we are over the threshold
+
+ if (scavengerThreadSleeping && !scavengerThreadSignaled)
+ {
+ Sync syncMem(&syncMemory, "Database::checkRecordScavenge");
+ syncMem.lock(Exclusive);
+
+ if ( !scavengerThreadSignaled
+ && (recordDataPool->activeMemory > lastActiveMemoryChecked))
+ {
+ // Start a new age generation regularly. Note that since activeMemory
+ // can go down due to a recent scavenge, it is possible for
+ // lastGenerationMemory to be > recordDataPool->activeMemory
+
+ if ( (int64) (recordDataPool->activeMemory - lastGenerationMemory)
+ > (int64) recordScavengeMaxGroupSize)
+ {
+ // Let the scavenger run to prune records.
+ // It will also retire records if recordScavengeThreshold has been reached.
+
+ INTERLOCKED_INCREMENT (currentGeneration);
+ lastGenerationMemory = recordDataPool->activeMemory;
+
+ INTERLOCKED_INCREMENT(scavengerThreadSignaled);
+ scavengerThreadWakeup();
+ }
+
+ else if (recordDataPool->activeMemory >= recordScavengeThreshold)
+ {
+ INTERLOCKED_INCREMENT(scavengerThreadSignaled);
+ scavengerThreadWakeup();
+ }
+
+ lastActiveMemoryChecked = recordDataPool->activeMemory;
+ }
+ }
+}
+
+// Signal the scavenger thread
+
+void Database::signalScavenger(bool force)
{
- retireRecords(true);
+ Sync syncMem(&syncMemory, "Database::signalScavenger");
+ syncMem.lock(Exclusive);
+
+ if (scavengerThreadSleeping && !scavengerThreadSignaled)
+ {
+ INTERLOCKED_INCREMENT(scavengerThreadSignaled);
+
+ if (force)
+ INTERLOCKED_INCREMENT(scavengeForced);
+
+ scavengerThreadWakeup();
+ }
}
void Database::debugTrace(void)
@@ -2622,3 +2758,8 @@ void Database::setLowMemory(void)
lowMemory = true;
}
+
+void Database::clearLowMemory(void)
+{
+ lowMemory = false;
+}
=== modified file 'storage/falcon/Database.h'
--- a/storage/falcon/Database.h 2008-10-16 01:04:03 +0000
+++ b/storage/falcon/Database.h 2009-02-05 05:34:42 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -40,6 +40,11 @@
#define VERSION_CURRENT COMBINED_VERSION(ODS_VERSION, ODS_MINOR_VERSION)
#define VERSION_SERIAL_LOG COMBINED_VERSION(ODS_VERSION2, ODS_MINOR_VERSION1)
+// Reserved tablespaces
+
+static const int TABLESPACE_ID_BACKLOG = -1;
+static const int TABLESPACE_ID_RESERVED = -2;
+
static const int FALC0N_TRACE_TRANSACTIONS = 1;
static const int FALC0N_SYNC_TEST = 2;
static const int FALC0N_SYNC_OBJECTS = 4;
@@ -48,6 +53,21 @@ static const int FALC0N_REPORT_WRITES =
static const int FALC0N_SYNC_HANDLER = 32;
static const int FALC0N_TEST_BITMAP = 64;
+// This constant defines how many times a thread will sleep(10) while
+// waiting for record cache memory to be freed up by the scavenger thread
+// before it gives up and returns OUT_OF_RECORD_MEMORY_ERROR.
+
+static const int OUT_OF_RECORD_MEMORY_RETRIES = 10;
+
+// Milliseconds per iteration to wait for the Scavenger
+
+static const int SCAVENGE_WAIT_MS = 20;
+
+// Scavenger cycles per call to updateCardinalities()
+
+static const int CARDINALITY_FREQUENCY = 20;
+
+
#define TABLE_HASH_SIZE 101
class Table;
@@ -116,8 +136,6 @@ public:
void shutdownNow();
void dropDatabase();
- void rollback (Transaction *transaction);
- void commit (Transaction *transaction);
void start();
void deleteRepositoryBlob(const char *schema, const char *repositoryName, int volume, int64 blobId, Transaction *transaction);
void deleteRepository (Repository *repository);
@@ -127,9 +145,10 @@ public:
Repository* findRepository(const char *schema, const char *name);
const char* fetchTemplate (JString applicationName, JString templateName, TemplateContext *context);
void licenseCheck();
- void cleanupRecords (RecordScavenge *recordScavenge);
void serverOperation (int op, Parameters *parameters);
- void retireRecords(bool forced);
+ void scavengeRecords(bool forced = false);
+ void pruneRecords(RecordScavenge* recordScavenge);
+ void retireRecords(RecordScavenge* recordScavenge);
int getMemorySize (const char *string);
JString analyze(int mask);
void upgradeSystemTables();
@@ -148,7 +167,13 @@ public:
int createSequence(int64 initialValue);
void ticker();
static void ticker (void *database);
- void scavenge();
+ static void cardinalityThreadMain(void * database);
+ void cardinalityThreadMain(void);
+ void cardinalityThreadWakeup(void);
+ static void scavengerThreadMain(void * database);
+ void scavengerThreadMain(void);
+ void scavengerThreadWakeup(void);
+ void scavenge(bool forced = false);
void validate (int optionMask);
Role* findRole(const char *schemaName, const char * roleName);
User* findUser (const char *account);
@@ -220,7 +245,9 @@ public:
void setRecordMemoryMax(uint64 value);
void setRecordScavengeThreshold(int value);
void setRecordScavengeFloor(int value);
- void forceRecordScavenge(void);
+ void checkRecordScavenge(void);
+ void signalCardinality(void);
+ void signalScavenger(bool force = false);
void debugTrace(void);
void pageCacheFlushed(int64 flushArg);
JString setLogRoot(const char *defaultPath, bool create);
@@ -228,6 +255,7 @@ public:
void clearIOError(void);
void flushWait(void);
void setLowMemory(void);
+ void clearLowMemory(void);
Dbb *dbb;
@@ -270,12 +298,16 @@ public:
SyncObject syncConnectionStatements;
SyncObject syncScavenge;
SyncObject syncSysDDL;
+ Mutex syncCardinality;
+ Mutex syncMemory;
PriorityScheduler *ioScheduler;
Threads *threads;
Scheduler *scheduler;
Scheduler *internalScheduler;
Scavenger *scavenger;
+#ifndef STORAGE_ENGINE
Scavenger *garbageCollector;
+#endif
TemplateManager *templateManager;
ImageManager *imageManager;
SessionManager *sessionManager;
@@ -290,6 +322,13 @@ public:
SyncHandler *syncHandler;
SearchWords *searchWords;
Thread *tickerThread;
+ Thread *cardinalityThread;
+ Thread *scavengerThread;
+ volatile INTERLOCK_TYPE cardinalityThreadSleeping;
+ volatile INTERLOCK_TYPE cardinalityThreadSignaled;
+ volatile INTERLOCK_TYPE scavengerThreadSleeping;
+ volatile INTERLOCK_TYPE scavengerThreadSignaled;
+ volatile INTERLOCK_TYPE scavengeForced;
PageWriter *pageWriter;
PreparedStatement *updateCardinality;
MemMgr *recordDataPool;
@@ -310,8 +349,12 @@ public:
volatile INTERLOCK_TYPE currentGeneration;
uint64 recordMemoryMax;
uint64 recordScavengeThreshold;
+ uint64 recordScavengeMaxGroupSize;
uint64 recordScavengeFloor;
- int64 lastRecordMemory;
+ uint64 recordPoolAllocCount;
+ uint64 lastGenerationMemory;
+ uint64 lastActiveMemoryChecked;
+ uint64 scavengeCount;
time_t creationTime;
volatile time_t lastScavenge;
};
=== modified file 'storage/falcon/DateTime.cpp'
--- a/storage/falcon/DateTime.cpp 2008-10-31 15:42:42 +0000
+++ b/storage/falcon/DateTime.cpp 2008-12-20 05:33:13 +0000
@@ -110,37 +110,37 @@ static TimeZoneRule noDST[] = { 0,
static TimeZoneRule USDST[] = { 2007, 2,8,-1,7200000, 10,1,-1,7200000,
0, 3,1,-1,7200000, 9,-1,1,7200000 };
-static TimeZoneRule ParisDST[] = { 0, 2,-1,1,7200000, 9,-1,1,7200000 };
-static TimeZoneRule LondonDST[] = { 0, 2,-1,1,3600000, 9,-1,1,3600000 };
-static TimeZoneRule WarsawDST[] = { 0, 2,-1,1,3600000, 9,-1,1,7200000 };
+static TimeZoneRule ParisDST[] = { 0, 2,-1,1,7200, 9,-1,1,7200 };
+static TimeZoneRule LondonDST[] = { 0, 2,-1,1,3600, 9,-1,1,3600 };
+static TimeZoneRule WarsawDST[] = { 0, 2,-1,1,3600, 9,-1,1,7200 };
static TimeZoneRule BrazilDST[] = { 0, 9,1,-1,0, 1,11,-1,0 };
static TimeZoneRule AzoresDST[] = { 0, 2,-1,1,0, 9,-1,1,0 };
-static TimeZoneRule InstanbulDST[] = { 0, 2,-1,1,10800000, 9,-1,1,10800000 };
-static TimeZoneRule AustralianDST[] = { 0, 9,-1,1,7200000, 2,-1,1,10800000 };
+static TimeZoneRule InstanbulDST[] = { 0, 2,-1,1,10800, 9,-1,1,10800 };
+static TimeZoneRule AustralianDST[] = { 0, 9,-1,1,7200, 2,-1,1,10800 };
static TimeZoneRule CairoDST[] = { 0, 3,-1,6,0, 8,-1,6,0 };
-static TimeZoneRule AucklandDST[] = { 0, 9,1,-1,7200000, 2,15,-1,10800000 };
-static TimeZoneRule RussianDST[] = { 0, 2,-1,1,7200000, 9,-1,1,10800000 };
+static TimeZoneRule AucklandDST[] = { 0, 9,1,-1,7200, 2,15,-1,10800 };
+static TimeZoneRule RussianDST[] = { 0, 2,-1,1,7200, 9,-1,1,10800 };
static TimeZoneRule RarotongaDST[] = { 0, 9,-1,1,0, 2,1,-1,0 };
static TimeZoneRule TehranDST[] = { 0, 2,4,0,0, 8,4,0,0 };
static TimeZoneRule ChileDST[] = { 0, 9,9,-1,0, 2,9,-1,0 };
-static TimeZoneRule CubaDST[] = { 0, 3,1,-1,0, 9,8,-1,3600000 };
-static TimeZoneRule HaitiDST[] = { 0, 3,1,-1,3600000, 9,-1,1,7200000 };
+static TimeZoneRule CubaDST[] = { 0, 3,1,-1,0, 9,8,-1,3600 };
+static TimeZoneRule HaitiDST[] = { 0, 3,1,-1,3600, 9,-1,1,7200 };
static TimeZoneRule GrandTurkDST[] = { 0, 3,1,-1,0, 9,-1,1,0 };
-static TimeZoneRule GodthabDST[] = { 0, 2,-1,1,-7200000, 9,-1,1,-7200000 };
-static TimeZoneRule TripoliDST[] = { 0, 2,-1,5,7200000, 9,1,-5,10800000 };
-static TimeZoneRule AmmanDST[] = { 0, 3,1,-6,0, 8,15,-6,3600000 };
-static TimeZoneRule RigaDST[] = { 0, 2,-1,1,7200000, 8,-1,1,10800000 };
+static TimeZoneRule GodthabDST[] = { 0, 2,-1,1,-7200, 9,-1,1,-7200 };
+static TimeZoneRule TripoliDST[] = { 0, 2,-1,5,7200, 9,1,-5,10800 };
+static TimeZoneRule AmmanDST[] = { 0, 3,1,-6,0, 8,15,-6,3600 };
+static TimeZoneRule RigaDST[] = { 0, 2,-1,1,7200, 8,-1,1,10800 };
static TimeZoneRule BeruitDST[] = { 0, 2,-1,1,0, 8,-1,1,0 };
-static TimeZoneRule WindhoekDST[] = { 0, 8,1,-1,7200000, 3,1,-1,7200000 };
+static TimeZoneRule WindhoekDST[] = { 0, 8,1,-1,7200, 3,1,-1,7200 };
static TimeZoneRule DamascusDST[] = { 0, 3,1,0,0, 9,1,0,0 };
static TimeZoneRule JerusalamDST[] = { 0, 2,15,-6,0, 8,15,-1,0 };
-static TimeZoneRule BagdadDST[] = { 0, 3,1,0,10800000, 9,1,0,14400000 };
-static TimeZoneRule BakuDST[] = { 0, 2,-1,1,18000000, 9,-1,1,18000000 };
+static TimeZoneRule BagdadDST[] = { 0, 3,1,0,10800, 9,1,0,14400 };
+static TimeZoneRule BakuDST[] = { 0, 2,-1,1,18000, 9,-1,1,18000 };
static TimeZoneRule BishkekDST[] = { 0, 3,7,-1,0, 8,-1,1,0 };
-static TimeZoneRule HobartDST[] = { 0, 9,1,-1,7200000, 2,-1,1,10800000 };
-static TimeZoneRule NoumeaDST[] = { 0, 10,-1,1,7200000, 2,1,-1,10800000 };
-static TimeZoneRule ChathamDST[] = { 0, 9,1,-1,9900000, 2,15,-1,13500000 };
+static TimeZoneRule HobartDST[] = { 0, 9,1,-1,7200, 2,-1,1,10800 };
+static TimeZoneRule NoumeaDST[] = { 0, 10,-1,1,7200, 2,1,-1,10800 };
+static TimeZoneRule ChathamDST[] = { 0, 9,1,-1,9900, 2,15,-1,13500 };
static TimeZoneRule StandleyDST[] = { 0, 8,8,-1,0, 3,16,-1,0 };
static TimeZoneRule AsuncionDST[] = { 0, 9,1,0,0, 2,1,0,0 };
//static TimeZoneRule DST = { };
@@ -1258,8 +1258,6 @@ int DateTime::timeRule(tm *time, int64 f
changeDay += 7;
}
- ++changeDay;
-
if (time->tm_mday < changeDay)
return -1;
=== modified file 'storage/falcon/Dbb.cpp'
--- a/storage/falcon/Dbb.cpp 2008-10-30 00:22:54 +0000
+++ b/storage/falcon/Dbb.cpp 2009-02-09 05:01:44 +0000
@@ -56,8 +56,6 @@
//#define STOP_RECORD 123
//#define TRACE_PAGE 109
-static const int SECTION_HASH_SIZE = 997;
-
extern uint falcon_large_blob_threshold;
#ifdef _DEBUG
@@ -74,7 +72,6 @@ Dbb::Dbb(Database *dbase)
{
database = dbase;
cache = NULL;
- sections = NULL;
sequenceSection = NULL;
nextIndex = 0;
nextSection = 0;
@@ -91,6 +88,7 @@ Dbb::Dbb(Database *dbase)
noLog = false;
syncClone.setName("Dbb::syncClone");
syncSequences.setName("Dbb::syncSequences");
+ memset (sections, 0, sizeof (sections));
}
@@ -101,7 +99,6 @@ Dbb::Dbb(Dbb *dbb, int tblSpaceId)
cache = dbb->cache;
pageSize = dbb->pageSize;
serialLog = dbb->serialLog;
- sections = NULL;
sequenceSection = NULL;
nextIndex = 0;
nextSection = 0;
@@ -113,6 +110,7 @@ Dbb::Dbb(Dbb *dbb, int tblSpaceId)
highPage = 0;
defaultIndexVersion = dbb->defaultIndexVersion;
noLog = false;
+ memset (sections, 0, sizeof (sections));
}
Dbb::~Dbb()
@@ -131,16 +129,12 @@ Dbb::~Dbb()
Section *section;
- if (sections)
- for (int n = 0; n < SECTION_HASH_SIZE; ++n)
- while ((section = sections [n]))
- {
- sections [n] = section->hash;
- delete section;
- }
-
- if (sections)
- delete [] sections;
+ for (int n = 0; n < SECTION_HASH_SIZE; ++n)
+ while ((section = sections [n]))
+ {
+ sections [n] = section->hash;
+ delete section;
+ }
if (inversion)
delete inversion;
@@ -149,7 +143,7 @@ Dbb::~Dbb()
dbb->close();
}
-Cache* Dbb::create(const char * fileName, int pageSz, int64 cacheSize, FileType fileType, TransId transId, const char *logRoot)
+Cache* Dbb::create(const char * fileName, int pageSz, int64 cacheSize, FileType fileType, TransId transId, const char *logRoot, bool useExistingFile)
{
serialLog = database->serialLog;
odsVersion = ODS_VERSION;
@@ -157,7 +151,11 @@ Cache* Dbb::create(const char * fileName
sequence = 1;
init(pageSz, (int) ((cacheSize + pageSz - 1) / pageSz));
- createFile(fileName);
+ if(useExistingFile)
+ openFile(fileName, false);
+ else
+ createFile(fileName);
+
try
{
Hdr::create(this, fileType, transId, logRoot);
@@ -168,7 +166,8 @@ Cache* Dbb::create(const char * fileName
catch(...)
{
closeFile();
- deleteFile();
+ if(!useExistingFile)
+ deleteFile();
throw;
}
@@ -194,8 +193,7 @@ void Dbb::init()
linesPerPage = (short) ((pageSize - OFFSET (RecordLocatorPage*, elements)) / sizeof (struct RecordIndex));
sequencesPerPage = (short) ((pageSize - OFFSET (SequencePage*, sequences)) / sizeof (int64));
sequencesPerSection = (int) (pagesPerSection * sequencesPerPage);
- sections = new Section* [SECTION_HASH_SIZE];
- memset (sections, 0, sizeof (Section*) * SECTION_HASH_SIZE);
+
utf8 = false;
}
@@ -1169,34 +1167,6 @@ void Dbb::reportStatistics()
priorFlushWrites = flushWrites;
}
-void Dbb::commit(Transaction *transaction)
-{
- if (transaction->hasUpdates)
- serialLog->logControl->commit.append(transaction);
-}
-
-void Dbb::prepareTransaction(TransId transId, int xidLength, const UCHAR *xid)
-{
- serialLog->logControl->prepare.append(transId, xidLength, xid);
-}
-
-void Dbb::rollback(TransId transId, bool updateTransaction)
-{
- if (updateTransaction)
- {
- if (serialLog)
- serialLog->logControl->rollback.append(transId, updateTransaction);
- //flush();
- }
-}
-
-/***
-void Dbb::setRecovering(bool flag)
-{
- recovering = flag;
-}
-***/
-
void Dbb::enableSerialLog()
{
Bdb *bdb = fetchPage(HEADER_PAGE, PAGE_header, Exclusive);
=== modified file 'storage/falcon/Dbb.h'
--- a/storage/falcon/Dbb.h 2008-10-30 00:22:54 +0000
+++ b/storage/falcon/Dbb.h 2009-02-02 13:00:38 +0000
@@ -36,6 +36,7 @@
#define PAGE_SIZE 4096
#define CACHE_SIZE 1024
+#define SECTION_HASH_SIZE 997
// Selective debugging
@@ -113,10 +114,7 @@ public:
void createSection(int32 sectionId, TransId transId);
void dropDatabase();
void enableSerialLog();
- void rollback (TransId transId, bool updateTransaction);
void updateRecord(int32 sectionId, int32 recordId, Stream *stream, TransId transId, bool earlyWrite);
- void prepareTransaction(TransId transId, int xidLength, const UCHAR *xid);
- void commit(Transaction *transaction);
void reportStatistics();
bool hasDirtyPages();
bool deleteShadow (DatabaseCopy *shadow);
@@ -168,7 +166,9 @@ public:
Bdb* fakePage (int32 pageNumber, PageType pageType, TransId transId);
Bdb* trialFetch(int32 pageNumber, PageType pageType, LockType lockType);
void init(int pageSz, int cacheSize);
- Cache* create (const char *fileName, int pageSize, int64 cacheSize, FileType fileType, TransId transId, const char *logRoot);
+ Cache* create (const char *fileName, int pageSize, int64 cacheSize, FileType fileType, TransId transId, const char *logRoot,
+ bool useExistingFile = false);
+
void validateCache(void);
void logUpdatedRecords(Transaction* transaction, RecordVersion* records, bool chill = false);
void logIndexUpdates(DeferredIndex* deferredIndex);
@@ -202,7 +202,7 @@ public:
int sequencesPerSection;
bool utf8;
bool noLog;
- Section **sections;
+ Section *sections[SECTION_HASH_SIZE];
int debug;
int sequence;
int odsVersion;
=== modified file 'storage/falcon/DeferredIndex.cpp'
--- a/storage/falcon/DeferredIndex.cpp 2008-11-14 15:38:44 +0000
+++ b/storage/falcon/DeferredIndex.cpp 2009-01-26 17:29:41 +0000
@@ -843,7 +843,7 @@ void DeferredIndex::detachTransaction(vo
//releaseRef();
}
-void DeferredIndex::chill(Dbb *dbb)
+bool DeferredIndex::chill(Dbb *dbb)
{
Sync sync(&syncObject, "DeferredIndex::chill");
sync.lock(Exclusive);
@@ -852,23 +852,34 @@ void DeferredIndex::chill(Dbb *dbb)
window = dbb->serialLog->setWindowInterest();
dbb->logIndexUpdates(this);
-
- // Free up the space used by this DeferredIndex
-
- freeHunks();
- initializeSpace();
- levels = 0;
- DILeaf *leaf = (DILeaf*) alloc(sizeof(DILeaf));
- leaf->count = 0;
- root = leaf;
- count = 0;
- minValue = NULL;
- maxValue = NULL;
- haveMinValue = true;
- haveMaxValue = true;
-
- Log::log(LogInfo, "%d: Index chill: transaction %ld, index %ld, %ld bytes, address %p, vofs %llx\n",
+
+ if (virtualOffset > 0)
+ {
+ // Virtual offset will be > 0 if chill was successful.
+ // Free up the space used by this DeferredIndex.
+
+ freeHunks();
+ initializeSpace();
+ levels = 0;
+ DILeaf *leaf = (DILeaf*) alloc(sizeof(DILeaf));
+ leaf->count = 0;
+ root = leaf;
+ count = 0;
+ minValue = NULL;
+ maxValue = NULL;
+ haveMinValue = true;
+ haveMaxValue = true;
+
+ Log::log(LogInfo, "%d: Index chill: transaction %ld, index %ld, %ld bytes, address %p, vofs %llx\n",
+ dbb->database->deltaTime, transaction->transactionId, index->indexId, sizeEstimate, this, virtualOffset);
+ }
+ else
+ {
+ Log::log(LogInfo, "%d: Index chill: transaction %ld, index %ld, %ld bytes, address %p, vofs %llx - NOT CHILLED\n",
dbb->database->deltaTime, transaction->transactionId, index->indexId, sizeEstimate, this, virtualOffset);
+ }
+
+ return virtualOffset > 0;
}
DINode* DeferredIndex::findMaxValue(void)
=== modified file 'storage/falcon/DeferredIndex.h'
--- a/storage/falcon/DeferredIndex.h 2008-10-16 02:53:35 +0000
+++ b/storage/falcon/DeferredIndex.h 2009-01-26 17:29:41 +0000
@@ -86,7 +86,7 @@ public:
void detachIndex(void);
void detachTransaction(void);
void scanIndex (IndexKey *lowKey, IndexKey *highKey, int searchFlags, Bitmap *bitmap);
- void chill(Dbb *dbb);
+ bool chill(Dbb *dbb);
int checkTail(uint position, DINode* node);
int checkTail(uint position, IndexKey *indexKey);
=== modified file 'storage/falcon/Engine.h'
--- a/storage/falcon/Engine.h 2008-06-19 15:09:45 +0000
+++ b/storage/falcon/Engine.h 2009-01-22 18:16:37 +0000
@@ -68,7 +68,8 @@ using namespace NAMESPACE;
#define ISUPPER(c) (c >= 'A' && c <= 'Z')
#define ISDIGIT(c) (c >= '0' && c <= '9')
#define UPPER(c) ((ISLOWER (c)) ? c - 'a' + 'A' : c)
-#define ROUNDUP(n,b) (((n) + b - 1) & ~(b - 1))
+#define ROUNDUP(n,b) ((((n) + (b) - 1) /(b) ) * (b))
+
#define ALIGN(ptr,b) ((UCHAR*) (((UIPTR) ptr + b - 1) / b * b))
#define SQLEXCEPTION SQLError
=== modified file 'storage/falcon/IO.cpp'
--- a/storage/falcon/IO.cpp 2008-11-20 17:05:50 +0000
+++ b/storage/falcon/IO.cpp 2009-01-27 20:44:30 +0000
@@ -281,15 +281,15 @@ bool IO::createFile(const char *name)
void IO::readPage(Bdb * bdb)
{
if (fatalError)
- FATAL ("can't continue after fatal error");
+ throw SQLError(IO_ERROR, "can't continue after fatal error");
SEEK_OFFSET offset = (int64) bdb->pageNumber * pageSize;
- int length = pread (offset, pageSize, (UCHAR *)bdb->buffer);
+ int length = pread(offset, pageSize, (UCHAR *)bdb->buffer);
if (length != pageSize)
{
declareFatalError();
- FATAL ("read error on page %d of \"%s\": %s (%d)",
+ throw SQLError(IO_ERROR, "read error on page %d of \"%s\": %s (%d)",
bdb->pageNumber, (const char*) fileName, strerror (errno), errno);
}
@@ -332,7 +332,7 @@ bool IO::trialRead(Bdb *bdb)
void IO::writePage(Bdb * bdb, int type)
{
if (fatalError)
- FATAL ("can't continue after fatal error");
+ throw SQLError(IO_ERROR, "can't continue after fatal error");
ASSERT(bdb->pageNumber != HEADER_PAGE || ((Page*)(bdb->buffer))->pageType == PAGE_header);
tracePage(bdb);
@@ -342,7 +342,7 @@ void IO::writePage(Bdb * bdb, int type)
void IO::writePages(int32 pageNumber, int length, const UCHAR* data, int type)
{
if (fatalError)
- FATAL ("can't continue after fatal error");
+ throw SQLError(IO_ERROR, "can't continue after fatal error");
SEEK_OFFSET offset = (int64) pageNumber * pageSize;
@@ -370,7 +370,7 @@ void IO::writePages(int32 pageNumber, in
declareFatalError();
- FATAL ("write error on page %d (%d/%d/%d) of \"%s\": %s (%d)",
+ throw SQLError(IO_ERROR, "write error on page %d (%d/%d/%d) of \"%s\": %s (%d)",
pageNumber, length, pageSize, fileId,
(const char*) fileName, strerror (errno), errno);
}
@@ -390,7 +390,9 @@ void IO::readHeader(Hdr * header)
n = ::read (fileId, buffer, maxPageSize);
if (n < (int) sizeof (Hdr))
- FATAL ("read error on database header");
+ throw SQLError(IO_ERROR,
+ "read error on tablespace header, file %s, read %d bytes at least %d was expected",
+ fileName.getString(), n, (int) sizeof(Hdr));
Hdr* hdr = (Hdr*) buffer;
if (falcon_checksums && hdr->pageSize <= n)
@@ -564,7 +566,7 @@ void IO::writeHeader(Hdr *header)
n = ::write (fileId, header, sizeof (Hdr));
if (n != sizeof (Hdr))
- FATAL ("write error on database clone header");
+ throw SQLError(IO_ERROR, "write error on database clone header");
}
void IO::deleteFile()
@@ -675,7 +677,7 @@ void IO::sync(void)
if (_commit(fileId))
{
declareFatalError();
- FATAL ("_commit failed on \"%s\": %s (%d)",
+ throw SQLError(IO_ERROR, "_commit failed on \"%s\": %s (%d)",
(const char*) fileName, strerror (errno), errno);
}
@@ -790,6 +792,7 @@ static int winOpen(const char *filename,
switch(GetLastError())
{
case ERROR_ACCESS_DENIED:
+ case ERROR_SHARING_VIOLATION:
errno = EACCES;
break;
case ERROR_FILE_NOT_FOUND:
=== modified file 'storage/falcon/Index.cpp'
--- a/storage/falcon/Index.cpp 2008-12-08 21:15:06 +0000
+++ b/storage/falcon/Index.cpp 2009-01-26 17:34:37 +0000
@@ -28,6 +28,7 @@
#include "Database.h"
#include "Value.h"
#include "Record.h"
+#include "Format.h"
#include "ResultSet.h"
#include "Collation.h"
#include "Sync.h"
@@ -257,12 +258,14 @@ DeferredIndex *Index::getDeferredIndex(T
(type != UniqueIndex) &&
(transaction->scanIndexCount == 0))
{
- if (deferredIndex->sizeEstimate > database->configuration->indexChillThreshold)
+
+ // Scavenge (or chill) this DeferredIndex and get a new one
+
+ if (deferredIndex->count > 0 &&
+ deferredIndex->sizeEstimate > database->configuration->indexChillThreshold)
{
- // Scavenge (or chill) this DeferredIndex and get a new one
- deferredIndex->chill(dbb);
- ASSERT(deferredIndex->virtualOffset);
- deferredIndex = NULL;
+ if (deferredIndex->chill(dbb))
+ deferredIndex = NULL;
}
}
@@ -362,31 +365,29 @@ void Index::makeKey(int count, Value **v
return;
}
- uint p = 0, q = 0;
+ uint p = 0;
int n;
UCHAR *key = indexKey->key;
for (n = 0; (n < count) && values[n]; ++n)
{
Field *field = fields[n];
- char padByte = PAD_BYTE(field);
- while (p % RUN != 0)
- key[p++] = padByte;
IndexKey tempKey(this);
makeKey(field, values[n], n, &tempKey);
int length = tempKey.keyLength;
UCHAR *t = tempKey.key;
-
- // All segments before the last one are padded to the nearest RUN length.
- if (n < count - 1)
- q = (length + RUN - 1) / (RUN - 1) * RUN;
- else
- q = (length * RUN / (RUN - 1)) + (length % (RUN -1));
-
- if (p + q > maxIndexKeyRunLength(database->getMaxKeyLength()))
+ // Calculate segment length to check for index overflow
+ // - There is a segment byte inserted at the start of the segment and every RUN bytes.
+ // - All segments before the last one are padded to the nearest RUN length.
+
+ uint segmentLength = (length + length/(RUN-1) + ((length%(RUN-1))?1:0));
+ if(n < numberFields - 1)
+ segmentLength = ROUNDUP(segmentLength , RUN);
+
+ if (p + segmentLength > maxIndexKeyRunLength(database->getMaxKeyLength()))
throw SQLError (INDEX_OVERFLOW, "maximum index key length exceeded");
for (int i = 0; i < length; ++i)
@@ -396,6 +397,25 @@ void Index::makeKey(int count, Value **v
key[p++] = t[i];
}
+
+ if (n < numberFields - 1)
+ {
+ char padByte = PAD_BYTE(field);
+
+ while (p % RUN != 0)
+ key[p++] = padByte;
+ }
+ }
+
+ if (n && n < numberFields)
+ {
+ // We're constructing partial search key, with only some
+ // first fields given. Append segment byte for the next
+ // segment. This will make key larger and will hopefully
+ // reduce the number of false positives in search (saves
+ // work in postprocessing).
+ if (p < (uint)database->getMaxKeyLength())
+ key[p++] = SEGMENT_BYTE(n, numberFields);
}
indexKey->keyLength = p;
@@ -406,8 +426,14 @@ void Index::deleteIndex(Transaction *tra
{
if (!damaged && indexId != -1)
{
- dbb->deleteIndex(indexId, indexVersion, TRANSACTION_ID(transaction));
+
+ // The Index class does not use a Sync object. To ensure that concurrent
+ // SRLUpdateIndex operations ignore DeferredIndexes associated with
+ // this index, set indexId to -1 before writing to the Serial Log.
+
+ int id = indexId;
indexId = -1;
+ dbb->deleteIndex(id, indexVersion, TRANSACTION_ID(transaction));
}
}
@@ -582,6 +608,9 @@ void Index::update(Record * oldRecord, R
// If there is a duplicate in the old version chain, don't bother with another
+ Sync syncPrior(record->format->table->getSyncPrior(record), "Index::update");
+ syncPrior.lock(Shared);
+
if (duplicateKey (&key, oldRecord))
return;
@@ -614,13 +643,18 @@ void Index::garbageCollect(Record * leav
{
int n = 0;
+ // Delete index entries of prior record versions of the 'leaving' record
+
for (Record *record = leaving; record && record != staying; record = record->getGCPriorVersion(), ++n)
if (record->hasRecord() && record->recordNumber >= 0)
{
IndexKey key(this);
makeKey (record, &key);
- if (!duplicateKey(&key, record->getPriorVersion()) && !duplicateKey (&key, staying))
+ // Delete the index entry for this record version if the key is not used by other record versions
+
+ if (!duplicateKey(&key, record->getPriorVersion()) // key not in 'leaving' record chain
+ && !duplicateKey (&key, staying)) // key not in 'staying' record chain
{
bool hit = false;
@@ -634,6 +668,8 @@ void Index::garbageCollect(Record * leav
hit = true;
}
+ // Delete the index entry directly from the index page
+
if (dbb->deleteIndexEntry(indexId, indexVersion, &key, record->recordNumber, TRANSACTION_ID(transaction)))
hit = true;
=== modified file 'storage/falcon/Interlock.h'
--- a/storage/falcon/Interlock.h 2008-12-11 12:35:08 +0000
+++ b/storage/falcon/Interlock.h 2009-01-10 16:00:02 +0000
@@ -52,9 +52,9 @@
/* Visual Studio 2003 and earlier do not have prototypes for atomic intrinsics */
extern "C"
{
- long _InterlockedIncrement(long volatile *Addend);
+ long _InterlockedIncrement(long volatile *Addend);
long _InterlockedDecrement(long volatile *Addend);
- long _InterlockedExchangeAdd(long volatile *Addend, long Value);
+ long _InterlockedExchangeAdd(long volatile *Addend, long Value);
long _InterlockedExchange(long volatile *Target,long Value);
long _InterlockedCompareExchange (long volatile *Target, long Value, long Comp);
}
=== modified file 'storage/falcon/Makefile.am'
--- a/storage/falcon/Makefile.am 2008-12-07 13:00:15 +0000
+++ b/storage/falcon/Makefile.am 2009-01-28 06:52:48 +0000
@@ -152,6 +152,7 @@ falcon_headers= Agent.h Alias.h Applicat
SRLIndexDelete.h \
SRLIndexPage.h \
SRLIndexUpdate.h \
+ SRLInventoryPage.h \
SRLInversionPage.h \
SRLOverflowPages.h \
SRLPrepare.h \
@@ -213,7 +214,7 @@ falcon_sources= Agent.cpp Alias.cpp \
BDB.cpp \
BigInt.cpp \
BigInteger.cpp \
- BinaryBlob.cpp Bitmap.cpp Blob.cpp \
+ BinaryBlob.cpp Bitmap.cpp \
BlobReference.cpp Btn.cpp Cache.cpp CmdGen.cpp \
CollationCaseless.cpp \
CollationUnknown.cpp \
@@ -278,7 +279,7 @@ falcon_sources= Agent.cpp Alias.cpp \
NInSelectBitmap.cpp NInSelect.cpp NInsert.cpp NMatching.cpp \
NNode.cpp NParameter.cpp NRecordNumber.cpp NRepair.cpp \
NReplace.cpp NSelect.cpp NSelectExpr.cpp NSequence.cpp \
- NStat.cpp NUpdate.cpp OpSys.cpp Page.cpp \
+ NStat.cpp NUpdate.cpp OpSys.cpp \
PageInventoryPage.cpp PagePrecedence.cpp PageWriter.cpp \
Parameter.cpp Parameters.cpp PreparedStatement.cpp \
PrettyPrint.cpp \
@@ -335,6 +336,7 @@ falcon_sources= Agent.cpp Alias.cpp \
SRLIndexDelete.cpp \
SRLIndexPage.cpp \
SRLIndexUpdate.cpp \
+ SRLInventoryPage.cpp \
SRLInversionPage.cpp \
SRLOverflowPages.cpp \
SRLPrepare.cpp \
@@ -369,7 +371,6 @@ falcon_sources= Agent.cpp Alias.cpp \
SyncHandler.cpp \
SyncObject.cpp\
SyncTest.cpp\
- SyncWait.cpp\
Syntax.cpp\
TableAttachment.cpp \
Table.cpp \
=== modified file 'storage/falcon/MemMgr.cpp'
--- a/storage/falcon/MemMgr.cpp 2008-11-03 00:34:05 +0000
+++ b/storage/falcon/MemMgr.cpp 2009-01-08 09:05:26 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -1209,3 +1209,10 @@ void MemMgr::validateBlock(MemBlock *blo
corrupt ("guard bytes overwritten");
#endif
}
+
+int MemMgr::blockSize(void *object)
+{
+ MemBlock *block = (MemBlock*) ((UCHAR*) object - OFFSET(MemBlock*, body));
+
+ return ABS(block->length);
+}
=== modified file 'storage/falcon/MemMgr.h'
--- a/storage/falcon/MemMgr.h 2008-10-31 15:42:42 +0000
+++ b/storage/falcon/MemMgr.h 2009-01-08 09:05:26 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -163,7 +163,7 @@ public:
static void release(void* block);
static void validate(void *object);
static void validateBlock (void *object);
-
+ static int blockSize(void *object);
};
#endif
=== removed file 'storage/falcon/Page.cpp'
--- a/storage/falcon/Page.cpp 2007-11-24 20:10:33 +0000
+++ b/storage/falcon/Page.cpp 1970-01-01 00:00:00 +0000
@@ -1,38 +0,0 @@
-/* Copyright (C) 2006 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-// Page.cpp: implementation of the Page class.
-//
-//////////////////////////////////////////////////////////////////////
-
-#include "Engine.h"
-#include "Page.h"
-
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
-/***
-Page::Page()
-{
-
-}
-
-Page::~Page()
-{
-
-}
-***/
-
=== modified file 'storage/falcon/PageInventoryPage.cpp'
--- a/storage/falcon/PageInventoryPage.cpp 2008-11-14 02:30:11 +0000
+++ b/storage/falcon/PageInventoryPage.cpp 2009-01-27 20:44:30 +0000
@@ -33,6 +33,7 @@
#include "SQLError.h"
#include "SerialLog.h"
#include "Database.h"
+#include "SerialLogControl.h"
#ifdef _DEBUG
#undef THIS_FILE
@@ -77,6 +78,10 @@ Bdb* PageInventoryPage::createInventoryP
for (int n = 0; n < dbb->pipSlots; ++n)
page->freePages [n] = -1;
+ if (dbb->database->serialLog && !dbb->database->serialLog->recovering
+ && (pageNumber != PIP_PAGE))
+ dbb->database->serialLog->logControl->inventoryPage.append(dbb, pageNumber);
+
return bdb;
}
=== modified file 'storage/falcon/Record.cpp'
--- a/storage/falcon/Record.cpp 2008-10-29 23:25:13 +0000
+++ b/storage/falcon/Record.cpp 2009-02-01 09:00:52 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,6 +22,7 @@
#include "Engine.h"
#include "Record.h"
#include "RecordVersion.h"
+#include "RecordScavenge.h"
#include "Value.h"
#include "Transaction.h"
#include "Format.h"
@@ -36,7 +37,8 @@
#include "EncodedRecord.h"
#include "Field.h"
#include "Serialize.h"
-
+#include "MemMgr.h"
+#include "Thread.h"
#undef new
#ifdef _DEBUG
@@ -484,10 +486,23 @@ bool Record::isVersion()
return false;
}
-
-bool Record::scavenge(RecordScavenge *recordScavenge, LockType lockType)
+bool Record::retire(RecordScavenge *recordScavenge)
{
- return true;
+ if (generation <= recordScavenge->scavengeGeneration)
+ {
+ recordScavenge->spaceRetired += getMemUsage();
+ ++recordScavenge->recordsRetired;
+#ifdef CHECK_RECORD_ACTIVITY
+ active = false;
+#endif
+ release();
+ return true;
+ }
+
+ ++recordScavenge->recordsRemaining;
+ recordScavenge->spaceRemaining += getMemUsage();
+
+ return false;
}
void Record::scavenge(TransId targetTransactionId, int oldestActiveSavePointId)
@@ -840,7 +855,6 @@ Record* Record::releaseNonRecursive(void
Record* Record::clearPriorVersion(void)
{
- ASSERT(false);
return NULL;
}
@@ -913,19 +927,39 @@ void Record::validateData(void)
ASSERT(data.record);
}
+// Allocate a record data buffer from the record cache.
+// Use an non-thread-safe increment of recordPoolAllocCount. It allows
+// full concurrency by multiple threads but it may miss a check every
+// now and then. This keeps the code from doing this check every time.
+// It is done about every 128 allocations from the record cache.
+
char* Record::allocRecordData(int length)
{
- for (int n = 0;; ++n)
+ for (int n = 1;; ++n)
try
{
+ if (format && format->table)
+ if ((++format->table->database->recordPoolAllocCount & 0x7F) == 0)
+ format->table->database->checkRecordScavenge();
+
return POOL_NEW(format->table->database->recordDataPool) char[length];
}
catch (SQLException& exception)
{
- if (n > 2 || exception.getSqlcode() != OUT_OF_RECORD_MEMORY_ERROR)
+ // If the error was out-of-memory, signal the scavenger,
+ // sleep(10),and try again. But try a limited number of times.
+
+ if ( exception.getSqlcode() != OUT_OF_RECORD_MEMORY_ERROR
+ || n > OUT_OF_RECORD_MEMORY_RETRIES)
throw;
- format->table->database->forceRecordScavenge();
+ format->table->database->signalScavenger(true);
+
+ // Give the scavenger thread a chance to release memory.
+ // Increase the wait time per iteration.
+
+ Thread *thread = Thread::getThread("Database::ticker");
+ thread->sleep(n * SCAVENGE_WAIT_MS);
}
return NULL;
@@ -960,6 +994,18 @@ int Record::getSize(void)
return sizeof(*this);
}
+int Record::getDataMemUsage(void)
+{
+ return (data.record == NULL ? 0 : MemMgr::blockSize(data.record));
+}
+
+int Record::getMemUsage(void)
+{
+ int objectSize = MemMgr::blockSize(this);
+ return objectSize + getDataMemUsage();
+}
+
+
SyncObject* Record::getSyncPrior(void)
{
return format->table->getSyncPrior(this);
=== modified file 'storage/falcon/Record.h'
--- a/storage/falcon/Record.h 2008-10-29 23:25:13 +0000
+++ b/storage/falcon/Record.h 2009-01-17 08:22:44 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,7 +27,7 @@
#define ALLOCATE_RECORD(n) (char*) MemMgrRecordAllocate (n, __FILE__, __LINE__)
#define DELETE_RECORD(record) MemMgrRecordDelete (record);
-#define CHECK_RECORD_ACTIVITY
+//#define CHECK_RECORD_ACTIVITY
#include "SynchronizationObject.h"
@@ -50,9 +50,10 @@ static const int recLock = 4; // this i
static const int recNoChill = 5; // record is in use and should not be chilled
static const int recRollback = 6; // record is being rolled back
static const int recUnlocked = 7; // record is being unlocked
-static const int recDeleting = 8; // record is being physically deleted
-static const int recPruning = 9; // record is being pruned
-static const int recEndChain = 10; // end of chain for garbage collection
+static const int recInserting = 8; // record is being physically inserted
+static const int recDeleting = 9; // record is being physically deleted
+static const int recPruning = 10; // record is being pruned
+static const int recEndChain = 11; // end of chain for garbage collection
class Format;
class Table;
@@ -77,7 +78,7 @@ public:
virtual void setSuperceded (bool flag);
virtual Record* fetchVersion (Transaction * transaction);
virtual Record* fetchVersionRecursive (Transaction *transaction);
- virtual bool scavenge(RecordScavenge *recordScavenge, LockType lockType);
+ virtual bool retire(RecordScavenge *recordScavenge);
virtual void scavenge(TransId targetTransactionId, int oldestActiveSavePointId);
virtual bool isVersion();
virtual bool isSuperceded();
@@ -115,6 +116,8 @@ public:
void validateData(void);
char* allocRecordData(int length);
void expungeRecord(void);
+ int getDataMemUsage(void);
+ int getMemUsage(void);
Record (Table *table, Format *recordFormat);
Record (Table *table, int32 recordNumber, Stream *stream);
=== modified file 'storage/falcon/RecordGroup.cpp'
--- a/storage/falcon/RecordGroup.cpp 2008-10-16 02:40:08 +0000
+++ b/storage/falcon/RecordGroup.cpp 2009-01-08 09:05:26 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -110,9 +110,8 @@ bool RecordGroup::store(Record * record,
return section->store(record, prior, id % base, NULL);
}
-int RecordGroup::retireRecords(Table *table, int base, RecordScavenge *recordScavenge)
+void RecordGroup::pruneRecords(Table *table, int base, RecordScavenge *recordScavenge)
{
- int count = 0;
int recordNumber = base * RECORD_SLOTS;
for (RecordSection **ptr = records, **end = records + RECORD_SLOTS; ptr < end; ++ptr, ++recordNumber)
@@ -120,23 +119,21 @@ int RecordGroup::retireRecords(Table *ta
RecordSection *section = *ptr;
if (section)
- {
- int n = section->retireRecords(table, recordNumber, recordScavenge);
- count += n;
-
- /***
- if (n)
- count += n;
- else
- {
- delete section;
- *ptr = NULL;
- }
- ***/
- }
+ section->pruneRecords(table, recordNumber, recordScavenge);
}
+}
- return count;
+void RecordGroup::retireRecords(Table *table, int base, RecordScavenge *recordScavenge)
+{
+ int recordNumber = base * RECORD_SLOTS;
+
+ for (RecordSection **ptr = records, **end = records + RECORD_SLOTS; ptr < end; ++ptr, ++recordNumber)
+ {
+ RecordSection *section = *ptr;
+
+ if (section)
+ section->retireRecords(table, recordNumber, recordScavenge);
+ }
}
int RecordGroup::countActiveRecords()
@@ -216,10 +213,3 @@ bool RecordGroup::retireSections(Table *
return inactive();
}
-
-void RecordGroup::inventoryRecords(RecordScavenge* recordScavenge)
-{
- for (RecordSection **section = records, **end = records + RECORD_SLOTS; section < end; ++section)
- if (*section)
- (*section)->inventoryRecords(recordScavenge);
-}
=== modified file 'storage/falcon/RecordGroup.h'
--- a/storage/falcon/RecordGroup.h 2008-10-16 02:40:08 +0000
+++ b/storage/falcon/RecordGroup.h 2009-01-08 09:05:26 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -35,11 +35,11 @@ public:
virtual int countActiveRecords();
virtual bool anyActiveRecords();
- virtual int chartActiveRecords(int *chart);
+ virtual int chartActiveRecords(int *chart);
virtual bool store (Record *record, Record *prior, int32 id, RecordSection **parentPtr);
- virtual void inventoryRecords(RecordScavenge* recordScavenge);
virtual Record* fetch (int32 id);
- virtual int retireRecords(Table *table, int base, RecordScavenge *recordScavenge);
+ virtual void pruneRecords(Table *table, int base, RecordScavenge *recordScavenge);
+ virtual void retireRecords(Table *table, int base, RecordScavenge *recordScavenge);
virtual bool retireSections(Table * table, int id);
virtual bool inactive();
=== modified file 'storage/falcon/RecordLeaf.cpp'
--- a/storage/falcon/RecordLeaf.cpp 2008-10-16 02:40:08 +0000
+++ b/storage/falcon/RecordLeaf.cpp 2009-01-27 17:32:40 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -114,115 +114,107 @@ bool RecordLeaf::store(Record *record, R
return true;
}
-int RecordLeaf::retireRecords (Table *table, int base, RecordScavenge *recordScavenge)
+// Prune old invisible record versions from the end of record chains.
+// The visible versions at the front of the list are kept.
+// Also, inventory each record slot on this leaf.
+
+void RecordLeaf::pruneRecords (Table *table, int base, RecordScavenge *recordScavenge)
{
- int count = 0;
Record **ptr, **end;
- Sync sync(&syncObject, "RecordLeaf::retireRecords(syncObject)");
+
+ // Get a shared lock since we are just traversing the tree.
+ // pruneRecords does not empty any slots in a record leaf.
+
+ Sync sync(&syncObject, "RecordLeaf::pruneRecords(syncObject)");
sync.lock(Shared);
-
- // Get a shared lock to find at least one record to scavenge
- // If scavengeGeneration == UNDEFINED then just count the records in the leaf.
-
+
for (ptr = records, end = records + RECORD_SLOTS; ptr < end; ++ptr)
{
Record *record = *ptr;
if (record)
{
- if (recordScavenge->scavengeGeneration == UNDEFINED)
- ++count;
- else if (record->isVersion())
+ Record* oldestVisible = recordScavenge->inventoryRecord(record);
+
+ // Prune invisible records.
+
+ if (oldestVisible)
{
- Sync syncPrior(record->getSyncPrior(), "RecordLeaf::retireRecords(prior)");
- syncPrior.lock(Shared);
-
- if (record->scavenge(recordScavenge, Shared))
- break;
- else
- ++count;
+ ASSERT(oldestVisible->state != recLock);
+
+ Record *prior = oldestVisible->clearPriorVersion();
+
+ for (Record *prune = prior; prune; prune = prune->getPriorVersion())
+ {
+ if (prune->useCount != 1)
+ {
+ prior = NULL;
+ break;
+ }
+ recordScavenge->recordsPruned++;
+ recordScavenge->spacePruned += prune->getMemUsage();
+ }
+
+ if (prior)
+ {
+#ifdef CHECK_RECORD_ACTIVITY
+ prior->active = false;
+#endif
+ table->garbageCollect(prior, record, NULL, false);
+ prior->release();
+ }
}
- else if ( record->generation <= recordScavenge->scavengeGeneration
- && record->useCount == 1)
- break;
- else
- ++count;
}
}
+}
+
+void RecordLeaf::retireRecords (Table *table, int base, RecordScavenge *recordScavenge)
+{
+ int count = 0;
+ Record **ptr, **end;
+
+ Sync sync(&syncObject, "RecordLeaf::retireRecords(syncObject)");
+ sync.lock(Shared);
+
+ // Get a shared lock to find at least one record to scavenge
+
+ for (ptr = records, end = records + RECORD_SLOTS; ptr < end; ++ptr)
+ {
+ Record *record = *ptr;
+
+ if (record && recordScavenge->canBeRetired(record))
+ break;
+ }
if (ptr >= end)
- return count;
-
- // Get an exclusive lock and do the actual scavenging
-
+ return;
+
+ // We can retire at least one record from this leaf;
+ // Get an exclusive lock and retire as many as possible.
+
sync.unlock();
sync.lock(Exclusive);
- count = 0;
-
+
for (ptr = records; ptr < end; ++ptr)
{
Record *record = *ptr;
- if (record)
+ if (record && recordScavenge->canBeRetired(record))
{
- if (record->isVersion())
- {
- Sync syncPrior(record->getSyncPrior(), "RecordLeaf::retireRecords(3)");
- syncPrior.lock(Exclusive);
-
- if (record->scavenge(recordScavenge, Exclusive))
- {
- *ptr = NULL;
- recordScavenge->spaceReclaimed += record->size;
- ++recordScavenge->recordsReclaimed;
-#ifdef CHECK_RECORD_ACTIVITY
- record->active = false;
-#endif
- if (record->state == recDeleted)
- record->expungeRecord();
-
- record->release();
- }
- else
- {
- ++recordScavenge->recordsRemaining;
- recordScavenge->spaceRemaining += record->size;
- ++count;
- }
- }
- else if ( (record->generation <= recordScavenge->scavengeGeneration)
- && (record->useCount == 1))
- {
+ if (record->retire(recordScavenge))
*ptr = NULL;
- recordScavenge->spaceReclaimed += record->size;
- ++recordScavenge->recordsReclaimed;
-#ifdef CHECK_RECORD_ACTIVITY
- record->active = false;
-#endif
- record->release();
- }
else
- {
- ++recordScavenge->recordsRemaining;
- recordScavenge->spaceRemaining += record->size;
- ++count;
-
- for (Record *prior = record->getPriorVersion(); prior; prior = prior->getPriorVersion())
- {
- ++recordScavenge->versionsRemaining;
- recordScavenge->spaceRemaining += prior->size;
- }
- }
+ count++;
}
}
-
+
// If this node is empty, store the base record number for use as an
// identifier when the leaf node is scavenged later.
-
+
if (!count && table->emptySections)
table->emptySections->set(base);
- return count;
+ return;
}
bool RecordLeaf::retireSections(Table * table, int id)
@@ -262,13 +254,3 @@ int RecordLeaf::chartActiveRecords(int *
return count;
}
-
-void RecordLeaf::inventoryRecords(RecordScavenge* recordScavenge)
-{
- Sync sync(&syncObject, "RecordLeaf::inventoryRecords");
- sync.lock(Shared);
-
- for (Record **ptr = records, **end = records + RECORD_SLOTS; ptr < end; ++ptr)
- if (*ptr)
- recordScavenge->inventoryRecord(*ptr);
-}
=== modified file 'storage/falcon/RecordLeaf.h'
--- a/storage/falcon/RecordLeaf.h 2008-10-16 02:40:08 +0000
+++ b/storage/falcon/RecordLeaf.h 2009-01-08 09:05:26 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -34,7 +34,8 @@ public:
virtual int countActiveRecords();
virtual bool anyActiveRecords();
virtual int chartActiveRecords(int *chart);
- virtual int retireRecords(Table *table, int id, RecordScavenge *recordScavenge);
+ virtual void pruneRecords(Table *table, int id, RecordScavenge *recordScavenge);
+ virtual void retireRecords(Table *table, int id, RecordScavenge *recordScavenge);
virtual bool retireSections(Table * table, int id);
virtual bool inactive();
virtual bool store(Record *record, Record *prior, int32 id,RecordSection **parentPtr);
@@ -44,7 +45,6 @@ public:
Record *records [RECORD_SLOTS];
SyncObject syncObject;
- void inventoryRecords(RecordScavenge* recordScavenge);
};
#endif // !defined(AFX_RECORDLEAF_H__02AD6A56_A433_11D2_AB5B_0000C01D2301__INCLUDED_)
=== modified file 'storage/falcon/RecordLocatorPage.cpp'
--- a/storage/falcon/RecordLocatorPage.cpp 2008-06-17 17:41:54 +0000
+++ b/storage/falcon/RecordLocatorPage.cpp 2009-01-30 11:35:52 +0000
@@ -269,7 +269,9 @@ void RecordLocatorPage::printPage(void)
void RecordLocatorPage::setIndexSlot(int slot, int32 pageNumber, int line, int availableSpace)
{
- ASSERT(availableSpace >= 0);
+ // Check that availableSpace is positive and can be converted to short
+ // without losing bits or changing sign
+ ASSERT(availableSpace >= 0 && availableSpace < 0x8000);
RecordIndex *element = elements + slot;
//validateSpaceSlots();
=== modified file 'storage/falcon/RecordScavenge.cpp'
--- a/storage/falcon/RecordScavenge.cpp 2008-10-29 23:25:13 +0000
+++ b/storage/falcon/RecordScavenge.cpp 2009-02-03 02:53:42 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007 MySQL AB
+/* Copyright (C) 2007 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,90 +18,327 @@
#include "RecordScavenge.h"
#include "Database.h"
#include "Record.h"
+#include "RecordVersion.h"
#include "Log.h"
#include "MemMgr.h"
#include "Sync.h"
+#include "Transaction.h"
+#include "TransactionManager.h"
-
-RecordScavenge::RecordScavenge(Database *db, TransId oldestTransaction, bool wasForced)
+RecordScavenge::RecordScavenge(Database *db, uint64 generation, bool forceScavenge)
+ : database(db), baseGeneration(generation), forced(forceScavenge)
{
- database = db;
- transactionId = oldestTransaction;
- forced = wasForced;
- baseGeneration = database->currentGeneration;
+ cycle = ++database->scavengeCycle;
+
memset(ageGroups, 0, sizeof(ageGroups));
- recordsReclaimed = 0;
+ veryOldRecords = 0;
+ veryOldRecordSpace = 0;
+
+ startingActiveMemory = database->recordDataPool->activeMemory;
+ prunedActiveMemory = 0;
+ retiredActiveMemory = 0;
+
+ scavengeStart = database->deltaTime;
+ pruneStop = 0;
+ retireStop = 0;
+ scavengeGeneration = 0;
+
+ // Results of Scavenging
+ recordsPruned = 0;
+ spacePruned = 0;
+ recordsRetired = 0;
+ spaceRetired = 0;
recordsRemaining = 0;
- versionsRemaining = 0;
- spaceReclaimed = 0;
spaceRemaining = 0;
- overflowSpace = 0;
- numberRecords = 0;
- recordSpace = 0;
+
+ // Results of the inventory
+ totalRecords = 0;
+ totalRecordSpace = 0;
+ pruneableRecords = 0;
+ pruneableSpace = 0;
+ retireableRecords = 0;
+ retireableSpace = 0;
+ unScavengeableRecords = 0;
+ unScavengeableSpace = 0;
+
+ Sync syncActive(&database->transactionManager->activeTransactions.syncObject, "RecordScavenge::RecordScavenge");
+ syncActive.lock(Shared);
+
+ oldestActiveTransaction = database->transactionManager->findOldestInActiveList();
}
RecordScavenge::~RecordScavenge(void)
{
}
-void RecordScavenge::inventoryRecord(Record* record)
+bool RecordScavenge::canBeRetired(Record* record)
+{
+ // Check if this record can be retired
+
+ if (record->generation <= scavengeGeneration)
+ {
+ // Record objects are read from pages
+
+ if (!record->isVersion())
+ return true;
+
+ RecordVersion * recVer = (RecordVersion *) record;
+ ASSERT(!recVer->superceded); // Must be the base record
+
+ // This record version may be retired if
+ // it is currently not pointed to by a transaction
+
+ if (!recVer->transaction)
+ return true;
+ }
+
+ return false;
+}
+
+// Take an inventory of every record in this record chain.
+// If there are any old invisible records at the end of
+// the chain, return a pointer to the oldest visible record.
+// It is assumed that the record sent is the 'base' record,
+// which means that the RecordLeaf has a pointer to this.
+// It is what you get from a Table::fetch()
+// Only base records with no priorRecords attached can be 'retired'.
+// 'Pruning' involved releasing the priorRecords at the end
+// of the chain that are no longer visible to any active transaction.
+
+Record* RecordScavenge::inventoryRecord(Record* record)
{
+ Record *oldestVisibleRec = NULL;
+
Sync syncPrior(record->getSyncPrior(), "RecordScavenge::inventoryRecord");
syncPrior.lock(Shared);
for (Record *rec = record; rec; rec = rec->getPriorVersion())
{
- ++numberRecords;
- recordSpace += record->size;
- uint64 age = baseGeneration - record->generation;
- int size = record->size + sizeof(MemBigHeader);
-
- if (record->hasRecord(false) || (record->state == recChilled))
- size += sizeof(MemBigHeader);
+ int scavengeType = CANNOT_SCAVENGE; // Initial value
+
+ ++totalRecords;
+ int size = rec->getMemUsage();
+ totalRecordSpace += size;
+
+ // Check if this record can be scavenged somehow
+
+ if (!rec->isVersion())
+ {
+ // This Record object was read from a page on disk
+
+ if (rec == record)
+ scavengeType = CAN_BE_RETIRED; // This is a base Record object
+ else
+ {
+ // There must be some newer RecordVersions.
+
+ if (oldestVisibleRec)
+ scavengeType = CAN_BE_PRUNED; // This is a Record object at the end of a chain.
+ else
+ oldestVisibleRec = rec;
+ }
+ }
+
+ else // This is a RecordVersion object
+ {
+ RecordVersion * recVer = (RecordVersion *) rec;
+
+ // We assume here that Transaction::commitRecords is only called
+ // when there are no dependent transactions. It means that if the
+ // transaction pointer is null, and we do not know the commitId,
+ // Then we can be assured that the recVer was committed before
+ // any active transaction, including oldestActiveTransaction.
+
+ bool committedBeforeAnyActiveTrans = recVer->committedBefore(oldestActiveTransaction);
+
+ // This recVer 'may' be retired if it is the base record AND
+ // it is currently not needed by any active transaction.
+
+ if (recVer == record && committedBeforeAnyActiveTrans)
+ scavengeType = CAN_BE_RETIRED;
- if (age != UNDEFINED && age < AGE_GROUPS)
- ageGroups[age] += size;
- else if (age >= AGE_GROUPS)
- overflowSpace += size;
- else
- ageGroups[0] = size;
+ // Look for the oldest visible record version in this chain.
+
+ if (oldestVisibleRec)
+ {
+ // Younger transactions may commit before older transactions.
+ // If this older record is visible, then forget oldestVisibleRec
+
+ if (!committedBeforeAnyActiveTrans)
+ oldestVisibleRec = NULL;
+
+ else
+ {
+ // Do not prune records that have other pointers to them.
+
+ if (recVer->useCount != 1)
+ oldestVisibleRec = rec; // Rreset this pointer.
+ else
+ scavengeType = CAN_BE_PRUNED;
+ }
+ }
+ else if (committedBeforeAnyActiveTrans)
+ {
+ ASSERT(rec->state != recLock);
+ oldestVisibleRec = rec;
+ }
+ }
+
+ // Add up the scavengeable space.
+
+ switch (scavengeType)
+ {
+ case CAN_BE_PRUNED:
+ pruneableRecords++;
+ pruneableSpace += size;
+ break;
+
+ case CAN_BE_RETIRED:
+ retireableRecords++;
+ retireableSpace += size;
+ break;
+
+ default:
+ unScavengeableRecords++;
+ unScavengeableSpace += size;
+ }
+
+ // Add up all retireable records in a array of relative ages
+ // from our baseGeneration. Only base records can be retired.
+
+ if (rec == record)
+ {
+ int64 age = (int64) baseGeneration - (int64) rec->generation;
+
+ // While this inventory is happening, newer records could be
+ // created that are a later generation than our baseGeneration.
+ // So check for age < 0.
+
+ if (age < 0)
+ ageGroups[0] += size;
+ else if (age < 1)
+ ageGroups[0] += size;
+ else if (age < (int64) AGE_GROUPS)
+ ageGroups[age] += size;
+ else // age >= AGE_GROUPS
+ {
+ veryOldRecords++;
+ veryOldRecordSpace += size;
+ }
+ }
}
+
+ return oldestVisibleRec;
}
-uint64 RecordScavenge::computeThreshold(uint64 target)
+uint64 RecordScavenge::computeThreshold(uint64 spaceToRetire)
{
- totalSpace = 0;
+ uint64 totalSpace = veryOldRecordSpace;
scavengeGeneration = 0;
-
- for (uint64 n = 0; n < AGE_GROUPS; ++n)
+
+ // The baseGeneration is the currentGeneration when the scavenge started
+ // It is in ageGroups[0]. Next oldest in ageGroups[1], etc.
+ // Find the youngest generation to start scavenging.
+ // Scavenge that scavengeGeneration and older.
+
+ for (int n = AGE_GROUPS - 1; n && !scavengeGeneration; n--)
{
totalSpace += ageGroups[n];
-
- if (totalSpace >= target && scavengeGeneration == 0)
+
+ if (totalSpace >= spaceToRetire)
scavengeGeneration = baseGeneration - n;
}
- totalSpace += overflowSpace;
-
- if (forced || (scavengeGeneration == 0 && totalSpace > target))
- scavengeGeneration = baseGeneration + AGE_GROUPS;
+ // We still may want to scavenge even if the age group total is
+ // too small, so use the base generation as a starting point.
- return scavengeGeneration;
+ return (scavengeGeneration ? scavengeGeneration : baseGeneration);
}
-void RecordScavenge::printRecordMemory(void)
+void RecordScavenge::print(void)
{
- Log::debug ("Record Memory usage for %s:\n", (const char*) database->name);
+ Log::log(LogScavenge, "=== Scavenge Cycle " I64FORMAT " - %s - %d seconds\n",
+ cycle, (const char*) database->name, retireStop - scavengeStart);
+
+ if (!recordsPruned && !recordsRetired)
+ return;
+
uint64 max;
+ // Find the maximum age group represented
+
for (max = AGE_GROUPS - 1; max > 0; --max)
if (ageGroups[max])
break;
+ Log::log (LogScavenge,"Cycle=" I64FORMAT
+ " Base Generation=" I64FORMAT
+ " Scavenge Generation=" I64FORMAT
+ " Forced=%d"
+ " Low Memory=%d\n",
+ cycle, baseGeneration, scavengeGeneration, (int)forced, (int)database->lowMemory);
+ Log::log (LogScavenge,"Cycle=" I64FORMAT
+ " Oldest Active Transaction=%d\n",
+ cycle, oldestActiveTransaction);
+ Log::log (LogScavenge,"Cycle=" I64FORMAT
+ " Threshold=" I64FORMAT
+ " Floor=" I64FORMAT
+ " Now=" I64FORMAT "\n",
+ cycle, database->recordScavengeThreshold,
+ database->recordScavengeFloor,
+ retiredActiveMemory );
for (uint64 n = 0; n <= max; ++n)
if (ageGroups [n])
- Log::debug (" %d. %d\n", baseGeneration - n, ageGroups[n]);
+ Log::log (LogScavenge,"Cycle=" I64FORMAT
+ " Age=" I64FORMAT " Size=" I64FORMAT "\n",
+ cycle, baseGeneration - n, ageGroups[n]);
+ Log::log (LogScavenge,"Cycle=" I64FORMAT
+ " Very Old Records=" I64FORMAT " Size=" I64FORMAT "\n",
+ cycle, veryOldRecords, veryOldRecordSpace);
+
+ // Results of the inventory
+
+ Log::log (LogScavenge,"Cycle=" I64FORMAT
+ " Inventory; Total records=" I64FORMAT " containing " I64FORMAT " bytes\n",
+ cycle, totalRecords, totalRecordSpace);
+ Log::log (LogScavenge,"Cycle=" I64FORMAT
+ " Inventory; Pruneable records=" I64FORMAT " containing " I64FORMAT " bytes\n",
+ cycle, pruneableRecords, pruneableSpace);
+ Log::log (LogScavenge,"Cycle=" I64FORMAT
+ " Inventory; Retireable records=" I64FORMAT " containing " I64FORMAT " bytes\n",
+ cycle, retireableRecords, retireableSpace);
+ Log::log (LogScavenge,"Cycle=" I64FORMAT
+ " Inventory; unScavengeable records=" I64FORMAT " containing " I64FORMAT " bytes\n",
+ cycle, unScavengeableRecords, unScavengeableSpace);
+
+ // Results of the Scavenge Cycle;
+
+ Log::log(LogScavenge, "Cycle=" I64FORMAT
+ " Results; Pruned " I64FORMAT " records, " I64FORMAT
+ " bytes in %d seconds\n",
+ cycle, recordsPruned, spacePruned, pruneStop - scavengeStart);
+ Log::log(LogScavenge, "Cycle=" I64FORMAT
+ " Results; Retired " I64FORMAT " records, " I64FORMAT
+ " bytes in %d seconds\n",
+ cycle, recordsRetired, spaceRetired, retireStop - pruneStop);
+
+ if (!recordsRetired)
+ {
+ recordsRemaining = totalRecords - recordsPruned - recordsRetired;
+ spaceRemaining = totalRecordSpace - spacePruned - spaceRetired;
+ }
- Log::log(LogScavenge, " total: " I64FORMAT ", threshold %d%s\n", totalSpace, scavengeGeneration,
- (scavengeGeneration > 0) ? " -- scavenge" : "");
+ Log::log(LogScavenge, "Cycle=" I64FORMAT
+ " Results; Remaining " I64FORMAT
+ " Records, " I64FORMAT " remaining bytes\n",
+ cycle, recordsRemaining, spaceRemaining);
+ Log::log (LogScavenge,"Cycle=" I64FORMAT
+ " Results; Active memory at Scavenge Start=" I64FORMAT "\n",
+ cycle, startingActiveMemory);
+ Log::log (LogScavenge,"Cycle=" I64FORMAT
+ " Results; Active memory after Pruning Records=" I64FORMAT "\n",
+ cycle, prunedActiveMemory);
+ Log::log (LogScavenge,"Cycle=" I64FORMAT
+ " Results; Active memory after Retiring Records=" I64FORMAT "\n",
+ cycle, retiredActiveMemory );
}
=== modified file 'storage/falcon/RecordScavenge.h'
--- a/storage/falcon/RecordScavenge.h 2008-05-09 19:58:50 +0000
+++ b/storage/falcon/RecordScavenge.h 2009-02-01 08:18:51 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007 MySQL AB
+/* Copyright (C) 2007 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,8 +16,12 @@
#ifndef _RECORD_SCAVENGE_H_
#define _RECORD_SCAVENGE_H_
-static const uint64 AGE_GROUPS = 20;
-static const uint64 UNDEFINED = -1;
+static const uint64 AGE_GROUPS = 100;
+static const uint64 AGE_GROUPS_IN_CACHE = 50;
+
+static const int CANNOT_SCAVENGE = 1;
+static const int CAN_BE_RETIRED = 2;
+static const int CAN_BE_PRUNED = 3;
class Database;
class Record;
@@ -25,28 +29,50 @@ class Record;
class RecordScavenge
{
public:
+ RecordScavenge(Database *db, uint64 generation, bool forceScavenge = false);
+ ~RecordScavenge(void);
+
+ bool canBeRetired(Record* record);
+ Record* inventoryRecord(Record* record);
+ uint64 computeThreshold(uint64 spaceToRetire);
+ void print(void);
+
Database *database;
- TransId transactionId;
- uint64 scavengeGeneration;
+ TransId oldestActiveTransaction;
+ uint64 cycle;
+ uint64 startingActiveMemory;
+ uint64 prunedActiveMemory;
+ uint64 retiredActiveMemory;
+
+ time_t scavengeStart;
+ time_t pruneStop;
+ time_t retireStop;
+
uint64 baseGeneration;
- uint recordsReclaimed;
- uint recordsRemaining;
- uint numberRecords;
- uint versionsRemaining;
- uint64 spaceReclaimed;
+ uint64 scavengeGeneration;
+
+ // Results of Scavenging
+ uint64 recordsPruned;
+ uint64 spacePruned;
+ uint64 recordsRetired;
+ uint64 spaceRetired;
+ uint64 recordsRemaining;
uint64 spaceRemaining;
+
+ // Results of the inventory
+ uint64 totalRecords;
+ uint64 totalRecordSpace;
+ uint64 pruneableRecords;
+ uint64 pruneableSpace;
+ uint64 retireableRecords;
+ uint64 retireableSpace;
+ uint64 unScavengeableRecords;
+ uint64 unScavengeableSpace;
uint64 ageGroups[AGE_GROUPS];
- uint64 overflowSpace;
- uint64 totalSpace;
- uint64 recordSpace;
- bool forced;
+ uint64 veryOldRecords;
+ uint64 veryOldRecordSpace;
- RecordScavenge(Database *db, TransId oldestTransaction, bool wasForced);
- ~RecordScavenge(void);
-
- void inventoryRecord(Record* record);
- uint64 computeThreshold(uint64 target);
- void printRecordMemory(void);
+ bool forced;
};
#endif
=== modified file 'storage/falcon/RecordSection.cpp'
--- a/storage/falcon/RecordSection.cpp 2007-09-20 15:44:25 +0000
+++ b/storage/falcon/RecordSection.cpp 2009-01-08 09:05:26 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
=== modified file 'storage/falcon/RecordSection.h'
--- a/storage/falcon/RecordSection.h 2008-10-16 04:48:40 +0000
+++ b/storage/falcon/RecordSection.h 2009-01-08 09:05:26 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -36,15 +36,15 @@ class RecordSection
public:
virtual bool retireSections(Table * table, int id) = 0;
virtual bool inactive() = 0;
- virtual ~RecordSection();
+ virtual ~RecordSection();
- virtual Record* fetch (int32 id) = 0;
- virtual bool store (Record *record, Record *prior, int32 id, RecordSection **parentPtr) = 0;
- virtual int retireRecords(Table *table, int base, RecordScavenge *recordScavenge) = 0;
- virtual void inventoryRecords(RecordScavenge* recordScavenge) = 0;
- virtual int countActiveRecords() = 0;
- virtual bool anyActiveRecords() = 0;
- virtual int chartActiveRecords(int *chart) = 0;
+ virtual Record* fetch (int32 id) = 0;
+ virtual bool store (Record *record, Record *prior, int32 id, RecordSection **parentPtr) = 0;
+ virtual void pruneRecords (Table *table, int base, RecordScavenge *recordScavenge) = 0;
+ virtual void retireRecords(Table *table, int base, RecordScavenge *recordScavenge) = 0;
+ virtual int countActiveRecords() = 0;
+ virtual bool anyActiveRecords() = 0;
+ virtual int chartActiveRecords(int *chart) = 0;
int32 base;
};
=== modified file 'storage/falcon/RecordVersion.cpp'
--- a/storage/falcon/RecordVersion.cpp 2008-11-07 01:09:04 +0000
+++ b/storage/falcon/RecordVersion.cpp 2009-02-03 02:53:42 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -180,84 +180,67 @@ void RecordVersion::commit()
transaction = NULL;
}
-// Scavenge record versions by the scavenger thread. Return true if the
-// record or any prior version of the record is a scavenge candidate.
+// Return true if this record has been committed before a certain transactionId
-bool RecordVersion::scavenge(RecordScavenge *recordScavenge, LockType lockType)
+bool RecordVersion::committedBefore(TransId transId)
{
- // Scavenge criteria:
- //
- // 1. Use count == 1 AND
- // 2. Record Version is older than the record version that was visible
- // to the oldest active transaction AND
- // 3. Either the record generation is older than the current generation
- // OR the scavenge is forced
- // OR there is no record data associated with the record version.
-
- if ( useCount == 1
- && !transaction
- && transactionId < recordScavenge->transactionId
- && (!hasRecord(false)
- || generation <= recordScavenge->scavengeGeneration
- || recordScavenge->forced))
+ // The transaction pointer in this record can disapear at any time due to
+ // another call to Transaction::commitRecords(). So read it locally
+
+ Transaction *transactionPtr = transaction;
+ if (transactionPtr)
+ return transactionPtr->committedBefore(transId);
+
+ // If the transaction Pointer is null, then this record is committed.
+ // All we have is the starting point for these transactions.
+ return (transactionId < transId);
+}
+
+
+bool RecordVersion::retire(RecordScavenge *recordScavenge)
+{
+ bool neededByAnyActiveTrans = true;
+ if ( !transaction
+ || transaction->committedBefore(recordScavenge->oldestActiveTransaction))
+ neededByAnyActiveTrans = false;
+
+ if ( generation <= recordScavenge->scavengeGeneration
+ && useCount == 1
+ && !priorVersion
+ && !neededByAnyActiveTrans)
{
-
- // Expunge all record versions prior to this
+ recordScavenge->recordsRetired++;
+ recordScavenge->spaceRetired += getMemUsage();
+#ifdef CHECK_RECORD_ACTIVITY
+ active = false;
+#endif
+ if (state == recDeleted)
+ expungeRecord(); // Allow this record number to be reused
- if (priorVersion && lockType == Exclusive)
- format->table->expungeRecordVersions(this, recordScavenge);
-
+ release();
return true;
}
- else
- {
- // Signal Table::cleanupRecords() that there is work to do
-
- format->table->activeVersions = true;
- // Scavenge criteria not met for this base record, so check prior versions.
-
- if (priorVersion && (recordScavenge->forced || recordScavenge->scavengeGeneration != UNDEFINED))
- {
-
- // Scavenge prior record versions only if we have an exclusive lock on
- // the record leaf. Return 'false' because the base record is not scavengable.
-
- if (lockType == Exclusive)
- priorVersion->scavenge(recordScavenge, lockType);
- else
-
- // Scan the prior record versions and return 'true' if a scavenge
- // candidate is found.
-
- for (Record *rec = priorVersion; rec; rec = rec->getPriorVersion())
- if ( rec->useCount == 1
- && !rec->getTransaction()
- && rec->getTransactionId() < recordScavenge->transactionId
- && (!rec->hasRecord(false)
- || rec->generation <= recordScavenge->scavengeGeneration))
- return true;
- }
- }
- return false;
+ return false;
}
// Scavenge record versions replaced within a savepoint.
-void RecordVersion::scavenge(TransId targetTransactionId, int oldestActiveSavePointId)
+void RecordVersion::scavengeSavepoint(TransId targetTransactionId, int oldestActiveSavePointId)
{
if (!priorVersion)
return;
- Sync syncPrior(getSyncPrior(), "RecordVersion::scavenge");
+ Sync syncPrior(getSyncPrior(), "RecordVersion::scavengeSavepoint");
syncPrior.lock(Shared);
Record *rec = priorVersion;
Record *ptr = NULL;
-
+
// Remove prior record versions assigned to the savepoint being released
- for (; rec && rec->getTransactionId() == targetTransactionId && rec->getSavePointId() >= oldestActiveSavePointId;
+ for (; ( rec && rec->getTransactionId() == targetTransactionId
+ && rec->getSavePointId() >= oldestActiveSavePointId);
rec = rec->getPriorVersion())
{
ptr = rec;
@@ -320,9 +303,18 @@ bool RecordVersion::isSuperceded()
Record* RecordVersion::clearPriorVersion(void)
{
+ Sync syncPrior(getSyncPrior(), "RecordVersion::clearPriorVersion");
+ syncPrior.lock(Exclusive);
+
Record * prior = priorVersion;
- priorVersion = NULL;
- return prior;
+
+ if (prior && prior->useCount == 1)
+ {
+ priorVersion = NULL;
+ return prior;
+ }
+
+ return NULL;
}
void RecordVersion::setPriorVersion(Record *oldVersion)
@@ -367,7 +359,7 @@ int RecordVersion::thaw()
// Nothing to do if the record is no longer chilled
if (state != recChilled)
- return size;
+ return getDataMemUsage();
// First, try to thaw from the serial log. If transaction->writePending is
// true, then the record data can be restored from the serial log. If writePending
=== modified file 'storage/falcon/RecordVersion.h'
--- a/storage/falcon/RecordVersion.h 2008-10-29 23:25:13 +0000
+++ b/storage/falcon/RecordVersion.h 2009-01-14 22:33:44 +0000
@@ -42,8 +42,8 @@ public:
virtual void setSuperceded (bool flag);
virtual Record* getPriorVersion();
virtual Record* getGCPriorVersion(void);
- virtual bool scavenge(RecordScavenge *recordScavenge, LockType lockType);
- virtual void scavenge(TransId targetTransactionId, int oldestActiveSavePoint);
+ virtual bool retire(RecordScavenge *recordScavenge);
+ virtual void scavengeSavepoint(TransId targetTransactionId, int oldestActiveSavePoint);
virtual bool isVersion();
virtual void rollback(Transaction *transaction);
virtual Record* fetchVersion (Transaction * trans);
@@ -59,6 +59,7 @@ public:
virtual void serialize(Serialize* stream);
void commit();
+ bool committedBefore(TransId);
protected:
virtual ~RecordVersion();
=== modified file 'storage/falcon/SRLCommit.cpp'
--- a/storage/falcon/SRLCommit.cpp 2007-10-04 20:45:34 +0000
+++ b/storage/falcon/SRLCommit.cpp 2008-12-19 18:45:32 +0000
@@ -46,18 +46,16 @@ void SRLCommit::append(Transaction *tran
transaction->addRef();
START_RECORD(srlCommit, "SRLCommit::append");
putInt(transaction->transactionId);
- //uint64 commitBlockNumber = log->nextBlockNumber;
uint64 commitBlockNumber = log->getWriteBlockNumber();
SerialLogTransaction *srlTransaction = log->getTransaction(transaction->transactionId);
-
+ srlTransaction->setTransaction(transaction);
+
+ // Flush transactions with changes immediately for durability
+
if (transaction->hasUpdates)
log->flush(false, commitBlockNumber, &sync);
else
sync.unlock();
-
- srlTransaction->setTransaction(transaction);
- srlTransaction->setState(sltCommitted);
- wakeup();
}
void SRLCommit::read()
=== modified file 'storage/falcon/SRLCreateTableSpace.cpp'
--- a/storage/falcon/SRLCreateTableSpace.cpp 2008-11-14 02:30:11 +0000
+++ b/storage/falcon/SRLCreateTableSpace.cpp 2009-01-28 23:57:54 +0000
@@ -90,9 +90,12 @@ void SRLCreateTableSpace::pass1()
void SRLCreateTableSpace::pass2()
{
- TableSpaceInit tsInit;
- tsInit.comment = comment;
- log->database->tableSpaceManager->redoCreateTableSpace(tableSpaceId, nameLength, name, filenameLength, filename, type, &tsInit);
+ if (control->isPostFlush())
+ {
+ TableSpaceInit tsInit;
+ tsInit.comment = comment;
+ log->database->tableSpaceManager->redoCreateTableSpace(tableSpaceId, nameLength, name, filenameLength, filename, type, &tsInit);
+ }
}
void SRLCreateTableSpace::commit()
=== added file 'storage/falcon/SRLInventoryPage.cpp'
--- a/storage/falcon/SRLInventoryPage.cpp 1970-01-01 00:00:00 +0000
+++ b/storage/falcon/SRLInventoryPage.cpp 2009-01-28 23:57:54 +0000
@@ -0,0 +1,63 @@
+/* Copyright 2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "Engine.h"
+#include "SRLInventoryPage.h"
+#include "PageInventoryPage.h"
+#include "SerialLogControl.h"
+#include "Dbb.h"
+#include "BDB.h"
+#include "Page.h"
+#include "Log.h"
+
+// Recreate inventory page
+void SRLInventoryPage::pass2()
+{
+ if (control->isPostFlush())
+ {
+ Bdb* bdb = PageInventoryPage::createInventoryPage(log->getDbb(tableSpaceId), pageNumber, NO_TRANSACTION);
+ bdb->mark(NO_TRANSACTION);
+ bdb->release(REL_HISTORY);
+ }
+}
+
+void SRLInventoryPage::print()
+{
+ logPrint("InventoryPage tableSpaceId %d, page %d \n", tableSpaceId, pageNumber);
+}
+
+void SRLInventoryPage::read()
+{
+ tableSpaceId = getInt();
+ pageNumber = getInt();
+}
+
+void SRLInventoryPage::append(Dbb *dbb, int32 pageNumber)
+{
+ START_RECORD(srlInventoryPage, "SRLInventoryPage::append");
+ putInt(dbb->tableSpaceId);
+ putInt(pageNumber);
+ sync.unlock();
+}
+
+SRLInventoryPage::SRLInventoryPage()
+{
+}
+
+SRLInventoryPage::~SRLInventoryPage()
+{
+}
+
=== added file 'storage/falcon/SRLInventoryPage.h'
--- a/storage/falcon/SRLInventoryPage.h 1970-01-01 00:00:00 +0000
+++ b/storage/falcon/SRLInventoryPage.h 2009-01-27 00:03:16 +0000
@@ -0,0 +1,35 @@
+/* Copyright 2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef SRL_INVENTORY_PAGE_H
+#define SRL_INVENTORY_PAGE_H
+
+#include "SerialLogRecord.h"
+#include "Dbb.h"
+
+class SRLInventoryPage : public SerialLogRecord
+{
+public:
+ virtual void pass2();
+ void print();
+ virtual void read();
+ void append(Dbb *dbb, int32 pageNumber);
+ SRLInventoryPage();
+ virtual ~SRLInventoryPage();
+ int32 pageNumber;
+
+};
+#endif
=== modified file 'storage/falcon/SRLPrepare.cpp'
--- a/storage/falcon/SRLPrepare.cpp 2008-07-24 08:45:03 +0000
+++ b/storage/falcon/SRLPrepare.cpp 2008-12-19 18:45:32 +0000
@@ -47,15 +47,12 @@ void SRLPrepare::append(TransId transId,
putInt(transId);
putInt(xidLength);
putData(xidLength, xid);
- SerialLogTransaction *transaction = log->getTransaction(transId);
+ SerialLogTransaction *srlTransaction = log->getTransaction(transId);
log->flush(false, log->nextBlockNumber, &sync);
- if (transaction)
- transaction->setState(sltPrepared);
-
- if (transaction)
- wakeup();
+ if (srlTransaction)
+ srlTransaction->setState(sltPrepared);
}
void SRLPrepare::read()
=== modified file 'storage/falcon/SRLRollback.cpp'
--- a/storage/falcon/SRLRollback.cpp 2008-07-24 08:45:03 +0000
+++ b/storage/falcon/SRLRollback.cpp 2008-12-19 18:45:32 +0000
@@ -38,23 +38,16 @@ SRLRollback::~SRLRollback()
}
-void SRLRollback::append(TransId transId, bool updateTransaction)
+void SRLRollback::append(Transaction *transaction)
{
START_RECORD(srlRollback, "SRLRollback::append");
- putInt(transId);
+ putInt(transaction->transactionId);
uint64 commitBlockNumber = log->nextBlockNumber;
- SerialLogTransaction *transaction = log->findTransaction(transId);
- if (updateTransaction)
+ if (transaction->hasUpdates)
log->flush(false, commitBlockNumber, &sync);
else
sync.unlock();
-
- if (transaction)
- {
- transaction->setState(sltRolledBack);
- wakeup();
- }
}
void SRLRollback::read()
=== modified file 'storage/falcon/SRLRollback.h'
--- a/storage/falcon/SRLRollback.h 2007-09-20 15:44:25 +0000
+++ b/storage/falcon/SRLRollback.h 2008-12-19 18:45:32 +0000
@@ -33,7 +33,7 @@ public:
virtual void print();
virtual void pass1();
virtual void read();
- void append(TransId transId, bool updateTransaction);
+ void append(Transaction *transaction);
SRLRollback();
virtual ~SRLRollback();
=== modified file 'storage/falcon/SRLUpdateIndex.cpp'
--- a/storage/falcon/SRLUpdateIndex.cpp 2008-11-14 15:38:44 +0000
+++ b/storage/falcon/SRLUpdateIndex.cpp 2009-01-22 18:40:02 +0000
@@ -40,21 +40,28 @@ SRLUpdateIndex::~SRLUpdateIndex(void)
void SRLUpdateIndex::append(DeferredIndex* deferredIndex)
{
+ // To ensure coordination with a concurrent SRLDeleteIndex, grab syncIndexes
+ // before getting the index id from the DeferredIndex.
+
+ Sync syncIndexes(&log->syncIndexes, "SRLUpdateIndex::append(Indexes)");
+ syncIndexes.lock(Shared);
+
Sync syncDI(&deferredIndex->syncObject, "SRLUpdateIndex::append(DI)");
syncDI.lock(Shared);
- if (!deferredIndex->index)
- return;
+ Index* index = deferredIndex->index;
- uint indexId = deferredIndex->index->indexId;
- int idxVersion = deferredIndex->index->indexVersion;
- int tableSpaceId = deferredIndex->index->dbb->tableSpaceId;
+ // A null index or indexId == -1 means that the index has been deleted
+
+ if (!index || index->indexId == -1)
+ return;
+
+ int idxId = index->indexId;
+ int idxVersion = index->indexVersion;
+ int tableSpaceId = index->dbb->tableSpaceId;
syncDI.unlock();
- Sync syncIndexes(&log->syncIndexes, "SRLUpdateIndex::append(Indexes)");
- syncIndexes.lock(Shared);
-
Transaction *transaction = deferredIndex->transaction;
DeferredIndexWalker walker(deferredIndex, NULL);
uint64 virtualOffset = 0;
@@ -70,7 +77,7 @@ void SRLUpdateIndex::append(DeferredInde
if (virtualOffset == 0)
virtualOffset = log->startRecordVirtualOffset;
- log->updateIndexUseVector(indexId, tableSpaceId, 1);
+ log->updateIndexUseVector(idxId, tableSpaceId, 1);
SerialLogTransaction *srlTrans = log->getTransaction(transaction->transactionId);
srlTrans->setTransaction(transaction);
ASSERT(transaction->writePending);
@@ -79,7 +86,7 @@ void SRLUpdateIndex::append(DeferredInde
putInt(tableSpaceId);
putInt(transaction->transactionId);
- putInt(indexId);
+ putInt(idxId);
putInt(idxVersion);
// Initialize the length field, adjust with correct length later.
@@ -105,7 +112,7 @@ void SRLUpdateIndex::append(DeferredInde
}
int len = (int) (log->writePtr - start);
- //printf("SRLUpdateIndex::append tid %d, index %d, length %d, ptr %x (%x)\n", transaction->transactionId, indexId, len, lengthPtr, org);
+ //printf("SRLUpdateIndex::append tid %d, index %d, length %d, ptr %x (%x)\n", transaction->transactionId, idxId, len, lengthPtr, org);
ASSERT(len >= 0);
// Update the length field
=== modified file 'storage/falcon/SRLUpdateRecords.cpp'
--- a/storage/falcon/SRLUpdateRecords.cpp 2008-11-19 17:00:02 +0000
+++ b/storage/falcon/SRLUpdateRecords.cpp 2009-01-21 00:35:50 +0000
@@ -28,6 +28,7 @@
#include "Sync.h"
#include "SerialLogWindow.h"
#include "Format.h"
+#include "SQLError.h"
SRLUpdateRecords::SRLUpdateRecords(void)
{
@@ -37,8 +38,26 @@ SRLUpdateRecords::~SRLUpdateRecords(void
{
}
-void SRLUpdateRecords::chill(Transaction *transaction, RecordVersion *record, uint dataLength)
+bool SRLUpdateRecords::chill(Transaction *transaction, RecordVersion *record, uint dataLength)
{
+ Sync syncPrior(record->getSyncPrior(), "SRLUpdateRecords::chill");
+
+ // Exclusively lock the record chain before chilling the record. Use a 50ms wait to defer
+ // to other tasks accessing the record chain.
+ //
+ // This is a provisional resolution to a syncPrior/syncWrite deadlock that can be triggered
+ // by a low-level thaw on a concurrent thread already holding syncPrior. Such a deadlock
+ // can occur while pruning record versions during during a scavenge.
+
+ try
+ {
+ syncPrior.lock(Exclusive, 50);
+ }
+ catch (...)
+ {
+ return false;
+ }
+
// Record data has been written to the serial log, so release the data
// buffer and set the state accordingly
@@ -55,6 +74,8 @@ void SRLUpdateRecords::chill(Transaction
transaction->totalRecordData -= dataLength;
else
transaction->totalRecordData = 0;
+
+ return true;
}
int SRLUpdateRecords::thaw(RecordVersion *record, bool *thawed)
@@ -200,15 +221,16 @@ void SRLUpdateRecords::append(Transactio
{
int chillBytes = record->getEncodedSize();
- chill(transaction, record, chillBytes);
-
- log->chilledRecords++;
- log->chilledBytes += chillBytes;
+ if (chill(transaction, record, chillBytes))
+ {
+ log->chilledRecords++;
+ log->chilledBytes += chillBytes;
- ASSERT(transaction->thawedRecords > 0);
+ //ASSERT(transaction->thawedRecords > 0);
- if (transaction->thawedRecords)
- transaction->thawedRecords--;
+ if (transaction->thawedRecords)
+ transaction->thawedRecords--;
+ }
}
else
{
@@ -253,9 +275,11 @@ void SRLUpdateRecords::append(Transactio
if (chillRecords && record->state != recDeleted)
{
- chill(transaction, record, stream.totalLength);
- chilledRecordsWindow++;
- chilledBytesWindow += stream.totalLength;
+ if (chill(transaction, record, stream.totalLength))
+ {
+ chilledRecordsWindow++;
+ chilledBytesWindow += stream.totalLength;
+ }
}
} // next record version
=== modified file 'storage/falcon/SRLUpdateRecords.h'
--- a/storage/falcon/SRLUpdateRecords.h 2008-11-14 02:30:11 +0000
+++ b/storage/falcon/SRLUpdateRecords.h 2009-01-17 08:22:44 +0000
@@ -33,7 +33,7 @@ public:
virtual void read(void);
virtual void pass2(void);
void append(Transaction *transaction, RecordVersion *records, bool chillRecords = false);
- void chill(Transaction *transaction, RecordVersion *record, uint dataLength);
+ bool chill(Transaction *transaction, RecordVersion *record, uint dataLength);
int thaw(RecordVersion *record, bool *thawed);
const UCHAR *data;
=== modified file 'storage/falcon/SRLVersion.h'
--- a/storage/falcon/SRLVersion.h 2008-03-28 22:44:36 +0000
+++ b/storage/falcon/SRLVersion.h 2009-01-26 18:13:45 +0000
@@ -42,7 +42,8 @@ static const int srlVersion12 = 12; //
static const int srlVersion13 = 13; // Added savepoint id to SRLUpdateRecords February 14, 2008
static const int srlVersion14 = 14; // Added supernodes logging March 7, 2008
static const int srlVersion15 = 15; // Added tablespace parameters to SRLCreateTableSpace March 27, 2008
-static const int srlCurrentVersion = srlVersion15;
+static const int srlVersion16 = 16; // Added SRLInventoryPage January 26, 2009
+static const int srlCurrentVersion = srlVersion16;
class SRLVersion : public SerialLogRecord
{
=== modified file 'storage/falcon/Scavenger.cpp'
--- a/storage/falcon/Scavenger.cpp 2008-10-16 02:53:35 +0000
+++ b/storage/falcon/Scavenger.cpp 2009-01-08 09:05:26 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -65,7 +65,7 @@ void Scavenger::scavenge()
void Scavenger::execute(Scheduler * scheduler)
{
- scavenge();
+ database->signalScavenger();
getNextEvent();
scheduler->addEvent (this);
}
=== modified file 'storage/falcon/Section.cpp'
--- a/storage/falcon/Section.cpp 2008-06-17 17:41:54 +0000
+++ b/storage/falcon/Section.cpp 2009-02-09 05:01:44 +0000
@@ -69,6 +69,15 @@ static const char THIS_FILE[]=__FILE__;
//////////////////////////////////////////////////////////////////////
+static Bdb* allocSectionPage(Dbb *dbb, int transId, int parentPage, int slot, int sectionId, int sequence, int level)
+{
+ Bdb *newBdb = dbb->allocPage(PAGE_sections, transId);
+
+ if (!dbb->serialLog->recovering && !dbb->noLog)
+ dbb->serialLog->logControl->sectionPage.append(dbb, transId, parentPage, newBdb->pageNumber, slot, sectionId, sequence, level);
+ return newBdb;
+}
+
Section::Section(Dbb *pDbb, int32 id, TransId transId)
{
dbb = pDbb;
@@ -129,7 +138,7 @@ int32 Section::createSection(Dbb * dbb,
}
else
{
- Bdb *sectionBdb = dbb->allocPage(PAGE_sections, transId);
+ Bdb *sectionBdb = allocSectionPage(dbb, transId, sections->pageNumber, slot, id, 0, 0);
BDB_HISTORY(sectionBdb);
int32 sectionPageNumber = sectionBdb->pageNumber;
page = (SectionPage*) sectionBdb->buffer;
@@ -139,10 +148,6 @@ int32 Section::createSection(Dbb * dbb,
sectionsBdb->mark(transId);
sections->pages [slot] = sectionPageNumber;
dbb->nextSection = (sectionSkipped) ? sectionSkipped : (id + 1);
-
- if (!dbb->serialLog->recovering && !dbb->noLog)
- dbb->serialLog->logControl->sectionPage.append(dbb, transId, sectionsBdb->pageNumber, sectionPageNumber, slot, id, 0, 0);
-
sectionsBdb->release(REL_HISTORY);
//Log::debug("Section::createSection: section %d created\n", id);
@@ -164,14 +169,19 @@ void Section::createSection(Dbb *dbb, in
if (sections->pages [slot] == 0)
{
+ // If we're in recovery and slot is empty, something went wrong , page must have
+ // been logged and rebuilt already (every allocation is redone)
+ ASSERT (!(dbb->serialLog && dbb->serialLog->recovering));
+
sectionsBdb->mark(transId);
- Bdb *sectionBdb = dbb->allocPage(PAGE_sections, transId);
+ Bdb *sectionBdb = allocSectionPage(dbb, transId, sectionsBdb->pageNumber, slot, sectionId, sequence, 0);
BDB_HISTORY(sectionBdb);
Log::debug("Section::createSection: recreating section %d, root %d\n",
sectionId, sectionBdb->pageNumber);
sections->pages [slot] = sectionBdb->pageNumber;
SectionPage *page = (SectionPage*) sectionBdb->buffer;
page->section = sectionId;
+
sectionBdb->release(REL_HISTORY);
}
@@ -270,18 +280,15 @@ Bdb* Section::getSectionPage(Dbb *dbb, i
break;
}
- Bdb *newBdb = dbb->allocPage(PAGE_sections, transId);
+ Bdb *newBdb = allocSectionPage(dbb, transId, bdb->pageNumber, slot, page->section, sequence, page->level -1);
BDB_HISTORY(newBdb);
SectionPage *newPage = (SectionPage*) newBdb->buffer;
- int32 newPageNumber = newBdb->pageNumber;
- int sectionId = page->section;
- newPage->section = sectionId;
+ newPage->section = page->section;
newPage->sequence = sequence;
newPage->level = page->level - 1;
bdb->mark(transId);
- page->pages [slot] = newPageNumber;
- int32 parentPage = bdb->pageNumber;
+ page->pages [slot] = newBdb->pageNumber;
bdb->release(REL_HISTORY);
if (newPage->level == 0)
@@ -291,8 +298,6 @@ Bdb* Section::getSectionPage(Dbb *dbb, i
page = newPage;
lockType = Exclusive;
- if (!dbb->serialLog->recovering && !dbb->noLog)
- dbb->serialLog->logControl->sectionPage.append(dbb, transId, parentPage, newPageNumber, slot, sectionId, sequence, page->level - 1);
}
}
}
@@ -1196,39 +1201,29 @@ bool Section::isCleanupRequired()
void Section::redoSectionPage(Dbb *dbb, int32 parentPage, int32 pageNumber, int slot, int sectionId, int sequence, int level)
{
- Bdb *bdb = dbb->fetchPage (parentPage, PAGE_any, Exclusive);
+ Bdb *bdb = dbb->fetchPage (parentPage, PAGE_sections, Exclusive);
BDB_HISTORY(bdb);
SectionPage *page = (SectionPage*) bdb->buffer;
- // Unless parent page is already leaf, probe and if necessary rebuild section page
+ // If page number != 0, we are creating a new section page
+ // Otherwise, the log record comes from deleteSection and
+ // we just need to clear the slot in the parent page.
- //if (pageNumber && (page->level > 0 || parentPage == SECTION_ROOT))
- if (pageNumber && (page->level > 0 || page->section == -1))
+ if (pageNumber != 0)
{
Bdb *sectionBdb = dbb->fakePage(pageNumber, PAGE_any, 0);
BDB_HISTORY(bdb);
SectionPage *sectionPage = (SectionPage*) sectionBdb->buffer;
-
- if (!dbb->trialRead(sectionBdb) ||
- sectionPage->pageType != PAGE_sections ||
- sectionPage->section != sectionId ||
- sectionPage->sequence != sequence ||
- sectionPage->level != level)
- {
- memset(sectionPage, 0, dbb->pageSize);
- //sectionPage->pageType = PAGE_sections;
- sectionBdb->setPageHeader(PAGE_sections);
- sectionPage->section = sectionId;
- sectionPage->sequence = sequence;
- sectionPage->level = level;
- }
+ memset(sectionPage, 0, dbb->pageSize);
+ sectionBdb->setPageHeader(PAGE_sections);
+ sectionPage->section = sectionId;
+ sectionPage->sequence = sequence;
+ sectionPage->level = level;
PageInventoryPage::markPageInUse(dbb, pageNumber, NO_TRANSACTION);
sectionBdb->release(REL_HISTORY);
}
- // Now try to store it in the right place
-
if (page->pages[slot] != pageNumber)
{
bdb->mark(NO_TRANSACTION);
@@ -1243,33 +1238,9 @@ int32 Section::getSectionRoot()
Bdb *bdb = getSectionPage(dbb, SECTION_ROOT, sectionId / dbb->pagesPerSection, Shared, NO_TRANSACTION);
BDB_HISTORY(bdb);
SectionPage *sectionPage = (SectionPage*) bdb->buffer;
- root = sectionPage->pages[sectionId % dbb->pagesPerSection];
+ int slot = sectionId % dbb->pagesPerSection;
+ root = sectionPage->pages[slot];
bdb->release(REL_HISTORY);
-
- if (root == 0)
- {
- if (!dbb->serialLog->recovering)
- throw SQLError(DATABASE_DAMAGED, "Missing section root for section %d/%d\n", sectionId, dbb->tableSpaceId);
-
- // Missing root page -- make a new one
-
- Bdb *sectionBdb = dbb->allocPage(PAGE_sections, NO_TRANSACTION);
- BDB_HISTORY(sectionBdb);
- root = sectionBdb->pageNumber;
- SectionPage *page = (SectionPage*) sectionBdb->buffer;
- page->section = sectionId;
- sectionBdb->release(REL_HISTORY);
-
- // Register new root page
-
- bdb = getSectionPage(dbb, SECTION_ROOT, sectionId / dbb->pagesPerSection, Exclusive, NO_TRANSACTION);
- BDB_HISTORY(bdb);
- sectionPage = (SectionPage*) bdb->buffer;
- sectionPage->pages[sectionId % dbb->pagesPerSection] = root;
- bdb->release(REL_HISTORY);
- }
-
-
return root;
}
@@ -1460,7 +1431,7 @@ void Section::redoBlobUpdate(Dbb* dbb, i
if (page->maxLine <= locatorLine)
page->maxLine = locatorLine + 1;
- page->setIndexSlot(locatorLine, dataPage, dataLine, dbb->pageSize);
+ page->setIndexSlot(locatorLine, dataPage, dataLine, DATA_PAGE_MAX_AVAILABLE_SPACE(dbb->pageSize));
bdb->release(REL_HISTORY);
}
@@ -1494,7 +1465,7 @@ void Section::redoBlobDelete(Dbb* dbb, i
BDB_HISTORY(bdb);
bdb->mark(NO_TRANSACTION);
RecordLocatorPage *page = (RecordLocatorPage*) bdb->buffer;
- page->setIndexSlot(locatorLine, 0, 0, dbb->pageSize);
+ page->setIndexSlot(locatorLine, 0, 0, DATA_PAGE_MAX_AVAILABLE_SPACE(dbb->pageSize));
bdb->release(REL_HISTORY);
}
=== modified file 'storage/falcon/SerialLog.cpp'
--- a/storage/falcon/SerialLog.cpp 2008-11-20 17:05:50 +0000
+++ b/storage/falcon/SerialLog.cpp 2009-02-05 05:34:42 +0000
@@ -51,6 +51,7 @@ static const char THIS_FILE[]=__FILE__;
#endif
static const int TRACE_PAGE = 0;
+static const int RECORD_MAX = 100000;
extern uint falcon_gopher_threads;
extern uint64 falcon_serial_log_file_size;
@@ -118,8 +119,10 @@ SerialLog::SerialLog(Database *db, JStri
blocking = false;
writeError = false;
windowBuffers = MAX(database->configuration->serialLogWindows, SRL_MIN_WINDOWS);
- tableSpaceInfo = NULL;
+
memset(tableSpaces, 0, sizeof(tableSpaces));
+ tableSpaceInfo = NULL;
+
syncWrite.setName("SerialLog::syncWrite");
syncSections.setName("SerialLog::syncSections");
syncIndexes.setName("SerialLog::syncIndexes");
@@ -284,9 +287,9 @@ void SerialLog::recover()
SerialLogBlock *recoveryBlock = recoveryWindow->firstBlock();
recoveryBlockNumber = recoveryBlock->blockNumber;
SerialLogBlock *lastBlock = findLastBlock(recoveryWindow);
- Log::log("first recovery block is " I64FORMAT "\n",
+ Log::log("\nFirst recovery block is " I64FORMAT "\n",
(otherWindow) ? otherWindow->firstBlock()->blockNumber : recoveryBlockNumber);
- Log::log("last recovery block is " I64FORMAT "\n", lastBlock->blockNumber);
+ Log::log("Last recovery block is " I64FORMAT "\n", lastBlock->blockNumber);
if (otherWindow)
{
@@ -306,7 +309,7 @@ void SerialLog::recover()
if (readBlockNumber == 0)
readBlockNumber = lastBlock->blockNumber;
- Log::log("recovery read block is " I64FORMAT "\n", readBlockNumber);
+ Log::log("Recovery read block is " I64FORMAT "\n", readBlockNumber);
nextBlockNumber = lastBlock->blockNumber + 1;
lastWindow->deactivateWindow();
SerialLogWindow *window = findWindowGivenBlock(readBlockNumber);
@@ -328,11 +331,20 @@ void SerialLog::recover()
recoveryIndexes = new RecoveryObjects(this);
recoveryPhase = 1; // Take Inventory (serialLogTransactions, recoveryObject states, last checkpoint)
- // Make a first pass finding records, transactions, etc.
+ Log::log("Recovery phase 1...\n");
+
+ unsigned long int recordCount = 0;
while ( (record = control.nextRecord()) )
+ {
+ if (++recordCount % RECORD_MAX == 0)
+ Log::log("Processed: %8ld\n", recordCount);
+
record->pass1();
+ }
+ Log::log("Processed: %8ld\n", recordCount);
+
//control.debug = false;
pass1 = false;
control.setWindow(window, block, 0);
@@ -344,9 +356,19 @@ void SerialLog::recover()
// Next, make a second pass to reallocate any necessary pages
+ Log::log("Recovery phase 2...\n");
+ recordCount = 0;
+
while ( (record = control.nextRecord()) )
+ {
+ if (++recordCount % RECORD_MAX == 0)
+ Log::log("Processed: %8ld\n", recordCount);
+
if (!isTableSpaceDropped(record->tableSpaceId) || record->type == srlDropTableSpace)
record->pass2();
+ }
+
+ Log::log("Processed: %8ld\n", recordCount);
recoveryPages->reset();
recoveryIndexes->reset();
@@ -363,10 +385,19 @@ void SerialLog::recover()
// Make a third pass doing things
+ Log::log("Recovery phase 3...\n");
+ recordCount = 0;
+
while ( (record = control.nextRecord()) )
+ {
+ if (++recordCount % RECORD_MAX == 0)
+ Log::log("Processed: %8ld\n", recordCount);
+
if (!isTableSpaceDropped(record->tableSpaceId))
record->redo();
-
+ }
+
+ Log::log("Processed: %8ld\n", recordCount);
for (SerialLogTransaction *action, **ptr = &running.first; (action = *ptr);)
if (action->completedRecovery())
@@ -1504,7 +1535,10 @@ Dbb* SerialLog::findDbb(int tableSpaceId
TableSpaceInfo* SerialLog::getTableSpaceInfo(int tableSpaceId)
{
TableSpaceInfo *info;
- int slot = tableSpaceId %SLT_HASH_SIZE;
+
+ // Map reserved tablespace ids from the end of the hash table
+
+ int slot = (tableSpaceId >= 0) ? (tableSpaceId % SLT_HASH_SIZE) : (SLT_HASH_SIZE + tableSpaceId);
for (info = tableSpaces[slot]; info; info = info->collision)
if (info->tableSpaceId == tableSpaceId)
=== modified file 'storage/falcon/SerialLogControl.cpp'
--- a/storage/falcon/SerialLogControl.cpp 2008-11-11 22:33:27 +0000
+++ b/storage/falcon/SerialLogControl.cpp 2009-01-26 18:13:45 +0000
@@ -171,7 +171,10 @@ SerialLogRecord* SerialLogControl::getRe
case srlSavepointRollback:
return &savepointRollback;
-
+
+ case srlInventoryPage:
+ return &inventoryPage;
+
default:
ASSERT(false);
}
=== modified file 'storage/falcon/SerialLogControl.h'
--- a/storage/falcon/SerialLogControl.h 2008-02-14 21:06:10 +0000
+++ b/storage/falcon/SerialLogControl.h 2009-01-26 18:13:45 +0000
@@ -62,6 +62,7 @@
#include "SRLUpdateBlob.h"
#include "SRLSession.h"
#include "SRLSavepointRollback.h"
+#include "SRLInventoryPage.h"
#define LOW_BYTE_FLAG 0x80
@@ -137,6 +138,7 @@ public:
SRLUpdateBlob smallBlob;
SRLSession session;
SRLSavepointRollback savepointRollback;
+ SRLInventoryPage inventoryPage;
};
#endif // !defined(AFX_SERIALLOGCONTROL_H__77229761_E146_4AE4_8BBC_2114F6A0FC93__INCLUDED_)
=== modified file 'storage/falcon/SerialLogRecord.cpp'
--- a/storage/falcon/SerialLogRecord.cpp 2008-11-20 17:05:50 +0000
+++ b/storage/falcon/SerialLogRecord.cpp 2008-12-19 18:45:32 +0000
@@ -226,11 +226,6 @@ void SerialLogRecord::startRecord()
log->startRecord();
}
-void SerialLogRecord::wakeup()
-{
- log->wakeup();
-}
-
void SerialLogRecord::putStream(Stream *stream)
{
putInt(stream->totalLength);
=== modified file 'storage/falcon/SerialLogRecord.h'
--- a/storage/falcon/SerialLogRecord.h 2008-11-14 02:30:11 +0000
+++ b/storage/falcon/SerialLogRecord.h 2009-01-26 18:13:45 +0000
@@ -71,7 +71,8 @@ static const int srlBlobDelete = 34;
static const int srlSmallBlob = 35;
static const int srlSession = 36;
static const int srlSavepointRollback = 37;
-static const int srlMax = 38;
+static const int srlInventoryPage = 38;
+static const int srlMax = 39;
class SerialLog;
@@ -98,7 +99,6 @@ public:
int getInt(const UCHAR** ptr);
const UCHAR* getData(int32 length);
void putStream (Stream *stream);
- void wakeup();
void startRecord();
void putData(uint32 length, const UCHAR *data);
void putInt(int32 number);
=== modified file 'storage/falcon/SparseArray.h'
--- a/storage/falcon/SparseArray.h 2007-09-20 15:44:25 +0000
+++ b/storage/falcon/SparseArray.h 2009-02-06 21:08:57 +0000
@@ -122,7 +122,7 @@ public:
if (!nextVector)
{
- if (level == 1)
+ if (lvl == 1)
{
nextVector = (void**) new T [width];
memset(nextVector, 0, sizeof(T) * width);
=== modified file 'storage/falcon/Statement.cpp'
--- a/storage/falcon/Statement.cpp 2008-09-03 21:49:18 +0000
+++ b/storage/falcon/Statement.cpp 2009-01-15 20:29:54 +0000
@@ -332,15 +332,19 @@ void Statement::createIndex(Syntax * syn
table->deleteIndex(oldIndex, transaction);
}
+ // If not adding system tables, create and populate the index
+
if (!database->formatting)
{
Transaction *sysTransaction = database->getSystemTransaction();
index->create(sysTransaction);
index->save();
database->commitSystemTransaction();
+
sysTransaction = database->getSystemTransaction();
table->populateIndex (index, sysTransaction);
database->commitSystemTransaction();
+
database->invalidateCompiledStatements (table);
//database->flush();
}
@@ -1301,13 +1305,32 @@ void Statement::upgradeTable(Syntax * sy
END_FOR;
FOR_OBJECTS (Field*, field, &changedFields)
- field->update();
+ field->update(); // does commitSystemTransaction
END_FOR;
+ if (!transaction)
+ transaction = database->getSystemTransaction();
+
FOR_OBJECTS (Index*, index, &newIndexes)
- index->create(transaction);
- index->save();
- table->populateIndex (index, transaction);
+ if (!database->formatting)
+ {
+ // Commit and populate the index in separate transactions
+
+ Transaction *sysTransaction = database->getSystemTransaction();
+ index->create(sysTransaction);
+ index->save();
+ database->commitSystemTransaction();
+
+ sysTransaction = database->getSystemTransaction();
+ table->populateIndex (index, sysTransaction);
+ database->commitSystemTransaction();
+ }
+ else
+ {
+ index->create(transaction);
+ index->save();
+ table->populateIndex (index, transaction);
+ }
END_FOR;
for (field = table->fields; field; field = field->next)
=== modified file 'storage/falcon/StorageDatabase.cpp'
--- a/storage/falcon/StorageDatabase.cpp 2008-10-16 02:53:35 +0000
+++ b/storage/falcon/StorageDatabase.cpp 2009-01-20 08:09:02 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -419,7 +419,7 @@ int StorageDatabase::nextIndexed(Storage
if (recordNumber < 0)
return StorageErrorRecordNotFound;
-
+
candidate = table->fetch(recordNumber);
++recordNumber;
@@ -491,21 +491,7 @@ int StorageDatabase::nextIndexed(Storage
return record->recordNumber;
}
-/*
-RecordVersion* StorageDatabase::lockRecord(StorageConnection* storageConnection, Table *table, Record* record)
-{
- try
- {
- return table->lockRecord(record, storageConnection->connection->getTransaction());
- }
- catch (SQLException& exception)
- {
- storageConnection->setErrorText(&exception);
-
- return NULL;
- }
-}
-*/
+
int StorageDatabase::savepointSet(Connection* connection)
{
Transaction *transaction = connection->getTransaction();
@@ -961,10 +947,10 @@ void StorageDatabase::validateCache(void
int StorageDatabase::getSegmentValue(StorageSegment* segment, const UCHAR* ptr, Value* value, Field *field)
{
int length = segment->length;
-
- switch (segment->type)
+
+ switch (segment->keyFormat)
{
- case HA_KEYTYPE_LONG_INT:
+ case KEY_FORMAT_LONG_INT:
{
int32 temp = (int32)
(((int32) ((UCHAR) ptr[0])) +
@@ -975,7 +961,7 @@ int StorageDatabase::getSegmentValue(Sto
}
break;
- case HA_KEYTYPE_SHORT_INT:
+ case KEY_FORMAT_SHORT_INT:
{
short temp = (int16)
(((short) ((UCHAR) ptr[0])) +
@@ -984,8 +970,8 @@ int StorageDatabase::getSegmentValue(Sto
}
break;
- case HA_KEYTYPE_ULONGLONG:
- case HA_KEYTYPE_LONGLONG:
+ case KEY_FORMAT_ULONGLONG:
+ case KEY_FORMAT_LONGLONG:
{
int64 temp = (int64)
((uint64)(((uint32) ((UCHAR) ptr[0])) +
@@ -1001,7 +987,7 @@ int StorageDatabase::getSegmentValue(Sto
}
break;
- case HA_KEYTYPE_FLOAT:
+ case KEY_FORMAT_FLOAT:
{
float temp;
#ifdef _BIG_ENDIAN
@@ -1016,7 +1002,7 @@ int StorageDatabase::getSegmentValue(Sto
}
break;
- case HA_KEYTYPE_DOUBLE:
+ case KEY_FORMAT_DOUBLE:
{
double temp;
#ifdef _BIG_ENDIAN
@@ -1034,11 +1020,9 @@ int StorageDatabase::getSegmentValue(Sto
value->setValue(temp);
}
break;
-
- case HA_KEYTYPE_VARBINARY1:
- case HA_KEYTYPE_VARBINARY2:
- case HA_KEYTYPE_VARTEXT1:
- case HA_KEYTYPE_VARTEXT2:
+
+ case KEY_FORMAT_VARBINARY:
+ case KEY_FORMAT_VARTEXT:
{
unsigned short len = (unsigned short)
(((short) ((UCHAR) ptr[0])) +
@@ -1047,45 +1031,32 @@ int StorageDatabase::getSegmentValue(Sto
length += 2;
}
break;
-
- case HA_KEYTYPE_BINARY:
- if (field->isString())
- value->setString(length, (const char*) ptr, false);
- else if (segment->isUnsigned)
- {
- int64 number = 0;
-
- for (int n = 0; n < length; ++n)
- number = number << 8 | *ptr++;
-
- value->setValue(number);
- }
- else if (field->precision < 19 && field->scale == 0)
- {
- int64 number = (signed char) (*ptr++ ^ 0x80);
-
- for (int n = 1; n < length; ++n)
- number = (number << 8) | *ptr++;
-
- if (number < 0)
- ++number;
-
- value->setValue(number);
- }
- else
- {
- BigInt bigInt;
- ScaledBinary::getBigIntFromBinaryDecimal((const char*) ptr, field->precision, field->scale, &bigInt);
- value->setValue(&bigInt);
- }
+ case KEY_FORMAT_TEXT:
+ case KEY_FORMAT_BINARY_STRING:
+ value->setString(length, (const char*) ptr, false);
break;
+
+ case KEY_FORMAT_BINARY_NEWDECIMAL:
+ {
+ BigInt bigInt;
+ ScaledBinary::getBigIntFromBinaryDecimal((const char*)
+ ptr, field->precision, field->scale, &bigInt);
+ value->setValue(&bigInt);
+ }
+ break;
+ case KEY_FORMAT_BINARY_INTEGER:
+ {
+ int64 number = 0;
- case HA_KEYTYPE_TEXT:
- value->setString(length, (const char*) ptr, false);
+ for (int n = 0; n < length; ++n)
+ number = number << 8 | *ptr++;
+
+ value->setValue(number);
+ }
break;
-
- case HA_KEYTYPE_ULONG_INT:
+
+ case KEY_FORMAT_ULONG_INT:
{
uint32 temp = (uint32)
(((uint32) ((UCHAR) ptr[0])) +
@@ -1093,18 +1064,27 @@ int StorageDatabase::getSegmentValue(Sto
(((uint32) ((UCHAR) ptr[2]) << 16)) +
(((uint32) ((UCHAR) ptr[3]) << 24)));
- if (field && field->type == Timestamp)
- value->setValue((int64) temp * 1000);
- else
value->setValue((int64) temp);
}
break;
+
+ case KEY_FORMAT_TIMESTAMP:
+ {
+ uint32 temp = (uint32)
+ (((uint32) ((UCHAR) ptr[0])) +
+ (((uint32) ((UCHAR) ptr[1]) << 8)) +
+ (((uint32) ((UCHAR) ptr[2]) << 16)) +
+ (((uint32) ((UCHAR) ptr[3]) << 24)));
+
+ value->setValue((int64) temp * 1000);
+ }
+ break;
- case HA_KEYTYPE_INT8:
+ case KEY_FORMAT_INT8:
value->setValue(*(signed char*) ptr);
break;
- case HA_KEYTYPE_USHORT_INT:
+ case KEY_FORMAT_USHORT_INT:
{
unsigned short temp = (unsigned short)
(((uint16) ((UCHAR) ptr[0])) +
@@ -1113,7 +1093,7 @@ int StorageDatabase::getSegmentValue(Sto
}
break;
- case HA_KEYTYPE_UINT24:
+ case KEY_FORMAT_UINT24:
{
uint32 temp = (uint32)
(((uint32) ((UCHAR) ptr[0])) +
@@ -1123,7 +1103,7 @@ int StorageDatabase::getSegmentValue(Sto
}
break;
- case HA_KEYTYPE_INT24:
+ case KEY_FORMAT_INT24:
{
int32 temp = (int32)
((((UCHAR) ptr[2]) & 128) ?
=== modified file 'storage/falcon/StorageDatabase.h'
--- a/storage/falcon/StorageDatabase.h 2008-10-16 02:53:35 +0000
+++ b/storage/falcon/StorageDatabase.h 2009-01-07 08:12:08 +0000
@@ -81,7 +81,6 @@ public:
int nextIndexed(StorageTable *storageTable, void* recordBitmap, int recordNumber, bool lockForUpdate);
int nextIndexed(StorageTable* storageTable, IndexWalker* indexWalker, bool lockForUpdate);
int fetch(StorageConnection* storageConnection, StorageTable* storageTable, int recordNumber, bool lockForUpdate);
-// RecordVersion* lockRecord(StorageConnection* storageConnection, Table *table, Record* record);
int updateRow(StorageConnection* storageConnection, Table* table, Record *oldRecord, Stream* stream);
int getSegmentValue(StorageSegment* segment, const UCHAR* ptr, Value* value, Field *field);
=== modified file 'storage/falcon/StorageHandler.cpp'
--- a/storage/falcon/StorageHandler.cpp 2008-11-13 13:27:13 +0000
+++ b/storage/falcon/StorageHandler.cpp 2009-01-27 17:26:16 +0000
@@ -506,7 +506,8 @@ int StorageHandler::createTablespace(con
try
{
- JString cmd = genCreateTableSpace(tableSpaceName, filename, comment);
+ JString tableSpace= JString::upcase(tableSpaceName);
+ JString cmd = genCreateTableSpace(tableSpace, filename, comment);
Sync sync(&dictionarySyncObject, "StorageHandler::createTablespace");
sync.lock(Exclusive);
Statement *statement = dictionaryConnection->createStatement();
@@ -547,8 +548,9 @@ int StorageHandler::deleteTablespace(con
try
{
+ JString tableSpace= JString::upcase(tableSpaceName);
CmdGen gen;
- gen.gen("drop tablespace \"%s\"", tableSpaceName);
+ gen.gen("drop tablespace \"%s\"", (const char*) tableSpace);
Sync sync(&dictionarySyncObject, "StorageHandler::deleteTablespace");
sync.lock(Exclusive);
Statement *statement = dictionaryConnection->createStatement();
@@ -982,7 +984,6 @@ void StorageHandler::initialize(void)
try
{
- defaultDatabase->getOpenConnection();
dictionaryConnection = defaultDatabase->getOpenConnection();
dropTempTables();
dictionaryConnection->commit();
=== modified file 'storage/falcon/StorageParameters.h'
--- a/storage/falcon/StorageParameters.h 2008-10-20 21:28:11 +0000
+++ b/storage/falcon/StorageParameters.h 2009-02-01 09:50:43 +0000
@@ -26,8 +26,8 @@ PARAMETER_UINT(large_blob_threshold, "Th
PARAMETER_UINT(lock_wait_timeout, "Transaction lock time period (seconds)", 0, 50, INT_MAX, 0, NULL)
PARAMETER_UINT(page_size, "The page size used when creating a Falcon tablespace.", 2048, 4096, 32768, 0x0200, NULL)
PARAMETER_UINT(record_chill_threshold, "Bytes of pending record data that is 'frozen' to the Falcon serial log.", 1, 5*1024*1024, 1024*1024*1024, 0, &updateRecordChillThreshold)
-PARAMETER_UINT(record_scavenge_floor, "A percentage of falcon_record_memory_threshold that defines the amount of record data that will remain in the record cache after a scavenge run.", 10, 50, 90, 0x2000, &StorageInterface::updateRecordScavengeFloor)
-PARAMETER_UINT(record_scavenge_threshold, "The percentage of falcon_record_memory_max that will cause the scavenger thread to start scavenging records from the record cache.", 10, 67, 100, 0x2000, &StorageInterface::updateRecordScavengeThreshold)
+PARAMETER_UINT(record_scavenge_floor, "A percentage of falcon_record_memory_threshold that defines the amount of record data that will remain in the record cache after a scavenge run.", 10, 80, 90, 0x2000, &StorageInterface::updateRecordScavengeFloor)
+PARAMETER_UINT(record_scavenge_threshold, "The percentage of falcon_record_memory_max that will cause the scavenger thread to start scavenging records from the record cache.", 10, 90, 100, 0x2000, &StorageInterface::updateRecordScavengeThreshold)
PARAMETER_UINT(serial_log_block_size, "Minimum block size for serial log.", 0, 0, 4096, 0, NULL)
PARAMETER_UINT(serial_log_buffers, "The number of buffers allocated for Falcon serial log.", SRL_MIN_WINDOWS, 20, 1000, 0x0200, NULL)
PARAMETER_UINT(serial_log_priority, "Whether or not serial log has write priority over other writes.", 0, 1, 1, 0, NULL)
=== modified file 'storage/falcon/StorageTable.cpp'
--- a/storage/falcon/StorageTable.cpp 2008-12-04 11:00:12 +0000
+++ b/storage/falcon/StorageTable.cpp 2009-01-15 20:29:54 +0000
@@ -194,11 +194,12 @@ int StorageTable::setCurrentIndex(int in
indexesLocked = true;
}
- if (!(currentIndex = share->getIndex(indexId)))
- {
- clearCurrentIndex();
- return StorageErrorNoIndex;
- }
+ currentIndex = share->getIndex(indexId);
+
+ int ret = checkCurrentIndex();
+
+ if (ret)
+ return ret;
upperBound = lowerBound = NULL;
searchFlags = 0;
@@ -219,6 +220,22 @@ int StorageTable::clearCurrentIndex()
return 0;
}
+int StorageTable::checkCurrentIndex()
+{
+ if (!currentIndex)
+ {
+ clearCurrentIndex();
+
+ // Use a more benign error until the server protects online alter
+ // with a DDL lock.
+
+ // return StorageErrorNoIndex;
+ return StorageErrorRecordNotFound;
+ }
+
+ return 0;
+}
+
int StorageTable::setIndex(StorageIndexDesc* indexDesc)
{
return share->setIndex(indexDesc);
@@ -226,11 +243,10 @@ int StorageTable::setIndex(StorageIndexD
int StorageTable::indexScan(int indexOrder)
{
- if (!currentIndex)
- {
- clearCurrentIndex();
- return StorageErrorNoIndex;
- }
+ int ret = checkCurrentIndex();
+
+ if (ret)
+ return ret;
int numberSegments = (upperBound) ? upperBound->numberSegments : (lowerBound) ? lowerBound->numberSegments : 0;
@@ -267,16 +283,15 @@ void StorageTable::indexEnd(void)
int StorageTable::setIndexBound(const unsigned char* key, int keyLength, int which)
{
- if (!currentIndex)
- {
- clearCurrentIndex();
- return StorageErrorNoIndex;
- }
+ int ret = checkCurrentIndex();
+
+ if (ret)
+ return ret;
if (which & LowerBound)
{
lowerBound = &lowerKey;
- int ret = storageDatabase->makeKey(currentIndex, key, keyLength, lowerBound);
+ ret = storageDatabase->makeKey(currentIndex, key, keyLength, lowerBound);
if (ret)
return ret;
@@ -287,7 +302,7 @@ int StorageTable::setIndexBound(const un
else if (which & UpperBound)
{
upperBound = &upperKey;
- int ret = storageDatabase->makeKey(currentIndex, key, keyLength, upperBound);
+ ret = storageDatabase->makeKey(currentIndex, key, keyLength, upperBound);
if (ret)
return ret;
@@ -375,6 +390,11 @@ const char* StorageTable::getSchemaName(
return share->schemaName;
}
+const char* StorageTable::getTableSpaceName(void)
+{
+ return share->tableSpace;
+}
+
void StorageTable::setConnection(StorageConnection* newStorageConn)
{
if (bitmap)
=== modified file 'storage/falcon/StorageTable.h'
--- a/storage/falcon/StorageTable.h 2008-10-22 20:44:09 +0000
+++ b/storage/falcon/StorageTable.h 2009-01-15 20:29:54 +0000
@@ -78,6 +78,7 @@ public:
virtual int indexScan(int indexOrder);
virtual int setCurrentIndex(int indexId);
virtual int clearCurrentIndex();
+ virtual int checkCurrentIndex();
virtual int setIndex(StorageIndexDesc* indexDesc);
virtual void indexEnd(void);
virtual int setIndexBound(const unsigned char* key, int keyLength, int which);
@@ -99,6 +100,7 @@ public:
virtual const unsigned char* getEncoding(int fieldIndex);
virtual const char* getName(void);
virtual const char* getSchemaName(void);
+ virtual const char* getTableSpaceName(void);
virtual int compareKey(const unsigned char* key, int keyLength);
virtual int translateError(SQLException *exception, int defaultStorageError);
virtual int isKeyNull(const unsigned char* key, int keyLength);
=== modified file 'storage/falcon/StorageTableShare.cpp'
--- a/storage/falcon/StorageTableShare.cpp 2008-11-05 14:51:37 +0000
+++ b/storage/falcon/StorageTableShare.cpp 2009-02-04 18:17:01 +0000
@@ -49,6 +49,9 @@ static const char *DB_ROOT = ".fts";
static const char THIS_FILE[]=__FILE__;
#endif
+extern void falcon_lock_init(void *lock);
+extern void falcon_lock_deinit(void *lock);
+
StorageIndexDesc::StorageIndexDesc()
{
id = 0;
@@ -124,6 +127,8 @@ StorageTableShare::StorageTableShare(Sto
storageHandler = handler;
storageDatabase = NULL;
impure = new UCHAR[lockSize];
+ falcon_lock_init(impure);
+
initialized = false;
table = NULL;
format = NULL;
@@ -148,6 +153,8 @@ StorageTableShare::~StorageTableShare(vo
{
delete syncObject;
delete syncIndexMap;
+
+ falcon_lock_deinit(impure);
delete [] impure;
if (storageDatabase)
@@ -258,7 +265,9 @@ int StorageTableShare::deleteTable(Stora
int StorageTableShare::truncateTable(StorageConnection *storageConnection)
{
int res = storageDatabase->truncateTable(storageConnection, this);
-
+
+ sequence = storageDatabase->findSequence(name, schemaName);
+
return res;
}
@@ -408,8 +417,7 @@ int StorageTableShare::dropIndex(Storage
// Remove index description from index mapping
- if (!ret)
- deleteIndex(indexDesc->id);
+ deleteIndex(indexDesc->id);
return ret;
}
=== modified file 'storage/falcon/StorageTableShare.h'
--- a/storage/falcon/StorageTableShare.h 2008-11-05 14:51:37 +0000
+++ b/storage/falcon/StorageTableShare.h 2009-01-21 16:48:25 +0000
@@ -38,13 +38,35 @@ class Sequence;
class SyncObject;
class Format;
+enum KeyFormat {
+ KEY_FORMAT_LONG_INT = 1,
+ KEY_FORMAT_SHORT_INT,
+ KEY_FORMAT_LONGLONG,
+ KEY_FORMAT_ULONGLONG,
+ KEY_FORMAT_FLOAT,
+ KEY_FORMAT_DOUBLE,
+ KEY_FORMAT_VARBINARY,
+ KEY_FORMAT_VARTEXT,
+ KEY_FORMAT_BINARY_STRING,
+ KEY_FORMAT_BINARY_NEWDECIMAL,
+ KEY_FORMAT_BINARY_INTEGER,
+ KEY_FORMAT_TEXT,
+ KEY_FORMAT_ULONG_INT,
+ KEY_FORMAT_TIMESTAMP,
+ KEY_FORMAT_INT8,
+ KEY_FORMAT_USHORT_INT,
+ KEY_FORMAT_UINT24,
+ KEY_FORMAT_INT24,
+ KEY_FORMAT_OTHER
+};
+
struct StorageSegment {
short type;
+ KeyFormat keyFormat;
short nullPosition;
int offset;
int length;
unsigned char nullBit;
- char isUnsigned;
void *mysql_charset;
};
=== modified file 'storage/falcon/StorageVersion.h'
--- a/storage/falcon/StorageVersion.h 2008-12-09 19:27:06 +0000
+++ b/storage/falcon/StorageVersion.h 2009-02-10 13:32:02 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006, 2007, 2008 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,5 +14,5 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#define FALCON_VERSION "T1.3-8"
-#define FALCON_DATE "09 December, 2008"
+#define FALCON_VERSION "T1.4-7"
+#define FALCON_DATE "10 February, 2009"
=== modified file 'storage/falcon/SyncObject.cpp'
--- a/storage/falcon/SyncObject.cpp 2008-10-16 02:59:09 +0000
+++ b/storage/falcon/SyncObject.cpp 2009-02-01 20:54:27 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -306,7 +306,7 @@ void SyncObject::lock(Sync *sync, LockTy
DEBUG_FREEZE;
}
-#else // FAST_SHARED
+#else // else not FAST_SHARED
// Old (aka working) version
@@ -499,7 +499,7 @@ void SyncObject::unlock(Sync *sync, Lock
DEBUG_FREEZE;
}
-#else // FAST_SHARED
+#else // else not FAST_SHARED
void SyncObject::unlock(Sync *sync, LockType type)
{
#if defined TRACE_SYNC_OBJECTS && defined USE_FALCON_SYNC_HANDLER
@@ -621,7 +621,7 @@ void SyncObject::wait(LockType type, Thr
thread->queue = NULL;
thread->lockType = type;
- *ptr = thread;
+ *ptr = thread; // Add this thread to the SyncObject queue
thread->lockGranted = false;
thread->lockPending = sync;
++thread->activeLocks;
@@ -638,17 +638,21 @@ void SyncObject::wait(LockType type, Thr
return;
}
- for (ptr = &queue; *ptr; ptr = &(*ptr)->queue)
- if (*ptr == thread)
- {
- *ptr = thread->queue;
- --waiters;
- break;
- }
-
if (!wokeup)
{
+ // A timeout occured.
+ // Take this thread off the queue and throw an exception
+
+ for (ptr = &queue; *ptr; ptr = &(*ptr)->queue)
+ if (*ptr == thread)
+ {
+ *ptr = thread->queue;
+ --waiters;
+ break;
+ }
+
mutex.release();
+ thread->lockPending = NULL;
timedout(timeout);
}
}
@@ -828,7 +832,7 @@ void SyncObject::grantLocks(void)
mutex.release();
}
-#else // FAST_SHARED
+#else // else not FAST_SHARED
void SyncObject::grantLocks(void)
{
@@ -964,7 +968,7 @@ void SyncObject::unlock(void)
ASSERT(false);
}
-#else //FAST_SHARED
+#else // else not FAST_SHARED
void SyncObject::unlock(void)
{
@@ -1107,7 +1111,7 @@ int SyncObject::getCollisionCount(void)
void SyncObject::backoff(Thread* thread)
{
//thread->sleep(1);
- int a = 0;
+ int a = 0;
for (int n = 0; n < thread->backoff; ++n)
++a;
=== modified file 'storage/falcon/SyncObject.h'
--- a/storage/falcon/SyncObject.h 2008-09-03 21:49:18 +0000
+++ b/storage/falcon/SyncObject.h 2009-01-08 09:05:26 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
=== removed file 'storage/falcon/SyncWait.cpp'
--- a/storage/falcon/SyncWait.cpp 2007-09-20 15:44:25 +0000
+++ b/storage/falcon/SyncWait.cpp 1970-01-01 00:00:00 +0000
@@ -1,26 +0,0 @@
-/* Copyright (C) 2006 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-// SyncWait.cpp: implementation of the SyncWait class.
-//
-//////////////////////////////////////////////////////////////////////
-
-#include "Engine.h"
-#include "SyncWait.h"
-
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
=== modified file 'storage/falcon/Table.cpp'
--- a/storage/falcon/Table.cpp 2008-11-20 17:05:50 +0000
+++ b/storage/falcon/Table.cpp 2009-02-09 10:33:13 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -57,6 +57,7 @@
#include "RecordScavenge.h"
#include "Section.h"
#include "BackLog.h"
+#include "Thread.h"
#ifndef STORAGE_ENGINE
#include "Trigger.h"
@@ -251,7 +252,9 @@ void Table::create(const char * tableTyp
dataSectionId = dbb->createSection(TRANSACTION_ID(transaction));
blobSectionId = dbb->createSection(TRANSACTION_ID(transaction));
- FOR_INDEXES(index, this);
+ // Iterate all indexes, assume indexId == -1
+
+ FOR_ALL_INDEXES(index, this);
index->create(transaction);
END_FOR;
}
@@ -340,6 +343,7 @@ void Table::insert(Transaction *transact
Format *format = getFormat(formatVersion);
record = allocRecordVersion(format, transaction, NULL);
+ record->state = recInserting;
// Handle any default values
@@ -380,15 +384,15 @@ void Table::insert(Transaction *transact
recordNumber = record->recordNumber = dbb->insertStub(dataSection, transaction);
- // Verify that record is valid
+ checkNullable(record); // Verify that record is valid
- checkNullable(record);
transaction->addRecord(record);
- insert(record, NULL, recordNumber);
+ insertIntoTree(record, NULL, recordNumber);
inserted = true;
insertIndexes(transaction, record);
updateInversion(record, transaction);
fireTriggers(transaction, PostInsert, NULL, record);
+ record->state = recData;
record->release();
}
catch (...)
@@ -396,7 +400,7 @@ void Table::insert(Transaction *transact
if (inserted)
{
transaction->removeRecord(record);
- insert(NULL, record, recordNumber);
+ insertIntoTree(NULL, record, recordNumber);
}
if (recordNumber >= 0)
@@ -409,8 +413,13 @@ void Table::insert(Transaction *transact
garbageCollect(record, NULL, transaction, true);
if (record)
+ {
+#ifdef CHECK_RECORD_ACTIVITY
+ record->active = false;
+#endif
record->release();
-
+ }
+
throw;
}
@@ -474,8 +483,6 @@ void Table::reformat()
void Table::updateRecord (RecordVersion * record)
{
- activeVersions = true;
-
FOR_OBJECTS (TableAttachment*, attachment, &attachments)
if (attachment->mask & POST_COMMIT)
attachment->postCommit(this, record);
@@ -498,7 +505,7 @@ Record* Table::fetchNext(int32 start)
Stream stream;
Sync sync(&syncObject, "Table::fetchNext");
sync.lock(Shared);
- Record *record;
+ Record *record = NULL;
int32 recordNumber = start;
for (;;)
@@ -519,23 +526,35 @@ Record* Table::fetchNext(int32 start)
// Record should exist somewhere
if (records && (record = records->fetch(bitNumber)))
+ {
+ // Don't bother with a record that is half-way inserted.
+
+ if (record->state == recInserting)
+ {
+ recordNumber = bitNumber + 1;
+ continue;
+ }
+
break;
+ }
if (backloggedRecords && (record = backlogFetch(bitNumber)))
break;
-
+
sync.unlock();
-
+
for (int n = 0; (record = databaseFetch(bitNumber)); ++n)
{
- if (insert(record, NULL, bitNumber))
+ if (insertIntoTree(record, NULL, bitNumber))
{
record->poke();
-
+
return record;
}
-
+
+#ifdef CHECK_RECORD_ACTIVITY
record->active = false;
+#endif
record->release();
sync.lock(Shared);
@@ -603,21 +622,26 @@ Record* Table::fetchNext(int32 start)
sync.unlock();
record = allocRecord(recNumber, &stream);
- if (insert(record, NULL, recNumber))
+ if (insertIntoTree(record, NULL, recNumber))
{
if (bitNumber < 0 || recNumber <= bitNumber)
return record;
}
else
{
+#ifdef CHECK_RECORD_ACTIVITY
record->active = false;
+#endif
record->release();
}
sync.lock(Shared);
}
- if (bitNumber >= 0 && bitNumber < recNumber && records && (record = records->fetch(bitNumber)))
+ if ( (bitNumber >= 0 )
+ && (bitNumber < recNumber)
+ && (records)
+ && (record = records->fetch(bitNumber)))
break;
sync.unlock();
@@ -841,7 +865,6 @@ void Table::init(int id, const char *sch
highWater = 0;
eof = false;
markedForDelete = false;
- activeVersions = false;
primaryKey = NULL;
formats = NEW Format* [FORMAT_HASH_SIZE];
triggers = NULL;
@@ -857,7 +880,6 @@ void Table::init(int id, const char *sch
alterIsActive = false;
syncObject.setName("Table::syncObject");
syncTriggers.setName("Table::syncTriggers");
- syncScavenge.setName("Table::syncScavenge");
syncAlter.setName("Table::syncAlter");
for (int n = 0; n < SYNC_VERSIONS_SIZE; n++)
@@ -912,10 +934,12 @@ Record* Table::fetch(int32 recordNumber)
sync.lock(Exclusive);
record = database->backLog->fetch(backlogId);
- if (insert(record, NULL, recordNumber))
+ if (insertIntoTree(record, NULL, recordNumber))
return record;
+#ifdef CHECK_RECORD_ACTIVITY
record->active = false;
+#endif
record->release();
continue;
@@ -929,10 +953,12 @@ Record* Table::fetch(int32 recordNumber)
record->poke();
- if (insert(record, NULL, recordNumber))
+ if (insertIntoTree(record, NULL, recordNumber))
return record;
+#ifdef CHECK_RECORD_ACTIVITY
record->active = false;
+#endif
record->release();
sync.lock(Shared);
}
@@ -973,7 +999,7 @@ Record* Table::backlogFetch(int32 record
if (backlogId)
{
Record *record = database->backLog->fetch(backlogId);
- ASSERT (insert(record, NULL, recordNumber));
+ ASSERT (insertIntoTree(record, NULL, recordNumber));
return record;
}
@@ -1006,7 +1032,7 @@ void Table::rollbackRecord(RecordVersion
// Replace the current version of this record.
- if (!insert(priorRecord, recordToRollback, recordToRollback->recordNumber))
+ if (!insertIntoTree(priorRecord, recordToRollback, recordToRollback->recordNumber))
{
if (priorRecord == NULL && priorState == recDeleted)
return;
@@ -1232,32 +1258,39 @@ void Table::insertIndexes(Transaction *t
{
if (indexes)
{
+ Sync syncTable(&syncObject, "Table::insertIndexes");
+
FOR_INDEXES(index, this);
- Sync sync(&index->syncUnique, "Table::insertIndexes");
+ Sync syncUnique(&index->syncUnique, "Table::insertIndexes");
if (needUniqueCheck(index,record))
for(;;)
{
- sync.lock(Exclusive);
+ syncUnique.lock(Exclusive);
- if(!checkUniqueIndex(index, transaction, record, &sync))
+ if(!checkUniqueIndex(index, transaction, record, &syncUnique))
break;
}
- index->insert(record, transaction);
+ // Block concurrent DDL with a shared lock. Double-check the
+ // index id in case the index was deleted.
+
+ syncTable.lock(Shared);
+
+ if (index->indexId != -1)
+ index->insert(record, transaction);
+
+ syncTable.unlock();
END_FOR;
}
}
-
void Table::update(Transaction * transaction, Record * oldRecord, int numberFields, Field** updateFields, Value * * values)
{
database->preUpdate();
RecordVersion *record = NULL;
bool updated = false;
int recordNumber = oldRecord->recordNumber;
- Sync scavenge(&syncScavenge, "Table::update(1)");
- //scavenge.lock(Shared);
try
{
@@ -1311,8 +1344,6 @@ void Table::update(Transaction * transac
// Make insert/update atomic, then check for unique index duplicats
-
- scavenge.lock(Shared);
validateAndInsert(transaction, record);
transaction->addRecord(record);
updated = true;
@@ -1323,9 +1354,8 @@ void Table::update(Transaction * transac
// If this is a re-update in the same transaction and the same savepoint,
// carefully remove the prior version.
-
- record->scavenge(transaction->transactionId, transaction->curSavePointId);
+ record->scavengeSavepoint(transaction->transactionId, transaction->curSavePointId);
record->release();
}
catch (...)
@@ -1333,7 +1363,7 @@ void Table::update(Transaction * transac
if (updated)
{
transaction->removeRecord(record);
- insert(oldRecord, record, recordNumber);
+ insertIntoTree(oldRecord, record, recordNumber);
}
garbageCollect(record, oldRecord, transaction, true);
@@ -1346,6 +1376,10 @@ void Table::update(Transaction * transac
if (record->state == recLock)
record->deleteData();
+#ifdef CHECK_RECORD_ACTIVITY
+ record->active = false;
+#endif
+
record->release();
}
@@ -1476,17 +1510,16 @@ ForeignKey* Table::findForeignKey(Foreig
void Table::deleteRecord(Transaction * transaction, Record * orgRecord)
{
database->preUpdate();
- Sync scavenge(&syncScavenge, "Table::deleteRecord");
// syncPrior is not needed here. It is handled in fetchVersion()
Record *candidate = fetch(orgRecord->recordNumber);
+ if (!candidate)
+ return;
+
checkAncestor(candidate, orgRecord);
RecordVersion *record;
bool wasLock = false;
- if (!candidate)
- return;
-
if (candidate->state == recLock && candidate->getTransaction() == transaction)
{
if (candidate->getSavePointId() == transaction->curSavePointId)
@@ -1533,8 +1566,6 @@ void Table::deleteRecord(Transaction * t
attachment->preDelete(this, record);
END_FOR;
- scavenge.lock(Shared);
-
if (wasLock)
{
record->state = recDeleted;
@@ -1548,11 +1579,15 @@ void Table::deleteRecord(Transaction * t
}
catch (...)
{
+#ifdef CHECK_RECORD_ACTIVITY
+ record->active = false;
+#endif
+
record->release();
-
+
throw;
}
-
+
transaction->addRecord(record);
}
@@ -1860,71 +1895,64 @@ void Table::setView(View *viewObject)
view = viewObject;
}
+// Prune old invisible records from this table and inventory the rest.
-int Table::retireRecords(RecordScavenge *recordScavenge)
+void Table::pruneRecords(RecordScavenge *recordScavenge)
{
if (!records)
- return 0;
+ return;
Sync syncObj(&syncObject, "Table::retireRecords");
syncObj.lock(Shared);
+ if (records)
+ records->pruneRecords(this, 0, recordScavenge);
+}
+
+void Table::retireRecords(RecordScavenge *recordScavenge)
+{
if (!records)
- return 0;
-
- activeVersions = false;
+ return;
+
+ Sync syncObj(&syncObject, "Table::retireRecords");
+ syncObj.lock(Shared);
+
+ if (!records)
+ return;
+
emptySections->clear();
- int count = records->retireRecords(this, 0, recordScavenge);
+ records->retireRecords(this, 0, recordScavenge);
+ syncObj.unlock();
+
+ // Get an exclusive lock only if there are empty leaf nodes. Find and
+ // delete the empty nodes using the stored record numbers as identifiers.
- if (count == 0)
+ if (emptySections->count > 0)
{
- syncObj.unlock();
syncObj.lock(Exclusive);
- // Confirm that tree is still empty
+ // Delete these newly emptied RecordLeaf sections
- count = records->countActiveRecords();
+ for (int sectionNumber = 0; (sectionNumber = emptySections->nextSet(0)) >= 0;)
+ {
+ int recordNumber = sectionNumber * RECORD_SLOTS;
+ records->retireSections(this, recordNumber);
+ emptySections->clear(sectionNumber);
+ }
+
+ // Check if there are any sections/active records left in this table.
- if (count == 0)
+ if (!records->anyActiveRecords())
{
delete records;
records = NULL;
}
}
- else
- {
- // Get an exclusive lock only if there are empty leaf nodes. Find and
- // delete the empty nodes using the stored record numbers as identifiers.
-
- if (emptySections->count > 0)
- {
- syncObj.unlock();
- syncObj.lock(Exclusive);
- for (int sectionNumber = 0; (sectionNumber = emptySections->nextSet(0)) >= 0;)
- {
- int recordNumber = sectionNumber * RECORD_SLOTS;
- records->retireSections(this, recordNumber);
- emptySections->clear(sectionNumber);
- }
-
- }
- }
-
- return count;
+ return;
}
-void Table::inventoryRecords(RecordScavenge* recordScavenge)
-{
- if (!records)
- return;
-
- Sync sync(&syncObject, "Table::inventoryRecords");
- sync.lock(Shared);
- records->inventoryRecords(recordScavenge);
-}
-
-bool Table::insert(Record * record, Record *prior, int recordNumber)
+bool Table::insertIntoTree(Record * record, Record *prior, int recordNumber)
{
ageGroup = database->currentGeneration;
Sync sync(&syncObject, "Table::insert");
@@ -1971,7 +1999,9 @@ bool Table::insert(Record * record, Reco
{
if (prior)
{
+#ifdef CHECK_RECORD_ACTIVITY
prior->active = false;
+#endif
prior->release();
}
@@ -1984,28 +2014,6 @@ bool Table::insert(Record * record, Reco
return false;
}
-void Table::expungeRecordVersions(RecordVersion *record, RecordScavenge *recordScavenge)
-{
- ASSERT(record->state != recLock);
-
- Record *prior = record->clearPriorVersion();
-
- if (recordScavenge)
- for (Record *rec = prior; rec; rec = rec->getPriorVersion())
- {
- ++recordScavenge->recordsReclaimed;
- recordScavenge->spaceReclaimed += record->size;
- }
-
-#ifdef CHECK_RECORD_ACTIVITY
- for (Record *rec = prior; rec; rec = rec->getPriorVersion())
- rec->active = false;
-#endif
-
- garbageCollect(prior, record, NULL, false);
- prior->release();
-}
-
bool Table::duplicateBlob(Value * blob, int fieldId, Record * recordChain)
{
bool isDuplicate = false;
@@ -2558,6 +2566,9 @@ bool Table::checkUniqueRecordVersion(int
if (dup->state == recLock)
continue; // Next record version.
+ if (dup->state == recRollback)
+ continue; // Next record version.
+
// The record has been deleted.
ASSERT(dup->state == recDeleted);
@@ -2608,12 +2619,14 @@ bool Table::checkUniqueRecordVersion(int
{
if (state == Active)
{
+ dup->addRef();
syncPrior.unlock(); // release lock before wait
syncUnique->unlock(); // release lock before wait
// Wait for that transaction, then restart checkUniqueIndexes()
state = transaction->getRelativeState(dup, WAIT_IF_ACTIVE);
+ dup->release(); // We are done with this now.
if (state != Deadlock)
{
@@ -2789,16 +2802,10 @@ int Table::chartActiveRecords(int *chart
void Table::rebuildIndex(Index *index, Transaction *transaction)
{
index->rebuildIndex(transaction);
- populateIndex(index, transaction);
+ populateIndex(index, transaction);
}
-void Table::cleanupRecords(RecordScavenge *recordScavenge)
-{
- if (activeVersions)
- retireRecords(recordScavenge);
-}
-
void Table::validateBlobs(int optionMask)
{
Field *field;
@@ -3037,6 +3044,7 @@ uint Table::insert(Transaction *transact
fmt = format = getFormat(formatVersion);
record = allocRecordVersion(fmt, transaction, NULL);
+ record->state = recInserting;
record->setEncodedRecord(stream, false);
recordNumber = record->recordNumber = dbb->insertStub(dataSection, transaction);
@@ -3046,11 +3054,11 @@ uint Table::insert(Transaction *transact
// Do the actual insert
transaction->addRecord(record);
- bool ret = insert(record, NULL, recordNumber);
+ bool ret = insertIntoTree(record, NULL, recordNumber);
inserted = true;
insertIndexes(transaction, record);
ASSERT(ret);
-
+ record->state = recData;
record->release();
}
catch (...)
@@ -3058,11 +3066,9 @@ uint Table::insert(Transaction *transact
if (inserted)
{
transaction->removeRecord(record);
- insert(NULL, record, recordNumber);
+ insertIntoTree(NULL, record, recordNumber);
}
- garbageCollect(record, NULL, transaction, true);
-
if (recordNumber >= 0)
{
dbb->updateRecord(dataSection, recordNumber, NULL, transaction, false);
@@ -3070,8 +3076,15 @@ uint Table::insert(Transaction *transact
record->recordNumber = -1;
}
+ garbageCollect(record, NULL, transaction, true);
+
if (record)
+ {
+#ifdef CHECK_RECORD_ACTIVITY
+ record->active = false;
+#endif
record->release();
+ }
throw;
}
@@ -3084,13 +3097,12 @@ void Table::update(Transaction * transac
database->preUpdate();
Record *candidate = fetch(orgRecord->recordNumber);
- checkAncestor(candidate, orgRecord);
-
if (!candidate)
return;
+ checkAncestor(candidate, orgRecord);
Record *oldRecord = candidate;
-
+
if (candidate->getTransaction() == transaction)
{
if (candidate->state == recLock)
@@ -3109,8 +3121,6 @@ void Table::update(Transaction * transac
RecordVersion *record = NULL;
bool updated = false;
- Sync scavenge(&syncScavenge, "Table::update(2)");
- //scavenge.lock(Shared);
if (candidate->state == recLock && candidate->getTransaction() == transaction)
{
@@ -3159,7 +3169,6 @@ void Table::update(Transaction * transac
END_FOR;
//updateInversion(record, transaction);
- scavenge.lock(Shared);
if (record->state == recLock)
record->state = recData;
@@ -3177,10 +3186,8 @@ void Table::update(Transaction * transac
// If this is a re-update in the same transaction and the same savepoint,
// carefully remove the prior version.
- record->scavenge(transaction->transactionId, transaction->curSavePointId);
-
- if (record)
- record->release();
+ record->scavengeSavepoint(transaction->transactionId, transaction->curSavePointId);
+ record->release();
oldRecord->release(); // This reference originated in this function.
}
@@ -3190,7 +3197,7 @@ void Table::update(Transaction * transac
{
transaction->removeRecord(record);
- if (!insert(oldRecord, record, record->recordNumber))
+ if (!insertIntoTree(oldRecord, record, record->recordNumber))
Log::debug("record backout failed after failed update\n");
}
@@ -3204,6 +3211,10 @@ void Table::update(Transaction * transac
if (record->state == recLock)
record->deleteData();
+#ifdef CHECK_RECORD_ACTIVITY
+ record->active = false;
+#endif
+
record->release();
}
@@ -3350,13 +3361,15 @@ void Table::validateAndInsert(Transactio
}
}
- if (insert(record, prior, record->recordNumber))
+ if (insertIntoTree(record, prior, record->recordNumber))
return;
if (n >= 7)
Log::debug("Table::validateAndInsert: things going badly (%d)\n", n);
+#ifdef CHECK_RECORD_ACTIVITY
record->active = false;
+#endif
}
throw SQLError(UPDATE_CONFLICT, "unexpected update conflict in table %s.%s record %d", schemaName, name, record->recordNumber);
@@ -3378,54 +3391,6 @@ void Table::waitForWriteComplete()
{
database->waitForWriteComplete(this);
}
-/*
-RecordVersion* Table::lockRecord(Record* record, Transaction* transaction)
-{
- Record *current = fetch(record->recordNumber);
-
- if (!current)
- throw SQLError(UPDATE_CONFLICT, "lock target from table %s.%s", schemaName, name);
-
- // If the current version is already updated/locked by us, there's nothing to do
-
- if (current->getTransaction() == transaction)
- {
- current->release();
-
- return NULL;
- }
-
- checkAncestor(current, record);
- Record *visible = current->fetchVersion(transaction);
-
- if (!visible)
- {
- printf("Target for transaction %d:\n", transaction->transactionId);
- record->print();
- current->printRecord("Current");
- current->fetchVersion(transaction);
- ASSERT(false);
- }
-
- RecordVersion *recordVersion = allocRecordVersion(NULL, transaction, visible);
- recordVersion->state = recLock;
- current->release();
-
- try
- {
- validateAndInsert(transaction, recordVersion);
- transaction->addRecord(recordVersion);
- recordVersion->release();
- }
- catch(...)
- {
- recordVersion->active = false;
- recordVersion->release();
- throw;
- }
-
- return recordVersion;
-} */
void Table::unlockRecord(int recordNumber)
{
@@ -3449,7 +3414,8 @@ void Table::unlockRecord(RecordVersion*
if ((record->state == recLock) && !record->isSuperceded())
{
- if (insert(record->getPriorVersion(), record, record->recordNumber))
+ Record *prior = record->getPriorVersion();
+ if (insertIntoTree(prior, record, record->recordNumber))
record->setSuperceded(true);
else
Log::debug("Table::unlockRecord: record lock not in record tree\n");
@@ -3560,7 +3526,7 @@ Record* Table::fetchForUpdate(Transactio
RecordVersion *recordVersion = allocRecordVersion(NULL, transaction, record);
recordVersion->state = recLock;
- if (insert(recordVersion, record, recordNumber))
+ if (insertIntoTree(recordVersion, record, recordNumber))
{
transaction->addRecord(recordVersion);
recordVersion->release();
@@ -3570,7 +3536,9 @@ Record* Table::fetchForUpdate(Transactio
return record;
}
+#ifdef CHECK_RECORD_ACTIVITY
recordVersion->active = false;
+#endif
recordVersion->release();
}
break;
@@ -3614,14 +3582,22 @@ void Table::optimize(Connection *connect
record = record->fetchVersion(transaction);
if (record)
+ {
+ record->release(); // no need to keep it around
++count;
+ }
}
cardinality = count;
+ // Disable index optimization until a more
+ // efficient method is implemented using
+ // the IndexWalker (Bug#36442)
+#if 0
FOR_INDEXES(index, this);
index->optimize(count, connection);
END_FOR;
+#endif
database->commitSystemTransaction();
}
@@ -3651,39 +3627,77 @@ bool Table::setAlter(void)
#undef new
+// Allocate a RecordVersion object from the record cache.
+// Use an non-thread-safe increment of recordPoolAllocCount. It allows
+// full concurrency by multiple threads but it may miss a check every
+// now and then. This keeps the code from doing this check every time.
+// It is done about every 128 allocations from the record cache.
+
RecordVersion* Table::allocRecordVersion(Format* format, Transaction* transaction, Record* priorVersion)
{
- for (int n = 0;; ++n)
+ for (int n = 1;; ++n)
+ {
try
{
+ if ((++database->recordPoolAllocCount & 0x7F) == 0)
+ database->checkRecordScavenge();
+
return POOL_NEW(database->recordDataPool) RecordVersion(this, format, transaction, priorVersion);
}
+
catch (SQLException& exception)
{
- if (n > 2 || exception.getSqlcode() != OUT_OF_RECORD_MEMORY_ERROR)
+ if ( exception.getSqlcode() != OUT_OF_RECORD_MEMORY_ERROR
+ || n > OUT_OF_RECORD_MEMORY_RETRIES)
throw;
-
- database->forceRecordScavenge();
+
+ database->signalScavenger(true);
+
+ // Give the scavenger thread a chance to release memory.
+ // Increase the wait time per iteration.
+
+ Thread *thread = Thread::getThread("Database::ticker");
+ thread->sleep(n * SCAVENGE_WAIT_MS);
}
-
+ }
+
return NULL;
}
+// Allocate a Record object from the record cache.
+// Use an non-thread-safe increment of recordPoolAllocCount. It allows
+// full concurrency by multiple threads but it may miss a check every
+// now and then. This keeps the code from doing this check every time.
+// It is done about every 128 allocations from the record cache.
+
Record* Table::allocRecord(int recordNumber, Stream* stream)
{
- for (int n = 0;; ++n)
+ for (int n = 1;; ++n)
+ {
try
{
+ if ((++database->recordPoolAllocCount & 0x7F) == 0)
+ database->checkRecordScavenge();
+
return POOL_NEW(database->recordDataPool) Record (this, recordNumber, stream);
}
+
catch (SQLException& exception)
{
- if (n > 2 || exception.getSqlcode() != OUT_OF_RECORD_MEMORY_ERROR)
+ if ( exception.getSqlcode() != OUT_OF_RECORD_MEMORY_ERROR
+ || n > OUT_OF_RECORD_MEMORY_RETRIES)
throw;
-
- database->forceRecordScavenge();
+
+ database->signalScavenger(true);
+
+ // Give the scavenger thread a chance to release memory.
+ // Increase the wait time per iteration.
+
+ Thread *thread = Thread::getThread("Database::ticker");
+ thread->sleep(n * SCAVENGE_WAIT_MS);
}
-
+ }
+
return NULL;
}
@@ -3785,7 +3799,7 @@ int32 Table::backlogRecord(RecordVersion
backloggedRecords->set(record->recordNumber, backlogId);
}
- ASSERT(insert(NULL, record, record->recordNumber));
+ ASSERT(insertIntoTree(NULL, record, record->recordNumber));
recordBitmap->set(record->recordNumber);
return backlogId;
@@ -3808,7 +3822,8 @@ void Table::deleteRecordBacklog(int32 re
SyncObject* Table::getSyncPrior(Record* record)
{
- int lockNumber = record->recordNumber % SYNC_VERSIONS_SIZE;
+ int recNumber = (record->recordNumber == -1) ? 0 : record->recordNumber;
+ int lockNumber = recNumber % SYNC_VERSIONS_SIZE;
return syncPriorVersions + lockNumber;
}
=== modified file 'storage/falcon/Table.h'
--- a/storage/falcon/Table.h 2008-11-20 05:32:18 +0000
+++ b/storage/falcon/Table.h 2009-02-09 05:01:44 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -42,11 +42,18 @@ static const int PostCommit = 128;
static const int BL_SIZE = 128;
static const int FORMAT_HASH_SIZE = 20;
-static const int SYNC_VERSIONS_SIZE = 16;
-static const int SYNC_THAW_SIZE = 16;
+static const int SYNC_VERSIONS_SIZE = 32; // 16;
+static const int SYNC_THAW_SIZE = 32; // 16;
#define FOR_FIELDS(field,table) {for (Field *field=table->fields; field; field = field->next){
-#define FOR_INDEXES(index,table) {for (Index *index=table->indexes; index; index = index->next){
+
+// For all indexes, regardless of state
+
+#define FOR_ALL_INDEXES(index,table) {for (Index *index=table->indexes; index; index = index->next){
+
+// For all indexes except incomplete or invalid
+
+#define FOR_INDEXES(index,table) {for (Index *index=table->indexes; index; index = index->next){if (index->indexId == -1) continue;
class Database;
class Dbb;
@@ -96,9 +103,9 @@ public:
void rebuildIndexes (Transaction *transaction, bool force = false);
void collationChanged (Field *field);
void validateBlobs (int optionMask);
- void cleanupRecords(RecordScavenge *recordScavenge);
void rebuildIndex (Index *index, Transaction *transaction);
- int retireRecords (RecordScavenge *recordScavenge);
+ void pruneRecords (RecordScavenge *recordScavenge);
+ void retireRecords (RecordScavenge *recordScavenge);
int countActiveRecords();
int chartActiveRecords(int *chart);
bool foreignKeyMember (ForeignKey *key);
@@ -139,7 +146,6 @@ public:
void expungeBlob (Value *blob);
bool duplicateBlob (Value *blob, int fieldId, Record *recordChain);
void expungeRecord(int32 recordNumber);
- void expungeRecordVersions (RecordVersion *record, RecordScavenge *recordScavenge);
void setView (View *view);
Index* findIndex (const char *indexName);
virtual PrivObject getPrivilegeType();
@@ -203,16 +209,14 @@ public:
RecordVersion* allocRecordVersion(Format* format, Transaction* transaction, Record* priorVersion);
Record* allocRecord(int recordNumber, Stream* stream);
- void inventoryRecords(RecordScavenge* recordScavenge);
Format* getCurrentFormat(void);
Record* fetchForUpdate(Transaction* transaction, Record* record, bool usingIndex);
-// RecordVersion* lockRecord(Record* record, Transaction* transaction);
void unlockRecord(int recordNumber);
void unlockRecord(RecordVersion* record);
void insert (Transaction *transaction, int count, Field **fields, Value **values);
uint insert (Transaction *transaction, Stream *stream);
- bool insert (Record *record, Record *prior, int recordNumber);
+ bool insertIntoTree (Record *record, Record *prior, int recordNumber);
void insertIndexes(Transaction *transaction, RecordVersion *record);
void update (Transaction *transaction, Record *record, int numberFields, Field **fields, Value** values);
@@ -231,7 +235,6 @@ public:
Dbb *dbb;
SyncObject syncObject;
SyncObject syncTriggers;
- SyncObject syncScavenge;
SyncObject syncAlter; // prevent concurrent Alter statements.
SyncObject syncPriorVersions[SYNC_VERSIONS_SIZE];
SyncObject syncThaw[SYNC_THAW_SIZE];
@@ -267,7 +270,6 @@ public:
bool changed;
bool eof;
bool markedForDelete;
- bool activeVersions;
bool alterIsActive;
bool deleting; // dropping or truncating.
int32 highWater;
=== modified file 'storage/falcon/TableSpaceManager.cpp'
--- a/storage/falcon/TableSpaceManager.cpp 2008-11-05 17:58:43 +0000
+++ b/storage/falcon/TableSpaceManager.cpp 2009-01-31 23:22:42 +0000
@@ -86,7 +86,10 @@ void TableSpaceManager::add(TableSpace *
TableSpace* TableSpaceManager::findTableSpace(const char *name)
{
- Sync syncObj(&syncObject, "TableSpaceManager::findTableSpace(1)");
+ Sync syncDDL(&database->syncSysDDL, "TableSpaceManager::findTableSpace(DDL)");
+ syncDDL.lock(Shared);
+
+ Sync syncObj(&syncObject, "TableSpaceManager::findTableSpace(syncObj)");
syncObj.lock(Shared);
TableSpace *tableSpace;
@@ -101,9 +104,6 @@ TableSpace* TableSpaceManager::findTable
if (tableSpace->name == name)
return tableSpace;
- Sync syncDDL(&database->syncSysDDL, "TableSpaceManager::findTableSpace(2)");
- syncDDL.lock(Shared);
-
PStatement statement = database->prepareStatement(
"select tablespace_id, filename, comment from system.tablespaces where tablespace=?");
statement->setString(1, name);
@@ -147,7 +147,7 @@ TableSpace* TableSpaceManager::getTableS
throw SQLError(TABLESPACE_NOT_EXIST_ERROR, "can't find table space \"%s\"", name);
if (!tableSpace->active)
- throw SQLError(RUNTIME_ERROR, "table space \"%s\" is not active", (const char*) tableSpace->name);
+ tableSpace->open();
return tableSpace;
}
@@ -156,9 +156,9 @@ TableSpace* TableSpaceManager::createTab
{
Sync syncDDL(&database->syncSysDDL, "TableSpaceManager::createTableSpace");
syncDDL.lock(Exclusive);
- Sequence *sequence = database->sequenceManager->getSequence(database->getSymbol("SYSTEM"), database->getSymbol("TABLESPACE_IDS"));
+
int type = (repository) ? TABLESPACE_TYPE_REPOSITORY : TABLESPACE_TYPE_TABLESPACE;
- int id = (int) sequence->update(1, database->getSystemTransaction());
+ int id = createTableSpaceId();
TableSpace *tableSpace = new TableSpace(database, name, id, fileName, type, tsInit);
@@ -175,6 +175,7 @@ TableSpace* TableSpaceManager::createTab
if (!repository)
tableSpace->create();
+
createdFile = true;
add(tableSpace);
database->serialLog->logControl->createTableSpace.append(tableSpace);
@@ -183,11 +184,15 @@ TableSpace* TableSpaceManager::createTab
{
if (createdFile)
IO::deleteFile(fileName);
+
database->rollbackSystemTransaction();
delete tableSpace;
+
throw;
}
+
database->commitSystemTransaction();
+
return tableSpace;
}
@@ -208,27 +213,11 @@ void TableSpaceManager::bootstrap(int se
p = EncodedDataStream::decode(p, &id, true);
p = EncodedDataStream::decode(p, &fileName, true);
p = EncodedDataStream::decode(p, &type, true);
- /***
- p = EncodedDataStream::decode(p, &comment, true);
- TableSpaceInit tsInit;
- tsInit.comment = comment.getString();
- ***/
TableSpace *tableSpace = new TableSpace(database, name.getString(), id.getInt(), fileName.getString(), type.getInt(), NULL);
Log::debug("New table space %s, id %d, type %d, filename %s\n", (const char*) tableSpace->name, tableSpace->tableSpaceId, tableSpace->type, (const char*) tableSpace->filename);
-
- if (tableSpace->type == TABLESPACE_TYPE_TABLESPACE)
- try
- {
- tableSpace->open();
- }
- catch(SQLException& exception)
- {
- Log::log("Couldn't open table space file \"%s\" for tablespace \"%s\": %s\n",
- fileName.getString(), name.getString(), exception.getText());
- }
-
+
add(tableSpace);
stream.clear();
}
@@ -251,7 +240,6 @@ TableSpace* TableSpaceManager::getTableS
throw SQLError(COMPILE_ERROR, "can't find table space %d", id);
if (!tableSpace->active)
- //throw SQLError(RUNTIME_ERROR, "table space \"%s\" is not active", (const char*) tableSpace->name);
tableSpace->open();
return tableSpace;
@@ -272,12 +260,12 @@ void TableSpaceManager::dropDatabase(voi
void TableSpaceManager::dropTableSpace(TableSpace* tableSpace)
{
- Sync syncObj(&syncObject, "TableSpaceManager::dropTableSpace(1)");
+ Sync syncDDL(&database->syncSysDDL, "TableSpaceManager::dropTableSpace(DDL)");
+ syncDDL.lock(Exclusive);
+
+ Sync syncObj(&syncObject, "TableSpaceManager::dropTableSpace(syncObj)");
syncObj.lock(Exclusive);
- Sync syncDDL(&database->syncSysDDL, "TableSpaceManager::dropTableSpace(2)");
- syncDDL.lock(Shared);
-
PStatement statement = database->prepareStatement(
"delete from system.tablespaces where tablespace=?");
statement->setString(1, tableSpace->name);
@@ -390,47 +378,60 @@ void TableSpaceManager::redoCreateTableS
{
Sync sync(&syncObject, "TableSpaceManager::redoCreateTableSpace");
sync.lock(Exclusive);
- TableSpace *tableSpace;
+ TableSpace *tableSpace = NULL;
for (tableSpace = idHash[id % TS_HASH_SIZE]; tableSpace; tableSpace = tableSpace->idCollision)
if (tableSpace->tableSpaceId == id)
- return;
+ {
+ tableSpace->close();
+ break;
+ }
- char buffer[1024];
- memcpy(buffer, name, nameLength);
- buffer[nameLength] = 0;
- char *file = buffer + nameLength + 1;
- memcpy(file, fileName, fileNameLength);
- file[fileNameLength] = 0;
- tableSpace = new TableSpace(database, buffer, id, file, type, tsInit);
- tableSpace->needSave = true;
- add(tableSpace);
+ if (!tableSpace)
+ {
+ char buffer[1024];
+ memcpy(buffer, name, nameLength);
+ buffer[nameLength] = 0;
+ char *file = buffer + nameLength + 1;
+ memcpy(file, fileName, fileNameLength);
+ file[fileNameLength] = 0;
+ tableSpace = new TableSpace(database, buffer, id, file, type, tsInit);
+ tableSpace->needSave = true;
+ add(tableSpace);
+ }
try
{
- tableSpace->open();
+ Dbb *dbb = tableSpace->dbb;
+
+ dbb->create(tableSpace->filename, database->dbb->pageSize, 0, HdrTableSpace,
+ NO_TRANSACTION, "", true);
+ dbb->close();
+
}
catch(SQLException& exception)
{
Log::log("Couldn't open table space file \"%s\" for tablespace \"%s\": %s\n",
- file, buffer, exception.getText());
+ tableSpace->filename.getString(), tableSpace->name.getString(), exception.getText());
+
+ // remove from various hashtables
+ expungeTableSpace(tableSpace->tableSpaceId);
}
}
void TableSpaceManager::initialize(void)
{
- Sync syncObj(&syncObject, "TableSpaceManager::initialize");
+ Sync syncDDL(&database->syncSysDDL, "TableSpaceManager::initialize(DDL)");
+ syncDDL.lock(Exclusive);
+
+ Sync syncObj(&syncObject, "TableSpaceManager::initialize(syncObj)");
syncObj.lock(Shared);
for (TableSpace *tableSpace = tableSpaces; tableSpace; tableSpace = tableSpace->next)
if (tableSpace->needSave)
- {
- Sync syncDDL(&database->syncSysDDL, "TableSpaceManager::dropTableSpace");
- syncDDL.lock(Shared);
tableSpace->save();
- syncDDL.unlock();
- database->commitSystemTransaction();
- }
+
+ database->commitSystemTransaction();
}
void TableSpaceManager::postRecovery(void)
@@ -563,3 +564,9 @@ void TableSpaceManager::getTableSpaceFil
}
}
+int TableSpaceManager::createTableSpaceId()
+{
+ Sequence *sequence = database->sequenceManager->getSequence(database->getSymbol("SYSTEM"), database->getSymbol("TABLESPACE_IDS"));
+ int id = (int) sequence->update(1, database->getSystemTransaction());
+ return id;
+}
=== modified file 'storage/falcon/TableSpaceManager.h'
--- a/storage/falcon/TableSpaceManager.h 2008-10-31 00:29:13 +0000
+++ b/storage/falcon/TableSpaceManager.h 2009-01-31 23:22:42 +0000
@@ -63,6 +63,7 @@ public:
void reportWrites(void);
void redoCreateTableSpace(int id, int nameLength, const char* name, int fileNameLength, const char* fileName, int type, TableSpaceInit* tsInit);
void initialize(void);
+ int createTableSpaceId();
Database *database;
TableSpace *tableSpaces;
=== modified file 'storage/falcon/Thread.cpp'
--- a/storage/falcon/Thread.cpp 2008-07-24 08:45:03 +0000
+++ b/storage/falcon/Thread.cpp 2009-01-27 17:32:40 +0000
@@ -107,7 +107,6 @@ void Thread::init(const char *desc)
activeLocks = 0;
locks = NULL;
lockPending = NULL;
- syncWait = NULL;
lockType = None;
defaultTimeZone = NULL;
javaThread = NULL;
@@ -451,12 +450,6 @@ void Thread::print(int level)
LOG_DEBUG ("%*sPending:\n", level * 2, "");
sync->print(level + 1);
}
-
- if (syncWait)
- {
- LOG_DEBUG ("%*sWaiting:\n", level * 2, "");
- syncWait->print(level + 1);
- }
}
***/
=== modified file 'storage/falcon/Thread.h'
--- a/storage/falcon/Thread.h 2008-06-11 18:24:29 +0000
+++ b/storage/falcon/Thread.h 2009-01-27 17:32:40 +0000
@@ -102,7 +102,6 @@ public:
volatile int32 activeLocks;
Sync *locks;
Sync *lockPending;
- SyncWait *syncWait;
bool marked;
int pageMarks;
int eventNumber; // for debugging
=== modified file 'storage/falcon/Transaction.cpp'
--- a/storage/falcon/Transaction.cpp 2008-11-20 17:05:50 +0000
+++ b/storage/falcon/Transaction.cpp 2009-01-09 21:49:16 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -37,6 +37,7 @@
#include "TransactionManager.h"
#include "SerialLog.h"
#include "SerialLogControl.h"
+#include "SerialLogTransaction.h"
#include "InfoTable.h"
#include "Thread.h"
#include "Format.h"
@@ -49,6 +50,10 @@
extern uint falcon_lock_wait_timeout;
+extern volatile int Talloc; // These are temporary for debug tracing
+extern volatile int Tdelete; // of number of allocated transaction objects.
+
+
static const char *stateNames [] = {
"Active",
"Limbo",
@@ -78,8 +83,8 @@ static const char THIS_FILE[]=__FILE__;
Transaction::Transaction(Connection *cnct, TransId seq)
{
- states = NULL;
- statesAllocated = 0;
+ Talloc++;
+
savePoints = NULL;
freeSavePoints = NULL;
useCount = 1;
@@ -90,7 +95,6 @@ Transaction::Transaction(Connection *cnc
syncSavepoints.setName("Transaction::syncSavepoints");
firstRecord = NULL;
lastRecord = NULL;
- dependencies = 0;
initialize(cnct, seq);
}
@@ -101,14 +105,14 @@ void Transaction::initialize(Connection*
ASSERT(savePoints == NULL);
ASSERT(freeSavePoints == NULL);
ASSERT(firstRecord == NULL);
- ASSERT(dependencies == 0);
connection = cnct;
isolationLevel = connection->isolationLevel;
mySqlThreadId = connection->mySqlThreadId;
database = connection->database;
- TransactionManager *transactionManager = database->transactionManager;
+ transactionManager = database->transactionManager;
systemTransaction = database->systemConnection == connection;
transactionId = seq;
+ commitId = 0;
chillPoint = &firstRecord;
commitTriggers = false;
hasUpdates = false;
@@ -132,7 +136,6 @@ void Transaction::initialize(Connection*
debugThawedRecords = 0;
debugThawedBytes = 0;
committedRecords = 0;
- numberStates = 0;
blockedBy = 0;
deletedRecords = 0;
inList = true;
@@ -142,7 +145,6 @@ void Transaction::initialize(Connection*
{
state = Available;
systemTransaction = false;
- oldestActive = 0;
writePending = false;
return;
@@ -158,48 +160,13 @@ void Transaction::initialize(Connection*
blockingRecord = NULL;
thread = Thread::getThread("Transaction::initialize");
syncIsActive.lock(NULL, Exclusive);
- Transaction *oldest = transactionManager->findOldest();
- oldestActive = (oldest) ? oldest->transactionId : transactionId;
- int count = transactionManager->activeTransactions.count;
-
- if (count > statesAllocated)
- {
- delete [] states;
- statesAllocated = count;
- states = new TransState[statesAllocated];
- }
-
- if (count)
- for (Transaction *transaction = transactionManager->activeTransactions.first; transaction; transaction = transaction->next)
- if (transaction->isActive() &&
- !transaction->systemTransaction &&
- transaction->transactionId < transactionId)
- {
- Sync syncDependency(&transaction->syncObject, "Transaction::initialize(2)");
- syncDependency.lock(Shared);
-
- if (transaction->isActive() &&
- !transaction->systemTransaction &&
- transaction->transactionId < transactionId)
- {
- transaction->addRef();
- INTERLOCKED_INCREMENT(transaction->dependencies);
- TransState *state = states + numberStates;
- state->transaction = transaction;
- state->transactionId = transaction->transactionId;
- state->state = transaction->state;
- ++numberStates;
- ASSERT(transaction->transactionId == state->transactionId);
- }
- }
-
state = Active;
}
Transaction::~Transaction()
{
- ASSERT(dependencies == 0);
-
+ Tdelete++;
+
if (state == Active)
{
Log::debug("Deleting apparently active transaction %d\n", transactionId);
@@ -210,9 +177,8 @@ Transaction::~Transaction()
}
if (inList)
- database->transactionManager->removeTransaction(this);
+ transactionManager->removeTransaction(this);
- delete [] states;
delete [] xid;
delete backloggedRecords;
chillPoint = &firstRecord;
@@ -244,11 +210,9 @@ void Transaction::commit()
if (!hasUpdates)
{
commitNoUpdates();
-
return;
}
- TransactionManager *transactionManager = database->transactionManager;
addRef();
Log::log(LogXARecovery, "%d: Commit %sTransaction %d\n",
database->deltaTime, (systemTransaction ? "System " : ""), transactionId);
@@ -297,9 +261,13 @@ void Transaction::commit()
}
syncRec.unlock();
- releaseDependencies();
database->flushInversion(this);
+ // Write the commit message to the serial log for durability.
+ // If a crash happens after this, the recover will commit.
+
+ database->serialLog->logControl->commit.append(this);
+
// Transfer transaction from active list to committed list, set committed state
Sync syncActiveTransactions(&transactionManager->activeTransactions.syncObject, "Transaction::commit(2)");
@@ -308,25 +276,37 @@ void Transaction::commit()
syncActiveTransactions.lock(Exclusive);
syncCommitted.lock(Exclusive);
+ // Set the commit transition id for this transaction
+
+ commitId = INTERLOCKED_INCREMENT(transactionManager->transactionSequence);
+
transactionManager->activeTransactions.remove(this);
transactionManager->committedTransactions.append(this);
state = Committed;
+ // This is one of the few points where we have an exclusive lock on both the
+ // active and committed transaction list. Although this has nothing to do
+ // with the commit of this transaction we use the opportunity to clean up
+ // old transaction objects
+
+ transactionManager->purgeTransactionsWithLocks();
+
syncCommitted.unlock();
syncActiveTransactions.unlock();
syncIsActive.unlock(); // signal waiting transactions
+
+ // signal a gopher to start processing this transaction
- database->commit(this);
+ SerialLogTransaction *srlTransaction = database->serialLog->getTransaction(transactionId);
+ srlTransaction->setState(sltCommitted);
+ database->serialLog->wakeup();
delete [] xid;
xid = NULL;
xidLength = 0;
// If there's no reason to stick around, just go away
-
- if ((dependencies == 0) && !writePending)
- commitRecords();
connection = NULL;
@@ -338,7 +318,6 @@ void Transaction::commit()
void Transaction::commitNoUpdates(void)
{
- TransactionManager *transactionManager = database->transactionManager;
addRef();
ASSERT(!deferredIndexes);
Log::log(LogXARecovery, "%d: CommitNoUpdates transaction %d\n", database->deltaTime, transactionId);
@@ -352,7 +331,6 @@ void Transaction::commitNoUpdates(void)
Sync syncActiveTransactions(&transactionManager->activeTransactions.syncObject, "Transaction::commitNoUpdates(2)");
syncActiveTransactions.lock(Shared);
- releaseDependencies();
if (xid)
{
@@ -363,10 +341,7 @@ void Transaction::commitNoUpdates(void)
Sync sync(&syncObject, "Transaction::commitNoUpdates(3)");
sync.lock(Exclusive);
-
- if (dependencies)
- transactionManager->expungeTransaction(this);
-
+
// If there's no reason to stick around, just go away
connection = NULL;
@@ -392,7 +367,6 @@ void Transaction::rollback()
releaseDeferredIndexes();
releaseSavepoints();
- TransactionManager *transactionManager = database->transactionManager;
Transaction *rollbackTransaction = transactionManager->rolledBackTransaction;
chillPoint = &firstRecord;
totalRecordData = 0;
@@ -441,13 +415,13 @@ void Transaction::rollback()
ASSERT(writePending);
writePending = false;
- releaseDependencies();
-
+
if (hasUpdates)
+ {
database->serialLog->preCommit(this);
-
- database->rollback(this);
-
+ database->serialLog->logControl->rollback.append(this);
+ }
+
if (xid)
{
delete [] xid;
@@ -458,34 +432,26 @@ void Transaction::rollback()
Sync syncActiveTransactions (&transactionManager->activeTransactions.syncObject, "Transaction::rollback(active)");
syncActiveTransactions.lock (Exclusive);
++transactionManager->rolledBack;
-
- while (dependencies)
- transactionManager->expungeTransaction(this);
-
- ASSERT(dependencies == 0);
+
inList = false;
transactionManager->activeTransactions.remove(this);
syncActiveTransactions.unlock();
state = RolledBack;
syncIsActive.unlock();
- release();
-}
+ // Finish the SerialLogTransaction and signal a gopher
-void Transaction::expungeTransaction(Transaction * transaction)
-{
- ASSERT(states != NULL || numberStates == 0);
-
- for (TransState *s = states, *end = s + numberStates; s < end; ++s)
- if (s->transaction == transaction)
- {
- if (COMPARE_EXCHANGE_POINTER(&s->transaction, transaction, NULL))
- transaction->releaseDependency();
+ if (hasUpdates)
+ {
+ SerialLogTransaction *srlTransaction = database->serialLog->getTransaction(transactionId);
+ srlTransaction->setState(sltRolledBack);
+ database->serialLog->wakeup();
+ }
- break;
- }
+ release();
}
+
void Transaction::prepare(int xidLen, const UCHAR *xidPtr)
{
if (state != Active)
@@ -504,7 +470,10 @@ void Transaction::prepare(int xidLen, co
database->pageWriter->waitForWrites(this);
state = Limbo;
- database->dbb->prepareTransaction(transactionId, xidLength, xid);
+
+ // Flush a prepare record to the serial log
+
+ database->serialLog->logControl->prepare.append(transactionId, xidLength, xid);
Sync sync(&syncDeferredIndexes, "Transaction::prepare");
sync.lock(Shared);
@@ -567,7 +536,7 @@ int Transaction::thaw(RecordVersion * re
// Nothing to do if record is no longer chilled
if (record->state != recChilled)
- return record->size;
+ return record->getDataMemUsage();
// Get pointer to record data in serial log
@@ -745,17 +714,12 @@ bool Transaction::visible(Transaction *
// This is REPEATABLE_READ
ASSERT (IS_REPEATABLE_READ(isolationLevel));
- // If the transaction started after we did, consider the transaction active
+ // If the other transaction committed after we started then it is not
+ // be visible to us
- if (transId > transactionId)
+ if (transaction->commitId > transactionId)
return false;
- // If the transaction was active when we started, use it's state at that point
-
- for (int n = 0; n < numberStates; ++n)
- if (states [n].transactionId == transId)
- return false;
-
return true;
}
@@ -790,26 +754,6 @@ bool Transaction::needToLock(Record* rec
return false;
}
-void Transaction::releaseDependencies()
-{
- if (!numberStates)
- return;
-
- for (TransState *state = states, *end = states + numberStates; state < end; ++state)
- {
- Transaction *transaction = state->transaction;
-
- if (transaction)
- {
- if (COMPARE_EXCHANGE_POINTER(&state->transaction, transaction, NULL))
- {
- ASSERT(transaction->transactionId == state->transactionId || transaction->transactionId == 0);
- ASSERT(transaction->state != Initializing);
- transaction->releaseDependency();
- }
- }
- }
-}
/*
* Transaction is fully mature and about to go away.
@@ -852,6 +796,14 @@ void Transaction::commitRecords()
State Transaction::getRelativeState(Record* record, uint32 flags)
{
+ // If this is a Record object it has no assosiated transaction
+ // and is always visible
+
+ if (!record->isVersion())
+ {
+ return CommittedVisible;
+ }
+
blockingRecord = record;
State state = getRelativeState(record->getTransaction(), record->getTransactionId(), flags);
blockingRecord = NULL;
@@ -877,17 +829,14 @@ State Transaction::getRelativeState(Tran
if (IS_CONSISTENT_READ(isolationLevel))
{
- // If the transaction is no longer around, and the record is,
- // then it must be committed.
+ // Be sure that transaction was not active when we started.
+ // If the transaction is no longer connected to the record,
+ // then it must be committed. The scavenger can scavenge
+ // transactions newer than the oldest active if they are
+ // committed.
if (transactionId < transId)
return CommittedInvisible;
-
- // Be sure it was not active when we started.
-
- for (int n = 0; n < numberStates; ++n)
- if (states [n].transactionId == transId)
- return CommittedInvisible;
}
return CommittedVisible;
@@ -962,9 +911,6 @@ void Transaction::writeComplete(void)
ASSERT(writePending);
ASSERT(state == Committed);
releaseDeferredIndexes();
-
- if (dependencies == 0)
- commitRecords();
// Log::log(LogXARecovery, "%d: WriteComplete %sTransaction %d\n",
// database->deltaTime, (systemTransaction ? "System " : ""), transactionId);
@@ -1001,7 +947,6 @@ State Transaction::waitForTransaction(Tr
if(transaction)
transaction->addRef();
- TransactionManager *transactionManager = database->transactionManager;
Sync syncActiveTransactions(&transactionManager->activeTransactions.syncObject,
"Transaction::waitForTransaction(1)");
syncActiveTransactions.lock(Shared);
@@ -1177,7 +1122,7 @@ void Transaction::releaseSavepoint(int s
for (RecordVersion *record = *savePoint->records; record && record->savePointId == savePointId; record = record->nextInTrans)
{
record->savePointId = nextLowerSavePointId;
- record->scavenge(transactionId, nextLowerSavePointId);
+ record->scavengeSavepoint(transactionId, nextLowerSavePointId);
}
savePoint->next = freeSavePoints;
@@ -1371,9 +1316,9 @@ void Transaction::releaseRecordLocks(voi
void Transaction::print(void)
{
- Log::debug(" %p Id %d, state %d, updates %d, wrtPend %d, states %d, dependencies %d, records %d\n",
+ Log::debug(" %p Id %d, state %d, updates %d, wrtPend %d, records %d\n",
this, transactionId, state, hasUpdates, writePending,
- numberStates, dependencies, firstRecord != NULL);
+ firstRecord != NULL);
}
void Transaction::printBlocking(int level)
@@ -1434,12 +1379,17 @@ void Transaction::printBlocking(int leve
what);
}
syncRec.unlock();
- database->transactionManager->printBlocking(this, level);
+ transactionManager->printBlocking(this, level);
}
void Transaction::getInfo(InfoTable* infoTable)
{
- if (!(state == Available && dependencies == 0))
+ // NOTE: The field for number of dependencies will be removed in
+ // a follow-up patch.
+ // Need to decide if we want to include the startEvent and endEvent
+ // in this table.
+
+ if (!(state == Available))
{
int n = 0;
infoTable->putString(n++, stateNames[state]);
@@ -1447,8 +1397,8 @@ void Transaction::getInfo(InfoTable* inf
infoTable->putInt(n++, transactionId);
infoTable->putInt(n++, hasUpdates);
infoTable->putInt(n++, writePending);
- infoTable->putInt(n++, dependencies);
- infoTable->putInt(n++, oldestActive);
+ infoTable->putInt(n++, 0); // Number of dependencies, will be removed
+ infoTable->putInt(n++, 0); // was oldestActive);
infoTable->putInt(n++, firstRecord != NULL);
infoTable->putInt(n++, (waitingFor) ? waitingFor->transactionId : 0);
@@ -1464,23 +1414,15 @@ void Transaction::getInfo(InfoTable* inf
}
}
-void Transaction::releaseDependency(void)
-{
- ASSERT(useCount >= 2);
- ASSERT(dependencies > 0);
- INTERLOCKED_DECREMENT(dependencies);
-
- if ((dependencies == 0) && !writePending && firstRecord)
- commitRecords();
- releaseCommittedTransaction();
-}
+// Called by the gopher thread to complete this transaction
void Transaction::fullyCommitted(void)
{
ASSERT(inList);
+ ASSERT(!isActive());
if (useCount < 2)
- Log::debug("Transaction::fullyCommitted: funny use count\n");
+ Log::debug("Transaction::fullyCommitted: Unusual use count=%d\n", useCount);
writeComplete();
releaseCommittedTransaction();
@@ -1488,26 +1430,16 @@ void Transaction::fullyCommitted(void)
void Transaction::releaseCommittedTransaction(void)
{
- release();
+ // NOTE: consider to just move the call to release() to where this method is called.
+ // Leave it in here in case we want to check for being able to delete the transaction
+ // object here.
- if ((useCount == 1) && (state == Committed) && (dependencies == 0) && !writePending)
- if (COMPARE_EXCHANGE(&inList, (INTERLOCK_TYPE) true, (INTERLOCK_TYPE) false))
- database->transactionManager->removeCommittedTransaction(this);
+ release();
}
-void Transaction::validateDependencies(bool noDependencies)
-{
- for (TransState *state = states, *end = states + numberStates; state < end; ++state)
- if (state->transaction)
- {
- ASSERT(!noDependencies);
- ASSERT(state->transaction->transactionId == state->transactionId);
- }
-}
void Transaction::printBlockage(void)
{
- TransactionManager *transactionManager = database->transactionManager;
LogLock logLock;
Sync sync (&transactionManager->activeTransactions.syncObject, "Transaction::printBlockage");
sync.lock (Shared);
@@ -1593,3 +1525,12 @@ void Transaction::validateRecords(void)
ASSERT(firstRecord == record);
}
+
+// Return true if this transaction was committed before
+// another transaction started. If commitId is 0, then
+// this trans is not yet committed.
+
+bool Transaction::committedBefore(TransId transactionId)
+{
+ return (commitId && commitId < transactionId);
+}
=== modified file 'storage/falcon/Transaction.h'
--- a/storage/falcon/Transaction.h 2008-10-02 23:20:47 +0000
+++ b/storage/falcon/Transaction.h 2009-01-08 09:05:26 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -42,6 +42,7 @@ class Bitmap;
class Record;
class InfoTable;
class Thread;
+class TransactionManager;
// Transaction States
@@ -90,9 +91,7 @@ public:
void removeRecordNoLock (RecordVersion *record);
void removeRecord(RecordVersion *record);
void removeRecord (RecordVersion *record, RecordVersion **ptr);
- void expungeTransaction (Transaction *transaction);
void commitRecords();
- void releaseDependencies();
bool visible (Transaction *transaction, TransId transId, int forWhat);
bool needToLock(Record* record);
void addRecord (RecordVersion *record);
@@ -108,12 +107,10 @@ public:
void truncateTable(Table* table);
bool hasRecords(Table* table);
void writeComplete(void);
- void releaseDependency(void);
int createSavepoint();
void releaseSavepoint(int savepointId);
void releaseSavepoints(void);
void rollbackSavepoint (int savepointId);
- void scavengeRecords(int ageGroup);
void add(DeferredIndex* deferredIndex);
void initialize(Connection* cnct, TransId seq);
bool isXidEqual(int testLength, const UCHAR* test);
@@ -127,12 +124,13 @@ public:
void fullyCommitted(void);
void releaseCommittedTransaction(void);
void commitNoUpdates(void);
- void validateDependencies(bool noDependencies);
void validateRecords(void);
void printBlocking(int level);
void releaseDeferredIndexes(void);
void releaseDeferredIndexes(Table* table);
void backlogRecords(void);
+ bool committedBefore(TransId transactionId);
+
inline bool isActive()
{
@@ -141,8 +139,9 @@ public:
Connection *connection;
Database *database;
- TransId transactionId;
- TransId oldestActive;
+ TransactionManager *transactionManager;
+ TransId transactionId; // used also as startEvent by dep.mgr.
+ TransId commitId; // used as commitEvent by dep.mgr.
TransId blockedBy;
int curSavePointId;
Transaction *next; // next in database
@@ -157,12 +156,10 @@ public:
Bitmap *backloggedRecords;
time_t startTime;
int deferredIndexCount;
- int statesAllocated;
int isolationLevel;
int xidLength;
int mySqlThreadId;
UCHAR *xid;
- TransState *states;
bool commitTriggers;
bool systemTransaction;
bool hasUpdates;
@@ -187,9 +184,7 @@ public:
RecordVersion **chillPoint; // points to a pointer to the first non-chilled record
int scanIndexCount;
- volatile int numberStates;
volatile INTERLOCK_TYPE state;
- volatile INTERLOCK_TYPE dependencies;
volatile INTERLOCK_TYPE useCount;
volatile INTERLOCK_TYPE inList;
=== modified file 'storage/falcon/TransactionManager.cpp'
--- a/storage/falcon/TransactionManager.cpp 2008-10-24 10:20:10 +0000
+++ b/storage/falcon/TransactionManager.cpp 2009-02-05 13:01:41 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -15,6 +15,7 @@
#include <memory.h>
+#include <limits.h>
#include "Engine.h"
#include "TransactionManager.h"
#include "Transaction.h"
@@ -36,6 +37,9 @@ static const int EXTRA_TRANSACTIONS = 10
static const char THIS_FILE[]=__FILE__;
#endif
+volatile int Talloc = 0; // Temp. will be removed. Used for tracing
+volatile int Tdelete = 0; // new and delete of trans objects.
+
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
@@ -70,80 +74,64 @@ TransactionManager::~TransactionManager(
}
}
-TransId TransactionManager::findOldestActive()
+TransId TransactionManager::findOldestInActiveList() const
{
- Sync syncCommitted(&committedTransactions.syncObject, "TransactionManager::findOldestActive(1)");
- syncCommitted.lock(Shared);
- TransId oldestCommitted = transactionSequence;
-
- for (Transaction *trans = committedTransactions.first; trans; trans = trans->next)
- oldestCommitted = MIN(trans->transactionId, oldestCommitted);
+ // Find the transaction id of the oldest active transaction in the
+ // active transaction list. If the list is empty, the
+ // latest allocated transaction id will be returned.
+ // This method assumes that the caller has set at least a shared lock
+ // on the active list.
- syncCommitted.unlock();
-
- Transaction *oldest = findOldest();
-
- if (oldest)
- {
- //Log::debug("Oldest transaction %d, oldest ancestor %d, oldest committed %d\n", oldest->transactionId, oldest->oldestActive, oldestCommitted);
+ // Note: Here we operate on a transaction list where we allow
+ // non-locking transaction allocations and de-allocations from,
+ // so be careful when updating this method.
- return MIN(oldest->oldestActive, oldestCommitted);
- }
-
- //Log::debug("No active, current %d, oldest committed %d\n", transactionSequence, oldestActive);
-
- return oldestCommitted;
-}
+ // NOTE: This needs to be updated when we allow transaction id to wrap
-Transaction* TransactionManager::findOldest(void)
-{
- Sync sync (&activeTransactions.syncObject, "TransactionManager::findOldest");
- sync.lock (Shared);
- Transaction *oldest = NULL;
+ TransId oldest = transactionSequence;
for (Transaction *transaction = activeTransactions.first; transaction; transaction = transaction->next)
- if (transaction->isActive() && (!oldest || transaction->transactionId < oldest->transactionId))
- oldest = transaction;
+ {
+ TransId transId = transaction->transactionId;
+ if (transaction->isActive() && (transId != 0 && transId < oldest))
+ oldest = transId;
+ }
return oldest;
}
+
Transaction* TransactionManager::startTransaction(Connection* connection)
{
+ // Go through the active transaction list to check if there are any
+ // transaction objects in state "Available" that can be re-used.
+ // Note that this is done using a shared lock on the active transaction
+ // list.
+
Sync sync (&activeTransactions.syncObject, "TransactionManager::startTransaction");
- sync.lock (Shared);
+ sync.lock(Shared);
Transaction *transaction;
- for (transaction = activeTransactions.first; transaction; transaction = transaction->next)
- if (transaction->state == Available && transaction->dependencies == 0)
+ for(transaction = activeTransactions.first; transaction; transaction = transaction->next)
+ if (transaction->state == Available)
if (COMPARE_EXCHANGE(&transaction->state, Available, Initializing))
{
- // Check again that the dependencies are zero. The transaction
- // object might have been re-use between the previous if-test
- // and the actual change of state
-
- if (transaction->dependencies != 0)
- {
- // Return the transaction object back to the list
-
- transaction->state = Available;
- }
- else
- {
- ASSERT(transaction->dependencies == 0);
- transaction->initialize(connection, INTERLOCKED_INCREMENT(transactionSequence));
-
- return transaction;
- }
+ transaction->initialize(connection, INTERLOCKED_INCREMENT(transactionSequence));
+ return transaction;
}
sync.unlock();
+
+ // We did not find an available transaction object to re-use,
+ // so we allocate a new one and add it to the active list
+
sync.lock(Exclusive);
- transaction = new Transaction (connection, INTERLOCKED_INCREMENT(transactionSequence));
+ transaction = new Transaction(connection, INTERLOCKED_INCREMENT(transactionSequence));
activeTransactions.append(transaction);
- // And, just for yucks, add another 10 Available transactions
+ // Since we have acquired the exclusive lock on the active transaction
+ // list we allocate some extra transaction objects for future use
for (int n = 0; n < EXTRA_TRANSACTIONS; ++n)
{
@@ -302,30 +290,63 @@ void TransactionManager::getTransactionI
void TransactionManager::purgeTransactions()
{
+ // This method is called by the scavenger to clean up old committed
+ // transactions.
+
+ // To purge the committed transaction list requires at least
+ // a shared lock on the active transaction list and an exclusive
+ // lock on the committed transaction list
+
+ Sync syncActive(&activeTransactions.syncObject, "TransactionManager::purgeTransaction");
+ syncActive.lock(Shared);
+
Sync syncCommitted(&committedTransactions.syncObject, "Transaction::purgeTransactions");
syncCommitted.lock(Exclusive);
-
+
+ purgeTransactionsWithLocks();
+}
+
+
+void TransactionManager::purgeTransactionsWithLocks()
+{
+ // Removes old committed transaction from the committed transaction list
+ // that no longer is visible by any currently active transactions.
+ // Note that this method relies on that the caller have at least a
+ // shared lock on the active transaction list and an exclusive lock on
+ // the committed transaction list
+
+ // Find the transaction id of the oldest active transaction
+
+ TransId oldestActive = findOldestInActiveList();
+
// Check for any fully mature transactions to ditch
-
- for (Transaction *transaction, *next = committedTransactions.first; (transaction = next);)
+
+ Transaction* transaction = committedTransactions.first;
+
+ while ((transaction != NULL) &&
+ (transaction->state == Committed) &&
+ (transaction->commitId < oldestActive) &&
+ !transaction->writePending)
{
- next = transaction->next;
+ transaction->commitRecords();
- if ((transaction->state == Committed) &&
- (transaction->dependencies == 0) &&
- !transaction->writePending)
+ if (COMPARE_EXCHANGE(&transaction->inList, (INTERLOCK_TYPE) true, (INTERLOCK_TYPE) false))
+ {
+ committedTransactions.remove(transaction);
+ transaction->release();
+ }
+ else
{
- transaction->commitRecords();
+ // If the compare and exchange operation failed we re-try this transaction on the next call
- if (COMPARE_EXCHANGE(&transaction->inList, (INTERLOCK_TYPE) true, (INTERLOCK_TYPE) false))
- {
- committedTransactions.remove(transaction);
- transaction->release();
- }
+ break;
}
+
+ transaction = committedTransactions.first;
}
}
+
void TransactionManager::getSummaryInfo(InfoTable* infoTable)
{
Sync syncActive (&activeTransactions.syncObject, "TransactionManager::getSummaryInfo(2)");
@@ -374,7 +395,6 @@ void TransactionManager::reportStatistic
Transaction *transaction;
int active = 0;
int available = 0;
- int dependencies = 0;
time_t maxTime = 0;
for (transaction = activeTransactions.first; transaction; transaction = transaction->next)
@@ -387,9 +407,6 @@ void TransactionManager::reportStatistic
else if (transaction->state == Available)
{
++available;
-
- if (transaction->dependencies)
- ++dependencies;
}
int pendingCleanup = committedTransactions.count;
@@ -399,8 +416,8 @@ void TransactionManager::reportStatistic
priorRolledBack = rolledBack;
if ((active || numberCommitted || numberRolledBack) && Log::isActive(LogInfo))
- Log::log (LogInfo, "%d: Transactions: %d committed, %d rolled back, %d active, %d/%d available, %d post-commit, oldest %d seconds\n",
- database->deltaTime, numberCommitted, numberRolledBack, active, available, dependencies, pendingCleanup, maxTime);
+ Log::log (LogInfo, "%d: Transactions: %d committed, %d rolled back, %d active, %d available, %d post-commit, oldest %d seconds\n",
+ database->deltaTime, numberCommitted, numberRolledBack, active, available, pendingCleanup, maxTime);
}
void TransactionManager::removeCommittedTransaction(Transaction* transaction)
@@ -412,16 +429,6 @@ void TransactionManager::removeCommitted
transaction->release();
}
-void TransactionManager::expungeTransaction(Transaction *transaction)
-{
- Sync syncActiveTrans(&activeTransactions.syncObject, "TransactionManager::removeTransaction");
- syncActiveTrans.lock(Shared);
-
- for (Transaction *trans = activeTransactions.first; trans; trans = trans->next)
- if ((trans->state != Available && trans->state != Initializing))
- //&& trans->transactionId > transaction->transactionId)
- trans->expungeTransaction(transaction);
-}
Transaction* TransactionManager::findTransaction(TransId transactionId)
{
@@ -445,24 +452,6 @@ Transaction* TransactionManager::findTra
return NULL;
}
-void TransactionManager::validateDependencies(void)
-{
- Sync syncActive(&activeTransactions.syncObject, "TransactionManager::validateDepedendencies(1)");
- syncActive.lock(Shared);
- Transaction *transaction;
-
- for (transaction = activeTransactions.first; transaction; transaction = transaction->next)
- if (transaction->isActive())
- transaction->validateDependencies(false);
-
- syncActive.unlock();
-
- Sync syncCommitted(&committedTransactions.syncObject, "TransactionManager::validateDepedendencies(2)");
- syncCommitted.lock(Shared);
-
- for (transaction = committedTransactions.first; transaction; transaction = transaction->next)
- transaction->validateDependencies(true);
-}
void TransactionManager::removeTransaction(Transaction* transaction)
{
=== modified file 'storage/falcon/TransactionManager.h'
--- a/storage/falcon/TransactionManager.h 2008-08-11 13:22:53 +0000
+++ b/storage/falcon/TransactionManager.h 2009-01-07 08:12:08 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -30,7 +30,6 @@ public:
TransactionManager(Database *database);
~TransactionManager(void);
- TransId findOldestActive();
Transaction* startTransaction(Connection* connection);
void dropTable(Table* table, Transaction* transaction);
void truncateTable(Table* table, Transaction* transaction);
@@ -39,14 +38,13 @@ public:
void commitByXid(int xidLength, const UCHAR* xid);
void rollbackByXid(int xidLength, const UCHAR* xid);
void print(void);
- Transaction* findOldest(void);
+ TransId findOldestInActiveList() const;
void getTransactionInfo(InfoTable* infoTable);
void purgeTransactions();
+ void purgeTransactionsWithLocks();
void getSummaryInfo(InfoTable* infoTable);
void reportStatistics(void);
- void expungeTransaction(Transaction *transaction);
Transaction* findTransaction(TransId transactionId);
- void validateDependencies(void);
void removeCommittedTransaction(Transaction* transaction);
void removeTransaction(Transaction* transaction);
void printBlockage(void);
=== modified file 'storage/falcon/ha_falcon.cpp'
--- a/storage/falcon/ha_falcon.cpp 2009-02-03 09:16:53 +0000
+++ b/storage/falcon/ha_falcon.cpp 2009-02-05 09:00:35 +0000
@@ -179,6 +179,18 @@ bool checkExceptionSupport()
return false;
}
+// Init/term routines for THR_LOCK, used within StorageTableShare.
+void falcon_lock_init(void *lock)
+{
+ thr_lock_init((THR_LOCK *)lock);
+}
+
+
+void falcon_lock_deinit(void *lock)
+{
+ thr_lock_delete((THR_LOCK *)lock);
+}
+
int StorageInterface::falcon_init(void *p)
{
DBUG_ENTER("falcon_init");
@@ -520,7 +532,6 @@ int StorageInterface::open(const char *n
if (!storageShare->initialized)
{
- thr_lock_init((THR_LOCK *)storageShare->impure);
storageShare->setTablePath(name, tempTable);
storageShare->initialized = true;
}
@@ -553,15 +564,15 @@ int StorageInterface::open(const char *n
thr_lock_data_init((THR_LOCK *)storageShare->impure, &lockData, NULL);
- if (table)
- mapFields(table);
+ // Map fields for Falcon record encoding
+
+ mapFields(table);
+
+ // Map server indexes to Falcon internal indexes
setIndexes(table);
- if (ret)
- DBUG_RETURN(error(ret));
-
- DBUG_RETURN(0);
+ DBUG_RETURN(error(ret));
}
@@ -859,7 +870,16 @@ int StorageInterface::create(const char
tableSpace = TEMPORARY_TABLESPACE;
}
else if (info->tablespace)
- tableSpace = info->tablespace;
+ {
+ if (!strcasecmp(info->tablespace, TEMPORARY_TABLESPACE))
+ {
+ my_printf_error(ER_ILLEGAL_HA_CREATE_OPTION,
+ "Cannot create non-temporary table '%s' in '%s' tablespace.", MYF(0), tableName, TEMPORARY_TABLESPACE);
+ storageTable->deleteTable();
+ DBUG_RETURN(HA_WRONG_CREATE_OPTION);
+ }
+ tableSpace = storageTable->getTableSpaceName();
+ }
else
tableSpace = DEFAULT_TABLESPACE;
@@ -884,8 +904,12 @@ int StorageInterface::create(const char
DBUG_RETURN(error(ret));
}
+ // Map fields for Falcon record encoding
+
mapFields(form);
+ // Map server indexes to Falcon indexes
+
setIndexes(table);
DBUG_RETURN(0);
@@ -899,25 +923,39 @@ int StorageInterface::add_index(TABLE* t
DBUG_RETURN(ret);
}
-int StorageInterface::createIndex(const char *schemaName, const char *tableName, TABLE *table, int indexId)
+int StorageInterface::createIndex(const char *schemaName, const char *tableName, TABLE *srvTable, int indexId)
{
- KEY *key = table->key_info + indexId;
+ int ret = 0;
+ CmdGen gen;
StorageIndexDesc indexDesc;
- getKeyDesc(table, indexId, &indexDesc);
+ getKeyDesc(srvTable, indexId, &indexDesc);
- CmdGen gen;
- const char *unique = (key->flags & HA_NOSAME) ? "unique " : "";
- gen.gen("create %sindex \"%s\" on %s.\"%s\" ", unique, indexDesc.name, schemaName, tableName);
- genKeyFields(key, &gen);
- const char *sql = gen.getString();
+ if (indexDesc.primaryKey)
+ {
+ int64 incrementValue = 0;
+ genTable(srvTable, &gen);
+
+ // Primary keys are a special case, so use upgrade()
+
+ ret = storageTable->upgrade(gen.getString(), incrementValue);
+ }
+ else
+ {
+ KEY *key = srvTable->key_info + indexId;
+ const char *unique = (key->flags & HA_NOSAME) ? "unique " : "";
+ gen.gen("create %sindex \"%s\" on %s.\"%s\" ", unique, indexDesc.name, schemaName, tableName);
+ genKeyFields(key, &gen);
+
+ ret = storageTable->createIndex(&indexDesc, gen.getString());
+ }
- return storageTable->createIndex(&indexDesc, sql);
+ return ret;
}
-int StorageInterface::dropIndex(const char *schemaName, const char *tableName, TABLE *table, int indexId, bool online)
+int StorageInterface::dropIndex(const char *schemaName, const char *tableName, TABLE *srvTable, int indexId, bool online)
{
StorageIndexDesc indexDesc;
- getKeyDesc(table, indexId, &indexDesc);
+ getKeyDesc(srvTable, indexId, &indexDesc);
CmdGen gen;
gen.gen("drop index %s.\"%s\"", schemaName, indexDesc.name);
@@ -1022,12 +1060,7 @@ int StorageInterface::delete_table(const
storageShare->lockIndexes(true);
storageShare->lock(true);
- if (storageShare->initialized)
- {
- thr_lock_delete((THR_LOCK*) storageShare->impure);
- storageShare->initialized = false;
- //DBUG_ASSERT(false);
- }
+ storageShare->initialized = false;
storageShare->unlock();
storageShare->unlockIndexes();
@@ -1378,9 +1411,14 @@ int StorageInterface::index_read(uchar *
enum ha_rkey_function find_flag)
{
DBUG_ENTER("StorageInterface::index_read");
- int ret, which = 0;
+ int which = 0;
ha_statistic_increment(&SSV::ha_read_key_count);
+ int ret = storageTable->checkCurrentIndex();
+
+ if (ret)
+ DBUG_RETURN(error(ret));
+
// XXX This needs to be revisited
switch(find_flag)
{
@@ -1446,22 +1484,34 @@ int StorageInterface::index_init(uint id
nextRecord = 0;
haveStartKey = false;
haveEndKey = false;
- int ret = 0;
- ret = storageTable->setCurrentIndex(idx);
+ // Get and hold a shared lock on StorageTableShare::indexes, then set
+ // the corresponding Falcon index for use on the current thread
+
+ int ret = storageTable->setCurrentIndex(idx);
+ // If the index is not found, remap the index and try again
+
if (ret)
{
- setIndex(table, idx);
+ storageShare->lockIndexes(true);
+ remapIndexes(table);
+ storageShare->unlockIndexes();
+
ret = storageTable->setCurrentIndex(idx);
- }
- // validateIndexes(table);
+ // Online ALTER allows access to partially deleted indexes, so
+ // fail silently for now to avoid fatal assert in server.
+ //
+ // TODO: Restore error when server imposes DDL lock across the
+ // three phases of online ALTER.
- if (ret)
- DBUG_RETURN(error(ret));
-
- DBUG_RETURN(ret);
+ if (ret)
+ //DBUG_RETURN(error(ret));
+ DBUG_RETURN(error(0));
+ }
+
+ DBUG_RETURN(error(ret));
}
int StorageInterface::index_end(void)
@@ -1516,15 +1566,15 @@ ha_rows StorageInterface::records_in_ran
DBUG_RETURN(MAX(guestimate, 2));
}
-void StorageInterface::getKeyDesc(TABLE *table, int indexId, StorageIndexDesc *indexDesc)
+void StorageInterface::getKeyDesc(TABLE *srvTable, int indexId, StorageIndexDesc *indexDesc)
{
- KEY *keyInfo = table->key_info + indexId;
+ KEY *keyInfo = srvTable->key_info + indexId;
int numberKeys = keyInfo->key_parts;
indexDesc->id = indexId;
indexDesc->numberSegments = numberKeys;
indexDesc->unique = (keyInfo->flags & HA_NOSAME);
- indexDesc->primaryKey = (table->s->primary_key == (uint)indexId);
+ indexDesc->primaryKey = (srvTable->s->primary_key == (uint)indexId);
// Clean up the index name for internal use
@@ -1541,21 +1591,104 @@ void StorageInterface::getKeyDesc(TABLE
segment->length = part->length;
segment->type = part->field->key_type();
segment->nullBit = part->null_bit;
- segment->isUnsigned = (part->field->flags & ENUM_FLAG) ?
- true : ((Field_num*) part->field)->unsigned_flag;
+ segment->mysql_charset = NULL;
+ // Separate correctly between types that may map to
+ // the same key type, but that should be treated differently.
+ // This way StorageInterface::getSegmentValue only have
+ // to switch on the keyFormat, and the logic needed at runtime
+ // is minimal.
+ // Also set the correct charset where appropriate.
switch (segment->type)
{
- case HA_KEYTYPE_TEXT:
- case HA_KEYTYPE_VARTEXT1:
- case HA_KEYTYPE_VARTEXT2:
+ case HA_KEYTYPE_LONG_INT:
+ segment->keyFormat = KEY_FORMAT_LONG_INT;
+ break;
+
+ case HA_KEYTYPE_SHORT_INT:
+ segment->keyFormat = KEY_FORMAT_SHORT_INT;
+ break;
+
+ case HA_KEYTYPE_ULONGLONG:
+ segment->keyFormat = KEY_FORMAT_ULONGLONG;
+ break;
+
+ case HA_KEYTYPE_LONGLONG:
+ segment->keyFormat = KEY_FORMAT_LONGLONG;
+ break;
+
+ case HA_KEYTYPE_FLOAT:
+ segment->keyFormat = KEY_FORMAT_FLOAT;
+ break;
+
+ case HA_KEYTYPE_DOUBLE:
+ segment->keyFormat = KEY_FORMAT_DOUBLE;
+ break;
+
case HA_KEYTYPE_VARBINARY1:
case HA_KEYTYPE_VARBINARY2:
+ segment->keyFormat = KEY_FORMAT_VARBINARY;
segment->mysql_charset = part->field->charset();
break;
+ case HA_KEYTYPE_VARTEXT1:
+ case HA_KEYTYPE_VARTEXT2:
+ segment->keyFormat = KEY_FORMAT_VARTEXT;
+ segment->mysql_charset = part->field->charset();
+ break;
+
+ case HA_KEYTYPE_BINARY:
+ switch (part->field->real_type())
+ {
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_DATETIME:
+ segment->keyFormat = KEY_FORMAT_BINARY_INTEGER;
+ break;
+
+ case MYSQL_TYPE_NEWDECIMAL:
+ segment->keyFormat = KEY_FORMAT_BINARY_NEWDECIMAL;
+ break;
+
+ default:
+ segment->keyFormat = KEY_FORMAT_BINARY_STRING;
+ break;
+ }
+ break;
+
+ case HA_KEYTYPE_TEXT:
+ segment->keyFormat = KEY_FORMAT_TEXT;
+ segment->mysql_charset = part->field->charset();
+ break;
+
+ case HA_KEYTYPE_ULONG_INT:
+ if (part->field->real_type() == MYSQL_TYPE_TIMESTAMP)
+ segment->keyFormat = KEY_FORMAT_TIMESTAMP;
+ else
+ segment->keyFormat = KEY_FORMAT_ULONG_INT;
+ break;
+
+ case HA_KEYTYPE_INT8:
+ segment->keyFormat = KEY_FORMAT_INT8;
+ break;
+
+ case HA_KEYTYPE_USHORT_INT:
+ segment->keyFormat = KEY_FORMAT_USHORT_INT;
+ break;
+
+ case HA_KEYTYPE_UINT24:
+ segment->keyFormat = KEY_FORMAT_UINT24;
+ break;
+
+ case HA_KEYTYPE_INT24:
+ segment->keyFormat = KEY_FORMAT_INT24;
+ break;
+
default:
- segment->mysql_charset = NULL;
+ segment->keyFormat = KEY_FORMAT_OTHER;
}
}
}
@@ -1576,16 +1709,12 @@ int StorageInterface::rename_table(const
ret = storageShare->renameTable(storageConnection, to);
- if (!ret)
- remapIndexes(table);
+ remapIndexes(table);
storageShare->unlock();
storageShare->unlockIndexes();
- if (ret)
- DBUG_RETURN(error(ret));
-
- DBUG_RETURN(ret);
+ DBUG_RETURN(error(ret));
}
double StorageInterface::read_time(uint index, uint ranges, ha_rows rows)
@@ -1605,20 +1734,15 @@ int StorageInterface::read_range_first(c
if ((res= scanRange(start_key, end_key, eq_range_arg)))
DBUG_RETURN(res);
- for (;;)
- {
- int result = index_next(table->record[0]);
-
- if (result)
- {
- if (result == HA_ERR_KEY_NOT_FOUND)
- result = HA_ERR_END_OF_FILE;
+ int result = index_next(table->record[0]);
- table->status = result;
- DBUG_RETURN(result);
- }
+ if (result)
+ {
+ if (result == HA_ERR_KEY_NOT_FOUND)
+ result = HA_ERR_END_OF_FILE;
- DBUG_RETURN(0);
+ table->status = result;
+ DBUG_RETURN(result);
}
DBUG_RETURN(0);
@@ -1633,8 +1757,12 @@ int StorageInterface::scanRange(const ke
haveStartKey = false;
haveEndKey = false;
storageTable->upperBound = storageTable->lowerBound = NULL;
- int ret = 0;
+ int ret = storageTable->checkCurrentIndex();
+
+ if (ret)
+ DBUG_RETURN(error(ret));
+
if (start_key && !storageTable->isKeyNull((const unsigned char*) start_key->key, start_key->length))
{
haveStartKey = true;
@@ -1645,7 +1773,7 @@ int StorageInterface::scanRange(const ke
else if (start_key->flag == HA_READ_AFTER_KEY)
storageTable->setReadAfterKey();
- int ret = storageTable->setIndexBound((const unsigned char*) start_key->key,
+ ret = storageTable->setIndexBound((const unsigned char*) start_key->key,
start_key->length, LowerBound);
if (ret)
DBUG_RETURN(error(ret));
@@ -1698,6 +1826,11 @@ int StorageInterface::index_next(uchar *
if (activeBlobs)
freeActiveBlobs();
+ int ret = storageTable->checkCurrentIndex();
+
+ if (ret)
+ DBUG_RETURN(error(ret));
+
for (;;)
{
lastRecord = storageTable->nextIndexed(nextRecord, lockForUpdate);
@@ -1821,7 +1954,7 @@ int StorageInterface::fillMrrBitmap()
startKey = mrr_cur_range.start_key.keypart_map? &mrr_cur_range.start_key: NULL;
endKey = mrr_cur_range.end_key.keypart_map? &mrr_cur_range.end_key: NULL;
if ((res = scanRange(startKey, endKey, test(mrr_cur_range.range_flag & EQ_RANGE))))
- return res;
+ DBUG_RETURN(res);
}
DBUG_RETURN(0);
}
@@ -2236,7 +2369,8 @@ int StorageInterface::alter_tablespace(h
{
DBUG_ENTER("NfsStorageEngine::alter_tablespace");
int ret = 0;
-
+ const char *data_file_name= ts_info->data_file_name;
+ char buff[FN_REFLEN];
/*
CREATE TABLESPACE tablespace
ADD DATAFILE 'file'
@@ -2256,28 +2390,30 @@ int StorageInterface::alter_tablespace(h
for NDB only.
*/
- /*
- Sergey Vojtovich is to reconsider this code
-
- if (ts_info->data_file_name)
+ if (data_file_name)
{
- char buff[FN_REFLEN];
- size_t dirname_part_length;
- dirname_part(buff, ts_info->data_file_name, &dirname_part_length);
- fn_format(buff, buff, mysql_real_data_home, "",
- MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
- if (test_if_data_home_dir(buff))
+ size_t length= strlen(data_file_name);
+ if (length <= 4 || strcmp(data_file_name + length - 4, ".fts"))
{
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "DATAFILE");
- DBUG_RETURN(1);
+ if (!length || length > FN_REFLEN - 5)
+ {
+ my_error(ER_BAD_PATH, MYF(0), data_file_name);
+ DBUG_RETURN(1);
+ }
+ memcpy(buff, data_file_name, length);
+ buff[length]= '.';
+ buff[length + 1]= 'f';
+ buff[length + 2]= 't';
+ buff[length + 3]= 's';
+ buff[length + 4]= '\0';
+ data_file_name= buff;
}
}
- */
switch (ts_info->ts_cmd_type)
{
case CREATE_TABLESPACE:
- ret = storageHandler->createTablespace( ts_info->tablespace_name, ts_info->data_file_name, ts_info->ts_comment);
+ ret = storageHandler->createTablespace( ts_info->tablespace_name, data_file_name, ts_info->ts_comment);
break;
case DROP_TABLESPACE:
@@ -2319,9 +2455,9 @@ int StorageInterface::check_if_supported
DBUG_ENTER("StorageInterface::check_if_supported_alter");
tempTable = (create_info->options & HA_LEX_CREATE_TMP_TABLE) ? true : false;
HA_ALTER_FLAGS supported;
- supported = supported | HA_ADD_INDEX | HA_DROP_INDEX | HA_ADD_UNIQUE_INDEX | HA_DROP_UNIQUE_INDEX;
+ supported = supported | HA_ADD_INDEX | HA_DROP_INDEX | HA_ADD_UNIQUE_INDEX | HA_DROP_UNIQUE_INDEX | HA_ADD_PK_INDEX | HA_DROP_PK_INDEX;
/**
- | HA_ADD_COLUMN | HA_COLUMN_STORAGE | HA_COLUMN_FORMAT | HA_ADD_PK_INDEX | HA_DROP_PK_INDEX;
+ | HA_ADD_COLUMN | HA_COLUMN_STORAGE | HA_COLUMN_FORMAT ;
**/
HA_ALTER_FLAGS notSupported = ~(supported);
@@ -2354,33 +2490,6 @@ int StorageInterface::check_if_supported
}
}
- if (alter_flags->is_set(HA_ADD_INDEX) || alter_flags->is_set(HA_ADD_UNIQUE_INDEX)
- || alter_flags->is_set(HA_DROP_INDEX) || alter_flags->is_set(HA_DROP_UNIQUE_INDEX))
- {
- for (unsigned int n = 0; n < altered_table->s->keys; n++)
- {
- KEY *key = altered_table->key_info + n;
- KEY *tableEnd = table->key_info + table->s->keys;
- KEY *tableKey;
-
- // Determine if this is a new index
-
- for (tableKey = table->key_info; tableKey < tableEnd; tableKey++)
- if (!strcmp(tableKey->name, key->name))
- break;
-
- // Unique, non-null keys are interpreted as primary keys.
- // Online add/drop primary keys not yet supported.
-
- if (tableKey >= tableEnd)
- if (n == altered_table->s->primary_key)
- {
- DBUG_PRINT("info",("Online add/drop primary key not supported"));
- DBUG_RETURN(HA_ALTER_NOT_SUPPORTED);
- }
- }
- }
-
DBUG_RETURN(HA_ALTER_SUPPORTED_NO_LOCK);
}
@@ -2404,10 +2513,10 @@ int StorageInterface::alter_table_phase2
if (alter_flags->is_set(HA_ADD_COLUMN))
ret = addColumn(thd, altered_table, create_info, alter_info, alter_flags);
- if ((alter_flags->is_set(HA_ADD_INDEX) || alter_flags->is_set(HA_ADD_UNIQUE_INDEX)) && !ret)
+ if ((alter_flags->is_set(HA_ADD_INDEX) || alter_flags->is_set(HA_ADD_UNIQUE_INDEX) || alter_flags->is_set(HA_ADD_PK_INDEX)) && !ret)
ret = addIndex(thd, altered_table, create_info, alter_info, alter_flags);
- if ((alter_flags->is_set(HA_DROP_INDEX) || alter_flags->is_set(HA_DROP_UNIQUE_INDEX)) && !ret)
+ if ((alter_flags->is_set(HA_DROP_INDEX) || alter_flags->is_set(HA_DROP_UNIQUE_INDEX) || alter_flags->is_set(HA_DROP_PK_INDEX)) && !ret)
ret = dropIndex(thd, altered_table, create_info, alter_info, alter_flags);
DBUG_RETURN(ret);
@@ -2490,8 +2599,7 @@ int StorageInterface::addIndex(THD* thd,
// The server indexes may have been reordered, so remap to the Falcon indexes
- if (!ret)
- remapIndexes(alteredTable);
+ remapIndexes(alteredTable);
storageShare->unlock();
storageShare->unlockIndexes();
@@ -2529,8 +2637,7 @@ int StorageInterface::dropIndex(THD* thd
// The server indexes have been reordered, so remap to the Falcon indexes
- if (!ret)
- remapIndexes(alteredTable);
+ remapIndexes(alteredTable);
storageShare->unlock();
storageShare->unlockIndexes();
@@ -2581,26 +2688,25 @@ void StorageInterface::mysqlLogger(int m
sql_print_information("%s", text);
}
-int StorageInterface::setIndex(TABLE *table, int indexId)
+int StorageInterface::setIndex(TABLE *srvTable, int indexId)
{
StorageIndexDesc indexDesc;
- getKeyDesc(table, indexId, &indexDesc);
+ getKeyDesc(srvTable, indexId, &indexDesc);
return storageTable->setIndex(&indexDesc);
}
-int StorageInterface::setIndexes(TABLE *table)
+int StorageInterface::setIndexes(TABLE *srvTable)
{
int ret = 0;
- if (!table || storageShare->haveIndexes(table->s->keys))
+ if (!srvTable || storageShare->haveIndexes(srvTable->s->keys))
return ret;
storageShare->lockIndexes(true);
storageShare->lock(true);
- ret = remapIndexes(table);
- // validateIndexes(table, true);
+ ret = remapIndexes(srvTable);
storageShare->unlock();
storageShare->unlockIndexes();
@@ -2608,41 +2714,47 @@ int StorageInterface::setIndexes(TABLE *
return ret;
}
-int StorageInterface::remapIndexes(TABLE *table)
+// Create an index entry in StorageTableShare for each TABLE index
+// Assume exclusive lock on StorageTableShare::syncIndexMap
+
+int StorageInterface::remapIndexes(TABLE *srvTable)
{
int ret = 0;
storageShare->deleteIndexes();
- if (!table)
+ if (!srvTable)
return ret;
- for (uint n = 0; n < table->s->keys; ++n)
- if ((ret = setIndex(table, n)))
- break;
+ // Ok to ignore errors in this context
+
+ for (uint n = 0; n < srvTable->s->keys; ++n)
+ setIndex(srvTable, n);
+ // validateIndexes(srvTable, true);
+
return ret;
}
-bool StorageInterface::validateIndexes(TABLE *table, bool exclusiveLock)
+bool StorageInterface::validateIndexes(TABLE *srvTable, bool exclusiveLock)
{
bool ret = true;
- if (!table)
+ if (!srvTable)
return false;
storageShare->lockIndexes(exclusiveLock);
- for (uint n = 0; (n < table->s->keys) && ret; ++n)
+ for (uint n = 0; (n < srvTable->s->keys) && ret; ++n)
{
StorageIndexDesc indexDesc;
- getKeyDesc(table, n, &indexDesc);
+ getKeyDesc(srvTable, n, &indexDesc);
if (!storageShare->validateIndex(n, &indexDesc))
ret = false;
}
- if (ret && (table->s->keys != (uint)storageShare->numberIndexes()))
+ if (ret && (srvTable->s->keys != (uint)storageShare->numberIndexes()))
ret = false;
storageShare->unlockIndexes();
@@ -2650,7 +2762,7 @@ bool StorageInterface::validateIndexes(T
return ret;
}
-int StorageInterface::genTable(TABLE* table, CmdGen* gen)
+int StorageInterface::genTable(TABLE* srvTable, CmdGen* gen)
{
const char *tableName = storageTable->getName();
const char *schemaName = storageTable->getSchemaName();
@@ -2658,9 +2770,9 @@ int StorageInterface::genTable(TABLE* ta
const char *sep = "";
char nameBuffer[256];
- for (uint n = 0; n < table->s->fields; ++n)
+ for (uint n = 0; n < srvTable->s->fields; ++n)
{
- Field *field = table->field[n];
+ Field *field = srvTable->field[n];
CHARSET_INFO *charset = field->charset();
if (charset)
@@ -2679,13 +2791,28 @@ int StorageInterface::genTable(TABLE* ta
sep = ",\n";
}
- if (table->s->primary_key < table->s->keys)
+ if (srvTable->s->primary_key < srvTable->s->keys)
{
- KEY *key = table->key_info + table->s->primary_key;
+ KEY *key = srvTable->key_info + srvTable->s->primary_key;
gen->gen(",\n primary key ");
genKeyFields(key, gen);
}
+#if 0
+ // Disable until UPGRADE TABLE supports index syntax
+
+ for (unsigned int n = 0; n < srvTable->s->keys; n++)
+ {
+ if (n != srvTable->s->primary_key)
+ {
+ KEY *key = srvTable->key_info + n;
+ const char *unique = (key->flags & HA_NOSAME) ? "unique " : "";
+ gen->gen(",\n %s key ", unique);
+ genKeyFields(key, gen);
+ }
+ }
+#endif
+
gen->gen (")");
return 0;
@@ -3078,7 +3205,7 @@ void StorageInterface::decodeRecord(ucha
case MYSQL_TYPE_TIMESTAMP:
{
int value = (int) (dataStream->value.integer64 / 1000);
- longstore(field->ptr, value);
+ ((Field_timestamp*)field)->store_timestamp(value);
}
break;
@@ -3726,18 +3853,22 @@ int StorageInterface::recover (handlerto
DBUG_RETURN(count);
}
+// Build a record field map for use by encode/decodeRecord()
-void StorageInterface::mapFields(TABLE *table)
+void StorageInterface::mapFields(TABLE *srvTable)
{
+ if (!srvTable)
+ return;
+
maxFields = storageShare->format->maxId;
unmapFields();
fieldMap = new Field*[maxFields];
memset(fieldMap, 0, sizeof(fieldMap[0]) * maxFields);
char nameBuffer[256];
- for (uint n = 0; n < table->s->fields; ++n)
+ for (uint n = 0; n < srvTable->s->fields; ++n)
{
- Field *field = table->field[n];
+ Field *field = srvTable->field[n];
storageShare->cleanupFieldName(field->field_name, nameBuffer, sizeof(nameBuffer), false);
int id = storageShare->getFieldId(nameBuffer);
@@ -3804,7 +3935,7 @@ static MYSQL_SYSVAR_UINT(allocation_exte
static MYSQL_SYSVAR_ULONGLONG(page_cache_size, falcon_page_cache_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"The amount of memory to be used for the database page cache.",
- NULL, NULL, LL(4)<<20, LL(2)<<20, (ulonglong) ~0, LL(1)<<20);
+ NULL, NULL, LL(250)<<20, LL(2)<<20, (ulonglong) max_memory_address, LL(1)<<20);
static MYSQL_THDVAR_BOOL(consistent_read, PLUGIN_VAR_OPCMDARG,
"Enable Consistent Read Mode for Repeatable Reads",
=== modified file 'storage/falcon/ha_falcon.h'
--- a/storage/falcon/ha_falcon.h 2008-12-08 21:15:06 +0000
+++ b/storage/falcon/ha_falcon.h 2009-01-15 20:29:54 +0000
@@ -126,19 +126,19 @@ public:
int dropIndex(THD* thd, TABLE* alteredTable, HA_CREATE_INFO* createInfo, HA_ALTER_INFO* alterInfo, HA_ALTER_FLAGS* alterFlags);
void getDemographics(void);
- int createIndex(const char *schemaName, const char *tableName, TABLE *table, int indexId);
- int dropIndex(const char *schemaName, const char *tableName, TABLE *table, int indexId, bool online);
- void getKeyDesc(TABLE *table, int indexId, StorageIndexDesc *indexInfo);
+ int createIndex(const char *schemaName, const char *tableName, TABLE *srvTable, int indexId);
+ int dropIndex(const char *schemaName, const char *tableName, TABLE *srvTable, int indexId, bool online);
+ void getKeyDesc(TABLE *srvTable, int indexId, StorageIndexDesc *indexInfo);
void startTransaction(void);
bool threadSwitch(THD *newThread);
int threadSwitchError(void);
int error(int storageError);
void freeActiveBlobs(void);
- int setIndex(TABLE *table, int indexId);
- int setIndexes(TABLE *table);
- int remapIndexes(TABLE *table);
- bool validateIndexes(TABLE *table, bool exclusiveLock = false);
- int genTable(TABLE* table, CmdGen* gen);
+ int setIndex(TABLE *srvTable, int indexId);
+ int setIndexes(TABLE *srvTable);
+ int remapIndexes(TABLE *srvTable);
+ bool validateIndexes(TABLE *srvTable, bool exclusiveLock = false);
+ int genTable(TABLE* srvTable, CmdGen* gen);
int genType(Field *field, CmdGen *gen);
void genKeyFields(KEY *key, CmdGen *gen);
void encodeRecord(uchar *buf, bool updateFlag);
| Thread |
|---|
| • bzr push into mysql-6.0 branch (alik:3015 to 3016) | Alexander Nozdrin | 11 Feb |