List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:February 11 2009 9:41am
Subject:bzr push into mysql-6.0 branch (alik:3015 to 3016)
View as plain text  
 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 Nozdrin11 Feb