List:Commits« Previous MessageNext Message »
From:Kevin Lewis Date:July 8 2009 8:39pm
Subject:bzr push into mysql-6.0-falcon-team branch (kevin.lewis:2743 to 2753)
Bug#45746
View as plain text  
 2753 Kevin Lewis	2009-07-08
      Bug#45746 - Gopher thread gets error 305.
      Transaction::thawAll was added for 44946 but it was too intrusive.
      It required a full thaw of all records in the transaction.  This
      patch limits thawAll to only those records that have already been
      superceded by a newer change at 'complete time' when thawAll is 
      called.  
      
      Also, RecordVersion::superceded is converted to 
      RecordVersion::base and made more reliable by updating it in
      RecordLeaf::store.
     @ storage/falcon/Record.cpp
        Bug#45746 - Convert 'superceded' to 'base'
        The value of 'base does not matter for a Record object
        since it is not assocviated with any transaction.
     @ storage/falcon/Record.h
        Bug#45746 - Convert 'superceded' to 'base'
     @ storage/falcon/RecordLeaf.cpp
        Bug#45746 - Set RecordVersion::base in RecordLeaf::store()
        so that it reliably reflects whether a record is currently 
        the base record.
     @ storage/falcon/RecordVersion.cpp
        Bug#45746 - Convert 'superceded' to 'base'.  
        Delete old places where superceded is set since 'base' 
        is set in RecordLeaf::store().
     @ storage/falcon/RecordVersion.h
        Bug#45746 - Convert 'superceded' to 'base'.
     @ storage/falcon/Table.cpp
        Bug#45746 - Convert 'superceded' to 'base'.  
        Delete old places where superceded is set since 'base' 
        is set in RecordLeaf::store().
     @ storage/falcon/Transaction.cpp
        Bug#45746 - Convert 'superceded' to 'base'.  
        Use RecordVersion::isBase() to limit the number of records
        thawed at complete time.

    modified:
      storage/falcon/Record.cpp
      storage/falcon/Record.h
      storage/falcon/RecordLeaf.cpp
      storage/falcon/RecordVersion.cpp
      storage/falcon/RecordVersion.h
      storage/falcon/Table.cpp
      storage/falcon/Transaction.cpp
 2752 John H. Embretsen	2009-07-03
      Bump Falcon's internal version number.
      We try to do this every time we merge upwards. This also makes it easier for developers to compare the ages of different codebases.

    modified:
      storage/falcon/StorageVersion.h
 2751 lars-erik.bjork@stripped	2009-07-01 [merge]
      merging ...

    added:
      mysql-test/suite/falcon/r/falcon_bug_45775.result
      mysql-test/suite/falcon/t/falcon_bug_45775.test
    modified:
      storage/falcon/StorageTableShare.cpp
      storage/falcon/StorageTableShare.h
      storage/falcon/ha_falcon.cpp
      storage/falcon/ha_falcon.h
 2750 lars-erik.bjork@stripped	2009-07-01
      IndexRootPage::splitIndexPage has a return statement that will never be exercised. This is probably because
      of multiple rewrites of the method. Because of this, there is really no need for the method to be declared
      to return a bool, as 'false' always will be the returned value. Changing the declaration to void, improves the readability of the code, and allows us to
      readability and allows us to remove two if-statements
     @ storage/falcon/IndexRootPage.cpp
        I have removed two if statements checking the return value of the call to splitIndexPage. I have also removed the return statement that will never be exercised.
     @ storage/falcon/IndexRootPage.h
        I have changed the method signature, the method is now a 'void' method

    modified:
      storage/falcon/IndexRootPage.cpp
      storage/falcon/IndexRootPage.h
 2749 Olav.Sandstaa@stripped	2009-06-26 [merge]
      Merging...

    modified:
      storage/falcon/StorageTable.cpp
      storage/falcon/Table.cpp
      storage/falcon/Table.h
 2748 Olav.Sandstaa@stripped	2009-06-26
      Bug#43490 Falcon internal thread terminate after throwing an instance of 'SQLError'
      
      The thrown exception contains the error string "can't continue after
      fatal error ". This exception is only thrown by the Falcon IO
      system. It is thrown after a fatal IO error has
      occurred. Unfortunately it gives very little information about what
      the actual error was.
      
      This patch improves the logging of "fatal" IO errors by writing to the
      error log file information about the error when it occurs. With this
      patch a message similar to this example will be written when
      IO::declareFatalError() is called:
      
      Falcon: Fatal IO error occurred in "IO::writePages": file
      "/home/olav/mysql/develop/falcon-elog/mysql-test/var/mysqld.1/data/falcon_user.fts", page 21: No space left on device (28)
      
      Note that this patch does not fix the problem but only improves the logging
      when the actually error occurs, hopefully making it easier to find the
      real error.

    modified:
      storage/falcon/IO.cpp
      storage/falcon/IOx.h
 2747 John H. Embretsen	2009-06-25
      Adjust falcon_team.experimental file to reflect recent changes (tests stabilized and moved to falcon suite).

    modified:
      mysql-test/collections/falcon_team.experimental
 2746 John H. Embretsen	2009-06-25
      Bug#45331 - Tests are not run on the weekly-6.0-falcon-team tree.
      Adjustments to run all Falcon big-tests in wekly runs instead of only non-failing or relatively "fast" tests.
      Also including falcon_team suite (although there are no big-tests there currently) to simplify maintenance.

    modified:
      mysql-test/collections/mysql-6.0-falcon-team.weekly
 2745 Kevin Lewis	2009-06-24
      Bug#43650 - The server calls StorageInterface::rnd_pos() when it has a list of records previously read and sorted and it wants to read them a final time.  If the isolation mode is read-committed, the call to fetchVersion will return NULL if the currently committed version is deleted.  This means it was deleted during the transaction.  Since the transaction was able to find a visible version of the record before, that visible version MUST still be around.  So the only reason that fetchVersion would return NULL is if the current visible version is deleted.  In repeatable-read, fetchVersion would return that previous visible record.
      
      So if fetchVersion or fetchForUpdate returns NULL to StorageDatabase::fetch(), instead of returning 
         StorageErrorRecordNotFound - HA_KEY_NOT_FOUND - "can't find record",
      it should return 
         StorageErrorRecordDeleted - HA_ERR_RECORD_DELETED
      so that the server will ignore this record and go  on to the nexxt record.

    modified:
      storage/falcon/StorageDatabase.cpp
      storage/falcon/StorageTableShare.h
      storage/falcon/ha_falcon.cpp
 2744 Kevin Lewis	2009-06-24
      Code Cleanup
     @ storage/falcon/ha_falcon.cpp
        Use Unix EOL.  Use (c).
     @ storage/falcon/ha_falcon.h
        cleanup

    modified:
      storage/falcon/ha_falcon.cpp
      storage/falcon/ha_falcon.h
 2743 Olav.Sandstaa@sun.com	2009-06-24 [merge]
      Merging

    modified:
      storage/falcon/Record.cpp
      storage/falcon/Record.h
      storage/falcon/RecordVersion.cpp
      storage/falcon/RecordVersion.h
      storage/falcon/SRLUpdateRecords.cpp
      storage/falcon/Table.cpp
      storage/falcon/Transaction.cpp
      storage/falcon/TransactionState.h
      storage/falcon/ha_falcon.cpp
      storage/falcon/ha_falcon.h
=== modified file 'mysql-test/collections/falcon_team.experimental'
--- a/mysql-test/collections/falcon_team.experimental	2009-03-31 12:45:26 +0000
+++ b/mysql-test/collections/falcon_team.experimental	2009-06-25 17:06:52 +0000
@@ -28,6 +28,3 @@
 #
 
 falcon_team.falcon_bug_34174                # Bug#41521 - falcon_bug_34174 fails with lock wait timeout, sometimes
-falcon_team.falcon_bug_34351_B              # Bug#42140 - falcon_bug_34351_B fails; sometimes
-falcon_team.falcon_bug_34351_C              # Bug#39890 - Falcon Error: page 0/1 wrong page type, expected 7 got 1
-falcon_team.falcon_deadlock                 # Bug#43554 - Intermittent lock-wait-timeout in falcon_deadlock test

=== modified file 'mysql-test/collections/mysql-6.0-falcon-team.weekly'
--- a/mysql-test/collections/mysql-6.0-falcon-team.weekly	2009-06-18 08:19:53 +0000
+++ b/mysql-test/collections/mysql-6.0-falcon-team.weekly	2009-06-25 16:59:40 +0000
@@ -1,2 +1,2 @@
 perl mysql-test-run.pl --force --comment=other_falcon --suite=main,funcs_1,parts,rpl --do-test=.*falcon.* --experimental=collections/default.experimental
-perl mysql-test-run.pl --comment=falcon_big --suite=falcon --force --retry-failure=0 --skip-ndb --big-test --suite-timeout=1440 --testcase-timeout=300 --experimental=collections/default.experimental falcon_blob_space-big falcon_bug_22169-big falcon_bug_22207-big falcon_bug_26433-big falcon_bug_30124-big falcon_bug_34351_A-big falcon_bug_34351_C-big falcon_record_cache_memory_leak-big falcon_unicode-big 
+perl mysql-test-run.pl --comment=falcon_big --suite=falcon,falcon_team --do-test=.*-big --force --retry-failure=0 --skip-ndb --big-test --suite-timeout=1440 --testcase-timeout=300 --experimental=collections/falcon_team.experimental

=== added file 'mysql-test/suite/falcon/r/falcon_bug_45775.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_45775.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_45775.result	2009-06-28 18:58:38 +0000
@@ -0,0 +1,31 @@
+*** Bug #45775 ***
+SET @@storage_engine = 'Falcon';
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (a int NOT NULL UNIQUE, b int, c int);
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) NOT NULL,
+  `b` int(11) DEFAULT NULL,
+  `c` int(11) DEFAULT NULL,
+  UNIQUE KEY `a` (`a`)
+) ENGINE=Falcon DEFAULT CHARSET=latin1
+ALTER TABLE t1 ADD PRIMARY KEY (b);
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) NOT NULL,
+  `b` int(11) NOT NULL DEFAULT '0',
+  `c` int(11) DEFAULT NULL,
+  PRIMARY KEY (`b`),
+  UNIQUE KEY `a` (`a`)
+) ENGINE=Falcon DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES (1,1,1);
+INSERT INTO t1 VALUES (1,1,2);
+ERROR 23000: Duplicate entry '1' for key 'a'
+INSERT INTO t1 VALUES (1,2,2);
+ERROR 23000: Duplicate entry '1' for key 'a'
+INSERT INTO t1 VALUES (2,1,2);
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+INSERT INTO t1 VALUES (2,2,2);
+DROP TABLE t1;

=== added file 'mysql-test/suite/falcon/t/falcon_bug_45775.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_45775.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_45775.test	2009-06-28 18:58:38 +0000
@@ -0,0 +1,50 @@
+#
+# Bug #45775: Crash when adding primary key to Falcon table with unique constraint
+#
+# The server treats a primary key and a unique key with non-null columns as
+# effectively the same. This test confirms that the storage engine makes the
+# correct distinction between the two.
+#
+--echo *** Bug #45775 ***
+
+--source include/have_falcon.inc
+
+# ----------------------------------------------------- #
+# --- Initialisation                                --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+# ----------------------------------------------------- #
+# --- Test                                          --- #
+# ----------------------------------------------------- #
+CREATE TABLE t1 (a int NOT NULL UNIQUE, b int, c int);
+SHOW CREATE TABLE t1;
+ALTER TABLE t1 ADD PRIMARY KEY (b);
+SHOW CREATE TABLE t1;
+
+INSERT INTO t1 VALUES (1,1,1);
+
+## Should fail with key conflict
+--error ER_DUP_ENTRY
+INSERT INTO t1 VALUES (1,1,2);
+
+## Should fail with unique key conflict
+--error ER_DUP_ENTRY
+INSERT INTO t1 VALUES (1,2,2);
+
+## Should fail with primary key conflict
+--error ER_DUP_ENTRY
+INSERT INTO t1 VALUES (2,1,2);
+
+INSERT INTO t1 VALUES (2,2,2);
+
+# ----------------------------------------------------- #
+# --- Final cleanup                                 --- #
+# ----------------------------------------------------- #
+DROP TABLE t1;
+

=== modified file 'storage/falcon/DataPage.cpp'
--- a/storage/falcon/DataPage.cpp	2009-06-12 13:34:24 +0000
+++ b/storage/falcon/DataPage.cpp	2009-06-22 12:23:12 +0000
@@ -43,7 +43,18 @@ static const char THIS_FILE[]=__FILE__;
 
 int DataPage::updateRecord(Section *section, int lineNumber, Stream *stream, TransId transId, bool earlyWrite)
 {
-	ASSERT(lineNumber < maxLine);
+	/* During recovery we might be asked to update a record that does
+	   not exist on the page. This situation can happen when the
+	   Record Locator page was written to disk while this data page
+	   was not written to disk before the server crash. We handle this
+	   by returning that there is no rom for this record on this
+	   page. */
+
+	if (lineNumber >= maxLine)
+		{
+		ASSERT(section->dbb->serialLog->recovering);
+		return 0;
+		}
 
 	Dbb *dbb = section->dbb;
 	LineIndex *index = lineIndex + lineNumber;
@@ -295,6 +306,17 @@ int DataPage::storeRecord(Dbb *dbb, Bdb 
 
 int DataPage::deleteLine (Dbb *dbb, int line, TransId transId)
 {
+	/* During recovery we might be asked to delete a record that does
+	   not exists on the page. This situation can happen when the
+	   Record Locator page was written to disk while this data
+	   page was not written to disk before the server crashed. */
+
+	if (line >= maxLine)
+		{
+		ASSERT(dbb->serialLog->recovering);
+		return 0;
+		}
+
 	// Handle overflow pages first
 
 	if (lineIndex [line].length < 0)

=== modified file 'storage/falcon/IO.cpp'
--- a/storage/falcon/IO.cpp	2009-04-07 20:16:05 +0000
+++ b/storage/falcon/IO.cpp	2009-06-26 11:13:44 +0000
@@ -109,6 +109,8 @@ static const int TRACE_SYNC_END		= -2;
 
 static const uint16 NON_ZERO_CHECKSUM_MAGIC = 0xAFFE;
 
+static const int NO_VALID_PAGE_NUMBER = -2;
+
 #ifdef SIMULATE_DISK_FULL
 static int simulateDiskFull = SIMULATE_DISK_FULL;
 #endif
@@ -289,7 +291,7 @@ void IO::readPage(Bdb * bdb)
 
 	if (length != pageSize)
 		{
-		declareFatalError();
+		declareFatalError("IO::readPage", bdb->pageNumber, errno);
 		if (length == -1)
 			{
 			throw SQLError(IO_ERROR, "read error on page %d of \"%s\": %s (%d)",
@@ -390,7 +392,7 @@ void IO::writePages(int32 pageNumber, in
 		if (errno == ENOSPC)
 			throw SQLError(DEVICE_FULL, "device full error on %s, page %d\n", (const char*) fileName, pageNumber);
 			
-		declareFatalError();
+		declareFatalError("IO::writePages", pageNumber, errno);
 		
 		throw SQLError(IO_ERROR, "write error on page %d (%d/%d/%d) of \"%s\": %s (%d)",
 				pageNumber, length, pageSize, fileId,
@@ -452,9 +454,27 @@ void IO::longSeek(int64 offset)
 		Error::error ("long seek failed on  \"%s\"", (const char*) fileName);
 }
 
-void IO::declareFatalError()
+void IO::declareFatalError(const char *methodName, int pageNumber, int errorNumber)
 {
+	// Update status about that a fatal IO error has occured
+
 	fatalError = true;
+
+	// Convert the page number to a string. Note that we use
+	// NO_VALID_PAGE_NUMBER to indicate that this error is not related
+	// to a specific page.
+
+	char pageNumberStr[40];
+	pageNumberStr[0] = 0;
+
+	if (pageNumber != NO_VALID_PAGE_NUMBER)
+		{
+		sprintf(pageNumberStr, ", page %d", pageNumber);
+		}
+
+	Log::fatal("Falcon: Fatal IO error occurred in \"%s\": file \"%s\"%s: %s (%d)\n", 
+			   methodName, (const char*) fileName, pageNumberStr,
+			   strerror(errorNumber), errorNumber);
 }
 
 
@@ -705,7 +725,7 @@ void IO::sync(void)
 #ifdef _WIN32
 	if (_commit(fileId))
 		{
-		declareFatalError();
+		declareFatalError("IO::sync", NO_VALID_PAGE_NUMBER, errno);
 		throw SQLError(IO_ERROR, "_commit failed on \"%s\": %s (%d)",
 				(const char*) fileName, strerror (errno), errno);
 		}

=== modified file 'storage/falcon/IOx.h'
--- a/storage/falcon/IOx.h	2008-09-11 10:56:00 +0000
+++ b/storage/falcon/IOx.h	2009-06-26 11:13:44 +0000
@@ -56,7 +56,6 @@ public:
 	void	write(uint32 length, const UCHAR *data);
 	static bool	doesFileExist(const char *fileName);
 	static int	fileStat(const char *fileName, struct stat *stats = NULL, int *errnum = NULL);
-	void	declareFatalError();
 	void	seek (int pageNumber);
 	void	closeFile();
 	void	readHeader (Hdr *header);
@@ -88,6 +87,10 @@ public:
 	static void		deleteFile(const char* fileName);
 	static int		getWriteMode(int attempt);
 
+private:
+	void	declareFatalError(const char *methodName, int PageNumber, int errorNumber);
+
+public:
 	JString		fileName;
 	SyncObject	syncObject;
 	int			fileId;

=== modified file 'storage/falcon/IndexRootPage.cpp'
--- a/storage/falcon/IndexRootPage.cpp	2009-04-14 19:14:20 +0000
+++ b/storage/falcon/IndexRootPage.cpp	2009-07-01 09:02:00 +0000
@@ -182,10 +182,9 @@ bool IndexRootPage::addIndexEntry(Dbb * 
 		/* Node didn't fit.  Split the page and propagate the
 		   split upward.  Sooner or later we'll go back and re-try
 		   the original insertion */
-
-		if (splitIndexPage (dbb, indexId, bdb, transId, result, key, recordNumber, isRoot))
-			return true;
-
+		
+		splitIndexPage (dbb, indexId, bdb, transId, result, key, recordNumber, isRoot);
+		
 #ifdef _DEBUG
 		if (n)
 			{
@@ -483,7 +482,7 @@ void IndexRootPage::scanIndex  (Dbb *dbb
 		}
 }
 
-bool IndexRootPage::splitIndexPage(Dbb * dbb, int32 indexId, Bdb * bdb, TransId transId,
+void IndexRootPage::splitIndexPage(Dbb * dbb, int32 indexId, Bdb * bdb, TransId transId,
 								   AddNodeResult addResult, IndexKey *indexKey, int recordNumber, bool isRoot)
 {
 
@@ -557,7 +556,7 @@ bool IndexRootPage::splitIndexPage(Dbb *
 		leftBdb->release(REL_HISTORY);
 		bdb->release(REL_HISTORY);
 		
-		return false;
+		return;
 		}
 
 	
@@ -596,15 +595,15 @@ bool IndexRootPage::splitIndexPage(Dbb *
 				}
 
 			parentBdb->release(REL_HISTORY);
-			return false;
+			return;
 			}
 
 		// Parent page needs to be split.Recurse
 		ASSERT(result == SplitMiddle || result == SplitEnd || result == NextPage);
 
-		if (splitIndexPage (dbb, indexId, parentBdb, transId, result, &splitKey,
-				splitPageNumber, (parentBdb->pageNumber == rootPageNumber)))
-			return true;
+		splitIndexPage (dbb, indexId, parentBdb, transId, result, &splitKey,
+						splitPageNumber, (parentBdb->pageNumber == rootPageNumber));
+
 		}
 }
 

=== modified file 'storage/falcon/IndexRootPage.h'
--- a/storage/falcon/IndexRootPage.h	2009-03-02 18:36:32 +0000
+++ b/storage/falcon/IndexRootPage.h	2009-07-01 09:02:00 +0000
@@ -43,7 +43,7 @@ public:
 	static void		debugBucket (Dbb *dbb, int indexId, int recordNumber, TransId transactionId);
 	static void		deleteIndex (Dbb *dbb, int32 indexId, TransId transId);
 	static bool		deleteIndexEntry (Dbb *dbb, int32 indexId, IndexKey *key, int32 recordNumber, TransId transId);
-	static bool		splitIndexPage (Dbb *dbb, int32 indexId, Bdb *bdb, TransId transId,
+	static void		splitIndexPage (Dbb *dbb, int32 indexId, Bdb *bdb, TransId transId,
 									AddNodeResult addResult, IndexKey *indexKey, int recordNumber, bool isRootPage);
 	static void		scanIndex (Dbb *dbb, int32 indexId, int32 rootPage, IndexKey *low, IndexKey *high, int searchFlags, TransId transId, Bitmap *bitmap);
 	static void		positionIndex(Dbb* dbb, int indexId, int32 rootPage, WalkIndex* walkIndex);

=== modified file 'storage/falcon/Log.cpp'
--- a/storage/falcon/Log.cpp	2008-04-09 01:36:46 +0000
+++ b/storage/falcon/Log.cpp	2009-06-23 13:20:36 +0000
@@ -119,6 +119,16 @@ void Log::debug(const char *txt, ...)
 	log (LogDebug, txt, args);
 }
 
+void Log::fatal(const char *txt, ...)
+{
+	if (!(activeMask & LogAlwaysWrite))
+		return;
+
+	va_list		args;
+	va_start	(args, txt);
+	log (LogAlwaysWrite, txt, args);
+}
+
 void Log::debugBreak(const char *txt, ...)
 {
 	if (!(activeMask & LogDebug))

=== modified file 'storage/falcon/Log.h'
--- a/storage/falcon/Log.h	2009-02-12 19:31:23 +0000
+++ b/storage/falcon/Log.h	2009-06-23 13:20:36 +0000
@@ -41,10 +41,17 @@ static const int	LogScrub         = 0x00
 static const int	LogException     = 0x00000100;	// 256;
 static const int	LogScavenge      = 0x00000200;	// 512;
 static const int	LogXARecovery    = 0x00000400;	// 1024;
+static const int	LogAlwaysWrite   = 0x00000800;	// 2048;
 static const int	LogMysqlInfo     = 0x20000000;
 static const int	LogMysqlWarning  = 0x40000000;
 static const int	LogMysqlError    = 0x80000000;
 
+// The default mask that will be used if falcon_debug_mask is not set.
+// The debug flag in this mask will always be active independent of what
+// the user sets in the falcon_debug_mask.
+
+static const int	LogDefaultMask   = LogAlwaysWrite;
+
 typedef void (Listener) (int, const char*, void *arg);
 
 struct LogListener {
@@ -71,6 +78,7 @@ public:
 	static void addListener (int mask, Listener *fn, void *arg);
 	static void print (int mask, const char *text, void *arg);
 	static void debug (const char *txt, ...);
+	static void fatal (const char *txt, ...);
 	static void log (const char *txt, ...);
 	static void setExclusive(void);
 	static void releaseExclusive(void);

=== modified file 'storage/falcon/Record.cpp'
--- a/storage/falcon/Record.cpp	2009-06-23 21:16:25 +0000
+++ b/storage/falcon/Record.cpp	2009-07-08 20:05:22 +0000
@@ -514,7 +514,7 @@ Record* Record::getPriorVersion()
 	return NULL;
 }
 
-void Record::setSuperceded(bool flag)
+void Record::setBase(bool flag)
 {
 
 }
@@ -531,7 +531,7 @@ TransactionState* Record::getTransaction
 	return NULL;
 }
 
-bool Record::isSuperceded()
+bool Record::isBase()
 {
 	return false;
 }

=== modified file 'storage/falcon/Record.h'
--- a/storage/falcon/Record.h	2009-06-23 21:16:25 +0000
+++ b/storage/falcon/Record.h	2009-07-08 20:05:22 +0000
@@ -116,7 +116,7 @@ public:
 	virtual TransactionState* getTransactionState() const;
 	virtual TransId		getTransactionId();
 	virtual int			getSavePointId();
-	virtual void		setSuperceded (bool flag);
+	virtual void		setBase (bool flag);
 	virtual Record*		fetchVersion (Transaction * transaction);
 	virtual void		retire(void);
 	virtual void		scavenge(TransId targetTransactionId, int oldestActiveSavePointId);
@@ -138,7 +138,7 @@ public:
 	virtual bool		isChilled();
 	virtual bool		isALock();
 	virtual bool		isDeleted();
-	virtual bool		isSuperceded();
+	virtual bool		isBase();
 	virtual bool		isVersion();
 	virtual bool		isNull(int fieldId);
 

=== modified file 'storage/falcon/RecordLeaf.cpp'
--- a/storage/falcon/RecordLeaf.cpp	2009-04-16 12:09:15 +0000
+++ b/storage/falcon/RecordLeaf.cpp	2009-07-08 20:05:22 +0000
@@ -54,7 +54,7 @@ RecordLeaf::~RecordLeaf()
 			for (Record *rec = records[n]; rec; rec = rec->getPriorVersion())
 				rec->active = false;
 #endif
-				
+			records[n]->setBase(false);
 			records[n]->release(REC_HISTORY);
 			}
 }
@@ -94,8 +94,9 @@ bool RecordLeaf::store(Record *record, R
 		return (*parentPtr)->store(record, prior, id, parentPtr);
 		}
 
-	// If we're adding a new version, don't bother with a lock.  Otherwise we need to lock out
-	// simultaneous fetches to avoid a potential race between addRef() and release().
+	// If we're adding a new version, don't bother with a lock.  
+	// Otherwise we need to lock out simultaneous fetches to avoid 
+	// a potential race between addRef() and release().
 
 	if (record && record->getPriorVersion() == prior)
 		{
@@ -111,6 +112,17 @@ bool RecordLeaf::store(Record *record, R
 			return false;
 		}
 
+	// Set the base boolean for these 2 Records.  
+	// This can be done after a successful CAS because the only thread 
+	// interested in this boolean is the one working on the pending transaction
+	// of the new base record, which it this thread.
+
+	if (prior)
+		prior->setBase(false);
+
+	if (record)
+		record->setBase(true);
+
 	return true;
 }
 
@@ -207,6 +219,7 @@ void RecordLeaf::retireRecords (Table *t
 				{
 				++recordScavenge->recordsRetired;
 				recordScavenge->spaceRetired += record->getMemUsage();
+				record->setBase(false);
 				record->retire();
 				}
 			else

=== modified file 'storage/falcon/RecordVersion.cpp'
--- a/storage/falcon/RecordVersion.cpp	2009-06-23 21:16:25 +0000
+++ b/storage/falcon/RecordVersion.cpp	2009-07-08 20:05:22 +0000
@@ -65,7 +65,7 @@ RecordVersion::RecordVersion(Table *tbl,
 	setTransactionState(transaction->transactionState);
 	
 	savePointId   = transaction->curSavePointId;
-	superceded    = false;
+	base = false;
 
 	// Add a use count on the transaction state to ensure it lives 
 	// as long as the record version object
@@ -77,10 +77,7 @@ RecordVersion::RecordVersion(Table *tbl,
 
 		// Be sure the priorVersion is thawed.
 		
-		priorVersion->hasRecord();
-		
-		if (transactionState == priorVersion->getTransactionState())
-			oldVersion->setSuperceded (true);
+		priorVersion->getRecordData();
 		}
 	else
 		recordNumber = -1;
@@ -94,18 +91,13 @@ RecordVersion::RecordVersion(Database* d
 	virtualOffset = stream->getInt64();
 	TransId transactionId = stream->getInt();
 	int priorType = stream->getInt();
-	superceded = false;
+	base = false;
 	transactionState = NULL;
 	

 	if (priorType == 0)
 		priorVersion = new Record(database, stream);
 	else if (priorType == 1)
-		{
 		priorVersion = new RecordVersion(database, stream);
-		
-		if (priorVersion->getTransactionId() == transactionId)
-			superceded = true;
-		}
 	else
 		priorVersion = NULL;
 	
@@ -208,7 +200,7 @@ Record* RecordVersion::fetchVersion(Tran
 
 void RecordVersion::rollback(Transaction *transaction)
 {
-	if (!superceded)
+	if (isBase())
 		format->table->rollbackRecord (this, transaction);
 }
 
@@ -318,9 +310,9 @@ Record* RecordVersion::getGCPriorVersion
 	return (state == recEndChain) ? NULL : priorVersion;
 }
 
-void RecordVersion::setSuperceded(bool flag)
+void RecordVersion::setBase(bool flag)
 {
-	superceded = flag;
+	base = flag;
 }
 
 /***
@@ -335,9 +327,9 @@ TransactionState* RecordVersion::getTran
 	return transactionState;
 }
 
-bool RecordVersion::isSuperceded()
+bool RecordVersion::isBase()
 {
-	return superceded;
+	return base;
 }
 
 // Set the priorVersion to NULL and return its pointer.
@@ -545,7 +537,7 @@ bool RecordVersion::hasRecord(void)
 	if (hasNoData(recordData))
 		return false;
 
-	if (isChilled())
+	if (recordData == recordIsChilled)
 		{
 		recordData = thaw();
 		ASSERT(recordData != recordIsChilled);

=== modified file 'storage/falcon/RecordVersion.h'
--- a/storage/falcon/RecordVersion.h	2009-06-23 21:16:25 +0000
+++ b/storage/falcon/RecordVersion.h	2009-07-08 20:05:22 +0000
@@ -40,7 +40,7 @@ public:
 	virtual TransactionState* getTransactionState() const;
 	virtual TransId		getTransactionId();
 	virtual int			getSavePointId();
-	virtual void		setSuperceded (bool flag);
+	virtual void		setBase (bool flag);
 	virtual Record*		getPriorVersion();
 	virtual Record*		getGCPriorVersion(void);
 	virtual void		retire(void);
@@ -62,7 +62,7 @@ public:
 	virtual bool		isChilled();
 	virtual bool		isALock();
 	virtual bool		isDeleted();
-	virtual bool		isSuperceded();
+	virtual bool		isBase();
 	virtual bool		isVersion();
 
 	void				commit();
@@ -82,7 +82,7 @@ public:
 	RecordVersion	*prevInTrans;
 	//TransId			transactionId;
 	int				savePointId;
-	bool			superceded;
+	bool			base;   // The record tree currently points to this revord version.
 
 //private:
 	TransactionState *transactionState;

=== modified file 'storage/falcon/StorageDatabase.cpp'
--- a/storage/falcon/StorageDatabase.cpp	2009-06-03 01:36:57 +0000
+++ b/storage/falcon/StorageDatabase.cpp	2009-06-24 22:17:25 +0000
@@ -375,7 +375,7 @@ int StorageDatabase::fetch(StorageConnec
 			if (!lockForUpdate)
 				candidate->release(REC_HISTORY);
 			
-			return StorageErrorRecordNotFound;
+			return StorageErrorRecordDeleted;
 			}
 		
 		if (!lockForUpdate && record != candidate)

=== modified file 'storage/falcon/StorageTable.cpp'
--- a/storage/falcon/StorageTable.cpp	2009-05-14 05:16:08 +0000
+++ b/storage/falcon/StorageTable.cpp	2009-06-25 22:48:40 +0000
@@ -643,7 +643,7 @@ void StorageTable::clearAlter(void)
 
 bool StorageTable::setAlter(void)
 {
-	return share->table->setAlter();
+	return share->table->setAlter(storageConnection->connection);
 }
 
 int StorageTable::alterCheck(void)

=== modified file 'storage/falcon/StorageTableShare.cpp'
--- a/storage/falcon/StorageTableShare.cpp	2009-04-27 16:43:53 +0000
+++ b/storage/falcon/StorageTableShare.cpp	2009-06-28 18:58:38 +0000
@@ -219,11 +219,11 @@ int StorageTableShare::create(StorageCon
 			case TABLESPACE_NOT_EXIST_ERROR:
 				return StorageErrorTableSpaceNotExist;
 			default:
-				return StorageErrorTableExits;
+				return StorageErrorTableExists;
 			}
 		}
 	if (!table)
-		return StorageErrorTableExits;
+		return StorageErrorTableExists;
 	
 	format = table->getCurrentFormat();
 
@@ -235,8 +235,12 @@ int StorageTableShare::create(StorageCon
 
 int StorageTableShare::upgrade(StorageConnection *storageConnection, const char* sql, int64 autoIncrementValue)
 {
-	if (!(table = storageDatabase->upgradeTable(storageConnection, name, schemaName, sql, autoIncrementValue)))
-		return StorageErrorTableExits;
+	Table* tableUpgrade = storageDatabase->upgradeTable(storageConnection, name, schemaName, sql, autoIncrementValue);
+	
+	if (tableUpgrade)
+		table = tableUpgrade;
+	else
+		return StorageErrorTableExists;
 
 	format = table->getCurrentFormat();
 	

=== modified file 'storage/falcon/StorageTableShare.h'
--- a/storage/falcon/StorageTableShare.h	2009-04-27 16:43:53 +0000
+++ b/storage/falcon/StorageTableShare.h	2009-06-28 18:58:38 +0000
@@ -100,7 +100,7 @@ enum StorageError {
 	StorageErrorTableNotFound		= -3,
 	StorageErrorNoIndex				= -4,
 	StorageErrorBadKey				= -5,
-	StorageErrorTableExits			= -6,
+	StorageErrorTableExists			= -6,
 	StorageErrorNoSequence			= -7,
 	StorageErrorUpdateConflict		= -8,
 	StorageErrorUncommittedUpdates	= -9,		// specific for drop table
@@ -120,7 +120,8 @@ enum StorageError {
 	StorageErrorDeviceFull			= -110,
 	StorageErrorTableSpaceDataFileExist	= -111,
 	StorageErrorIOErrorSerialLog	= -112,
-	StorageErrorInternalError		= -113
+	StorageErrorInternalError		= -113,
+	StorageErrorRecordDeleted		= -114		// Record requested has been deleted
 	};
 	
 static const int StoreErrorIndexShift	= 10;

=== modified file 'storage/falcon/StorageVersion.h'
--- a/storage/falcon/StorageVersion.h	2009-04-30 10:06:12 +0000
+++ b/storage/falcon/StorageVersion.h	2009-07-03 11:14:02 +0000
@@ -14,5 +14,5 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
 
-#define FALCON_VERSION	"T1.6-0"
-#define FALCON_DATE		"30 April, 2009"
+#define FALCON_VERSION	"T1.6-1"
+#define FALCON_DATE		"03 July, 2009"

=== modified file 'storage/falcon/Table.cpp'
--- a/storage/falcon/Table.cpp	2009-06-23 21:16:25 +0000
+++ b/storage/falcon/Table.cpp	2009-07-08 20:05:22 +0000
@@ -917,7 +917,8 @@ void Table::init(int id, const char *sch
 	debugThawedBytes = 0;
 	cardinality = 0;
 	priorCardinality = 0;
-	alterIsActive = false;
+	alterIsActive = 0;
+	alterConnection  = NULL;
 	syncObject.setName("Table::syncObject");
 	syncTriggers.setName("Table::syncTriggers");
 	syncAlter.setName("Table::syncAlter");
@@ -1065,23 +1066,15 @@ void Table::rollbackRecord(RecordVersion
 	Record *priorRecord = recordToRollback->getPriorVersion();
 
 	if (priorRecord)
-		{
 		priorRecord->addRef(REC_HISTORY);
-		priorRecord->setSuperceded(false);
-		}
 
 	// Replace the current version of this record.
 
 	if (!insertIntoTree(priorRecord, recordToRollback, recordToRollback->recordNumber))
 		{
-		// If a transaction inserts a record and then deletes it, 
-		// the deleted record version will have no priorRecord.
+		// Deleted record versions must always have a prior version.
 
-		if (priorRecord == NULL && recordToRollback->isDeleted())
-			{
-			ASSERT(!(priorRecord == NULL && recordToRollback->isDeleted()));
-			return; // This should not be an excuse to keep going.
-			}
+		ASSERT(!(recordToRollback->isDeleted() && priorRecord == NULL));
 
 		// The store of this record into the record leaf failed. No way to recover.
 		// While the base record is uncommitted, only that transaction can change it.
@@ -1426,10 +1419,6 @@ void Table::update(Transaction * transac
 
 		if (record)
 			{
-			Record *prior = record->getPriorVersion();
-			if (prior)
-				prior->setSuperceded(false);
-
 			ASSERT(!record->isALock());
 			record->deleteData();
 
@@ -1774,7 +1763,8 @@ void Table::truncate(Transaction *transa
 	ageGroup = database->currentGeneration;
 	debugThawedRecords = 0;
 	debugThawedBytes = 0;
-	alterIsActive = false;
+	alterIsActive = 0;
+	alterConnection  = NULL;
 	deleting = false;
 }
 
@@ -3251,10 +3241,6 @@ void Table::update(Transaction * transac
 				}
 			else
 				{
-				Record* prior = record->getPriorVersion();
-				if (prior)
-					prior->setSuperceded(false);
-
 				char* recordData = record->exchangeData((char*) recordDataIsFreed);
 				record->deleteData(recordData, false);
 
@@ -3456,9 +3442,10 @@ void Table::unlockRecord(RecordVersion* 
 	if (!record->isALock())
 		return;
 
-	// A lock record that has superceded=true is already unlocked
+	// A lock record that has base=false is either already unlocked,
+	// or it has been superceded by an updated version.
 
-	if (record->isSuperceded())
+	if (!record->isBase())
 		return;
 
 	// Only unlock records at the current savepoint
@@ -3467,9 +3454,7 @@ void Table::unlockRecord(RecordVersion* 
 		return;
 
 	Record *prior = record->getPriorVersion();
-	if (insertIntoTree(prior, record, record->recordNumber))
-		record->setSuperceded(true);
-	else
+	if (!insertIntoTree(prior, record, record->recordNumber))
 		Log::debug("Table::unlockRecord: record lock not in record tree\n");
 }
 
@@ -3695,19 +3680,21 @@ void Table::clearAlter(void)
 		{
 		Sync sync(&syncAlter, "Table::clearAlter");
 		sync.lock(Exclusive);
-		alterIsActive = false;
+		if (--alterIsActive == 0)
+			alterConnection  = NULL;
 		}
 }
 
-bool Table::setAlter(void)
+bool Table::setAlter(Connection* connection)
 {
 	Sync sync(&syncAlter, "Table::setAlter");
 	sync.lock(Exclusive);
 
-	if (alterIsActive)
+	if (alterIsActive && (connection != alterConnection))
 		return false;
 
-	alterIsActive = true;
+	alterIsActive++;
+	alterConnection = connection;
 	
 	return true;
 }

=== modified file 'storage/falcon/Table.h'
--- a/storage/falcon/Table.h	2009-06-02 15:25:59 +0000
+++ b/storage/falcon/Table.h	2009-06-25 22:48:40 +0000
@@ -127,7 +127,7 @@ public:
 	int			nextColumnId (int previous);
 	void		loadStuff();
 	void		clearAlter(void);
-	bool		setAlter(void);
+	bool		setAlter(Connection* connection);
 	
 	void		addTrigger (Trigger *trigger);
 	void		dropTrigger (Trigger *trigger);
@@ -271,7 +271,8 @@ public:
 	bool			changed;
 	bool			eof;
 	bool			markedForDelete;
-	bool			alterIsActive;
+	int				alterIsActive;
+	Connection*		alterConnection;			// The connection currintly doing an alter.
 	bool			deleting;					// dropping or truncating.
 	int32			recordBitmapHighWater;
 	int32			ageGroup;

=== modified file 'storage/falcon/Thread.cpp'
--- a/storage/falcon/Thread.cpp	2009-03-20 19:28:10 +0000
+++ b/storage/falcon/Thread.cpp	2009-06-24 13:31:32 +0000
@@ -196,7 +196,7 @@ void Thread::thread()
 	catch (SQLException& exception)
 		{
 #ifdef FALCONDB
-		Log::log ("Thread::thread: thread %d: %s\n", threadId, exception.getText());
+		Log::fatal ("Thread::thread: thread %d: %s\n", threadId, exception.getText());
 #endif
 		release();
 		throw;
@@ -204,7 +204,7 @@ void Thread::thread()
 	catch (...)
 		{
 #ifdef FALCONDB
-		Log::log ("Thread::thread: unexpected exception, rethrowing, thread %d\n", threadId);
+		Log::fatal ("Thread::thread: unexpected exception, rethrowing, thread %d\n", threadId);
 #endif
 		release();
 		throw;

=== modified file 'storage/falcon/Transaction.cpp'
--- a/storage/falcon/Transaction.cpp	2009-06-23 21:16:25 +0000
+++ b/storage/falcon/Transaction.cpp	2009-07-08 20:05:22 +0000
@@ -249,7 +249,7 @@ void Transaction::commit()
 		RECORD_HISTORY(record);
 		Table * table = record->format->table;
 
-		if (!record->isSuperceded() && !record->isALock())
+		if (record->isBase() && !record->isALock())
 			{
 			table->updateRecord (record);
 			
@@ -385,6 +385,8 @@ void Transaction::rollback()
 	Sync syncRec(&syncRecords, "Transaction::rollback(records)");
 	syncRec.lock(Exclusive);
 
+	// firstRecord is the oldest, remove and add to stack.
+
 	while (firstRecord)
 		{
 		record = firstRecord;
@@ -397,6 +399,8 @@ void Transaction::rollback()
 		
 	lastRecord = NULL;
 
+	// Stack is newest to oldest.
+
 	while (stack)
 		{
 		record = stack;
@@ -1543,7 +1547,7 @@ void Transaction::backlogRecords(void)
 		// Be sure this is the base record.  Backlog all chilled records 
 		// and deleted records, but not lock records
 
-		if (   !record->isSuperceded()
+		if (   record->isBase()
 		    && (   record->isChilled()
 		        || record->isDeleted() ))
 			{
@@ -1596,6 +1600,10 @@ bool Transaction::committedBefore(TransI
 	return (transactionState->commitId && transactionState->commitId < transactionId);
 }
 
+// Called at 'transaction complete' time to thaw any records 
+// that are already updated to a newer version.  At this time, 
+// the record can still be found in the serial log.
+
 void Transaction::thawAll(void)
 {
 	Sync syncRec(&syncRecords,"Transaction::thawAll");
@@ -1607,7 +1615,7 @@ void Transaction::thawAll(void)
 	for (RecordVersion *record = firstRecord; record && record->nextInTrans; record = record->nextInTrans)
 		{
 		totalRecords++;
-		if (record->isChilled())
+		if (record->isChilled()&& !record->isBase())

 			{
 			totalThawed++;
 			record->getRecordData();

=== modified file 'storage/falcon/ha_falcon.cpp'
--- a/storage/falcon/ha_falcon.cpp	2009-05-20 10:41:39 +0000
+++ b/storage/falcon/ha_falcon.cpp	2009-06-28 18:58:38 +0000
@@ -1,4 +1,4 @@
-/* Copyright ⌐ 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+/* Copyright (c) 2006-2008 MySQL AB, 2008-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
@@ -91,6 +91,10 @@ extern StorageHandler	*storageHandler;
 #undef PARAMETER_UINT
 #undef PARAMETER_BOOL
 
+// Unique name assigned by server to the primary key
+
+extern const char *primary_key_name;
+
 ulonglong	falcon_record_memory_max;
 ulonglong	falcon_serial_log_file_size;
 uint		falcon_allocation_extent;
@@ -252,7 +256,8 @@ int StorageInterface::falcon_init(void *
 	//falcon_hton->show_status  = StorageInterface::show_status;
 	falcon_hton->flags = HTON_NO_FLAGS;
 	falcon_debug_mask&= ~(LogMysqlInfo|LogMysqlWarning|LogMysqlError);
-	storageHandler->addNfsLogger(falcon_debug_mask, StorageInterface::logger, NULL);
+	int falconDebugMask = falcon_debug_mask | LogDefaultMask;
+	storageHandler->addNfsLogger(falconDebugMask, StorageInterface::logger, NULL);
 	storageHandler->addNfsLogger(LogMysqlInfo|LogMysqlWarning|LogMysqlError, StorageInterface::mysqlLogger, NULL);
 
 	if (falcon_debug_server)
@@ -470,7 +475,7 @@ StorageInterface::StorageInterface(handl
 	activeBlobs = NULL;
 	freeBlobs = NULL;
 	errorText = NULL;
-	fieldMap = NULL;
+	fieldMap.storageInterface = this;
 	indexOrder = false;
 	
 	if (table_arg)
@@ -482,7 +487,6 @@ StorageInterface::StorageInterface(handl
 	tableFlags = default_table_flags;
 }
 
-
 StorageInterface::~StorageInterface(void)
 {
 	if (storageTable)
@@ -509,7 +513,7 @@ StorageInterface::~StorageInterface(void
 		storageConnection = NULL;
 		}
 
-	unmapFields();
+	fieldMap.unmapFields();
 }
 
 int StorageInterface::rnd_init(bool scan)
@@ -584,7 +588,7 @@ int StorageInterface::open(const char *n
 
 	// Map fields for Falcon record encoding
 	
-	mapFields(table);
+	fieldMap.mapFields(table);
 	
 	// Map server indexes to Falcon internal indexes
 	
@@ -606,7 +610,7 @@ int StorageInterface::close(void)
 	if (storageTable)
 		storageTable->clearCurrentIndex();
 
-	unmapFields();
+	fieldMap.unmapFields();
 
 	// Temporarily comment out DTrace probes in Falcon, see bug #36403
 	// FALCON_CLOSE();
@@ -909,22 +913,20 @@ int StorageInterface::create(const char 
 	if ((ret = storageTable->create(gen.getString(), incrementValue)))
 		{
 		storageTable->deleteTable();
-		
 		DBUG_RETURN(error(ret));
 		}
 
 	for (n = 0; n < form->s->keys; ++n)
-		if (n != form->s->primary_key)
+		if (!isPrimaryKey(form, n))
 			if ((ret = createIndex(schemaName, tableName, form, n)))
 				{
 				storageTable->deleteTable();
-
 				DBUG_RETURN(error(ret));
 				}
 
 	// Map fields for Falcon record encoding
 	
-	mapFields(form);
+	fieldMap.mapFields(form);
 	
 	// Map server indexes to Falcon indexes
 	
@@ -1586,6 +1588,19 @@ ha_rows StorageInterface::records_in_ran
 	DBUG_RETURN(MAX(guestimate, 2));
 }
 
+bool StorageInterface::isPrimaryKey(TABLE *srvTable, uint indexId)
+{
+	uint primaryKey = srvTable->s->primary_key;
+	
+	// If primary_key != MAX_KEY, then the key is either a primary key or
+	// a unique key with all non-NULL columns. Check the key name to
+	// distinguish between them. The primary key is always "PRIMARY". 
+	
+	return (indexId == primaryKey &&
+			primaryKey != MAX_KEY &&
+			!strcmp(srvTable->s->key_info[primaryKey].name, primary_key_name));
+}
+
 void StorageInterface::getKeyDesc(TABLE *srvTable, int indexId, StorageIndexDesc *indexDesc)
 {
 	KEY *keyInfo = srvTable->key_info + indexId;
@@ -1594,7 +1609,7 @@ void StorageInterface::getKeyDesc(TABLE 
 	indexDesc->id			  = indexId;
 	indexDesc->numberSegments = numberKeys;
 	indexDesc->unique		  = (keyInfo->flags & HA_NOSAME);
-	indexDesc->primaryKey	  = (srvTable->s->primary_key == (uint)indexId);
+	indexDesc->primaryKey	  = isPrimaryKey(srvTable, indexId);
 	
 	// Clean up the index name for internal use
 	
@@ -2151,7 +2166,7 @@ int StorageInterface::getMySqlError(int 
 			DBUG_PRINT("info", ("StorageErrorBadKey"));
 			return (HA_ERR_WRONG_INDEX);
 
-		case StorageErrorTableExits:
+		case StorageErrorTableExists:
 			DBUG_PRINT("info", ("StorageErrorTableExits"));
 			return (HA_ERR_TABLE_EXIST);
 
@@ -2213,6 +2228,10 @@ int StorageInterface::getMySqlError(int 
 			DBUG_PRINT("info", ("StorageErrorIOErrorSerialLog"));
 			return (HA_ERR_LOGGING_IMPOSSIBLE);
 
+		case StorageErrorRecordDeleted:
+			DBUG_PRINT("info", ("StorageErrorRecordDeleted"));
+			return (HA_ERR_RECORD_DELETED);
+
 		default:
 			DBUG_PRINT("info", ("Unknown Falcon Error"));
 			return (200 - storageError);
@@ -2553,10 +2572,6 @@ int StorageInterface::addColumn(THD* thd
 {
 	int ret;
 	int64 incrementValue = 0;
-	/***
-	const char *tableName = storageTable->getName();
-	const char *schemaName = storageTable->getSchemaName();
-	***/
 	CmdGen gen;
 	genTable(alteredTable, &gen);
 	
@@ -2584,6 +2599,8 @@ int StorageInterface::addColumn(THD* thd
 	if ((ret = storageTable->upgrade(gen.getString(), incrementValue)))
 		return (error(ret));
 
+	fieldMap.remapFields(alteredTable);
+	
 	return 0;
 }
 
@@ -2683,7 +2700,7 @@ uint StorageInterface::max_supported_key
 
 void StorageInterface::logger(int mask, const char* text, void* arg)
 {
-	if (mask & falcon_debug_mask)
+	if (mask & (falcon_debug_mask | LogDefaultMask))
 		{
 		printf("%s", text);
 		fflush(stdout);
@@ -2809,7 +2826,9 @@ int StorageInterface::genTable(TABLE* sr
 		sep = ",\n";
 		}
 
-	if (srvTable->s->primary_key < srvTable->s->keys)
+	// Confirm that primary_key is actually a primary key
+		
+	if (isPrimaryKey(srvTable, srvTable->s->primary_key))
 		{
 		KEY *key = srvTable->key_info + srvTable->s->primary_key;
 		gen->gen(",\n  primary key ");
@@ -2976,15 +2995,27 @@ void StorageInterface::encodeRecord(ucha
 	storageTable->preInsert(&dataStream);
 	my_ptrdiff_t ptrDiff = buf - table->record[0];
 	my_bitmap_map *old_map = dbug_tmp_use_all_columns(table, table->read_set);
-	FieldFormat *fieldFormat = storageShare->format->format;
-	int maxId = storageShare->format->maxId;
+
+	// Default format for the table, possibly newer than the record format
+	
+	FieldFormat *tableFormat = storageShare->format->format;
+
+	// Maximum field definitions for the table
+	
+	int tableMaxId = storageShare->format->maxId;
+	
+	// Maximum field definitions for the current record
 	
-	for (int n = 0; n < maxId; ++n, ++fieldFormat)
+	int recordMaxId = (updateFlag ? storageTable->format->maxId : tableMaxId);
+	
+	for (int id = 0; id < tableMaxId; ++id, ++tableFormat)
 		{
-		if (fieldFormat->fieldId < 0 || fieldFormat->offset == 0)
+		if (tableFormat->fieldId < 0 || tableFormat->offset == 0)
 			continue;
 			
-		Field *field = fieldMap[fieldFormat->fieldId];
+		// Get the field definition
+		
+		Field *field = fieldMap[tableFormat->fieldId];
 		ASSERT(field);
 		
 		if (ptrDiff)
@@ -2992,8 +3023,17 @@ void StorageInterface::encodeRecord(ucha
 
 		if (updateFlag && !bitmap_is_set(table->write_set, field->field_index))
 			{
-			const unsigned char *p = storageTable->getEncoding(n);
-			dataStream.encodeEncoding(p);
+			// Online ALTER ADD COLUMN may have extended the default record format
+			// of the table beyond that of the existing rows. If the current field
+			// is not defined for this record, set the field to NULL.
+			
+			if (id >= recordMaxId)
+				dataStream.encodeNull();
+			else
+				{
+				const unsigned char *p = storageTable->getEncoding(id);
+				dataStream.encodeEncoding(p);
+				}
 			}
 		else if (field->is_null())
 			dataStream.encodeNull();
@@ -3179,40 +3219,33 @@ void StorageInterface::decodeRecord(ucha
 
 	// Format of this record
 
-	FieldFormat *fieldFormat = storageTable->format->format;
+	FieldFormat *recordFormat = storageTable->format->format;
 	int maxId = storageTable->format->maxId;
 	
-	// Current format for the table, possibly newer than the record format
+	// Default format for the table, possibly newer than the record format
 	
 	int tableMaxId = storageTable->share->format->maxId;
-	FieldFormat *tableFieldFormat = storageTable->share->format->format;
+	FieldFormat *tableFormat = storageTable->share->format->format;
+	
+	// Update the field map if it was changed on another thread
+
+	if (fieldMap.maxFields < tableMaxId)
+		fieldMap.remapFields(table);
 	
-	for (int n = 0; n < tableMaxId; ++n, ++fieldFormat, ++tableFieldFormat)
+	for (int id = 0; id < tableMaxId; ++id, ++recordFormat, ++tableFormat)
 		{
-		// Online ALTER ADD COLUMN creates a new record format for the table
-		// that will have more fields than the older formats associated with
-		// existing rows.
-		//
-		// Currently, online ALTER ADD COLUMN only supports nullable columns and
-		// no default value. If the format of this record has fewer fields
-		// than the default format of the table, then there are no fields to
-		// decode beyond maxId, so set them to NULL.
+		dataStream.decode();
+
+		Field *field = NULL;
 		
-		if (n >= maxId)
-			{
-			Field *newField = fieldMap[tableFieldFormat->fieldId];
-			newField->set_null();
-			newField->reset();
-			continue;
-			}
-	
-		// If the format doesn't have an offset, the field doesn't exist in the record
+		// Get the field definition id from the format associated with the current record.
+		// If the field is undefined for this record, then get the field id from the
+		// default table format and set the field to NULL.
 		
-		if (fieldFormat->fieldId < 0 || fieldFormat->offset == 0)
-			continue;
-			
-		dataStream.decode();
-		Field *field = fieldMap[fieldFormat->fieldId];
+		if (id < maxId)
+			field = fieldMap[recordFormat->fieldId];
+		else
+			field = fieldMap[tableFormat->fieldId];
 
 		// If we don't have a field for the physical field, just skip over it and don't worry
 		
@@ -3924,7 +3957,8 @@ void StorageInterface::updateDebugMask(M
 	falcon_debug_mask = *(uint*) save;
 	falcon_debug_mask&= ~(LogMysqlInfo|LogMysqlWarning|LogMysqlError);
 	storageHandler->deleteNfsLogger(StorageInterface::logger, NULL);
-	storageHandler->addNfsLogger(falcon_debug_mask, StorageInterface::logger, NULL);
+	int falconDebugMask = falcon_debug_mask | LogDefaultMask;
+	storageHandler->addNfsLogger(falconDebugMask, StorageInterface::logger, NULL);
 }
 
 int StorageInterface::recover (handlerton * hton, XID *xids, uint length)
@@ -3948,17 +3982,41 @@ int StorageInterface::recover (handlerto
 	DBUG_RETURN(count);
 }
 
+FieldMap::FieldMap(StorageInterface *storageInt, TABLE *srvTable)
+					: storageInterface(storageInt)
+{
+	if (!srvTable || !storageInterface)
+		{
+		fields = NULL;
+		maxFields = 0;
+		return;
+		}
+		
+	mapFields(srvTable);
+}
+
+FieldMap::~FieldMap()
+{
+	unmapFields();
+}
+
+Field* FieldMap::operator[](int id)
+{
+	return ((fields && id < maxFields) ? fields[id] : NULL);
+}
+
 // Build a record field map for use by encode/decodeRecord()
 
-void StorageInterface::mapFields(TABLE *srvTable)
+void FieldMap::mapFields(TABLE *srvTable)
 {
-	if (!srvTable)
+	if (!srvTable || !storageInterface)
 		return;
 	
-	maxFields = storageShare->format->maxId;
+	StorageTableShare *storageShare = storageInterface->storageShare;
 	unmapFields();
-	fieldMap = new Field*[maxFields];
-	memset(fieldMap, 0, sizeof(fieldMap[0]) * maxFields);
+	maxFields = storageShare->format->maxId;
+	fields = new Field*[maxFields];
+	memset(fields, 0, sizeof(fields[0]) * maxFields);
 	char nameBuffer[256];
 
 	for (uint n = 0; n < srvTable->s->fields; ++n)
@@ -3968,17 +4026,24 @@ void StorageInterface::mapFields(TABLE *
 		int id = storageShare->getFieldId(nameBuffer);
 		
 		if (id >= 0)
-			fieldMap[id] = field;
+			fields[id] = field;
 		}
 }
 
-void StorageInterface::unmapFields(void)
+void FieldMap::unmapFields(void)
 {
-	if (fieldMap)
+	if (fields)
 		{
-		delete []fieldMap;
-		fieldMap = NULL;
+		delete[] fields;
+		fields = NULL;
 		}
+	maxFields = 0;
+}
+
+void FieldMap::remapFields(TABLE *srvTable)
+{
+	unmapFields();
+	mapFields(srvTable);
 }
 
 static MYSQL_SYSVAR_STR(serial_log_dir, falcon_serial_log_dir,

=== modified file 'storage/falcon/ha_falcon.h'
--- a/storage/falcon/ha_falcon.h	2009-01-15 20:29:54 +0000
+++ b/storage/falcon/ha_falcon.h	2009-06-28 18:58:38 +0000
@@ -13,6 +13,7 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
+class StorageInterface;
 class StorageConnection;
 class StorageTable;
 class StorageTableShare;
@@ -32,6 +33,22 @@ struct TABLE_SHARE;
 class StorageIndexDesc;
 struct StorageBlob;
 
+class FieldMap
+{
+public:
+	FieldMap(void) : storageInterface(NULL), fields(NULL), maxFields(0) {};
+	FieldMap(StorageInterface *storageInt, TABLE *srvTable = NULL);
+	~FieldMap(void);
+	void mapFields(TABLE *srvTable);
+	void unmapFields(void);
+	void remapFields(TABLE *srvTable);
+	Field* operator[](int id);
+
+	StorageInterface *storageInterface;
+	Field **fields;
+	int maxFields;
+};
+
 class StorageInterface : public handler
 {
 public:
@@ -129,6 +146,7 @@ public:
 	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);
+	bool			isPrimaryKey(TABLE *srvTable, uint indexId);
 	void			startTransaction(void);
 	bool			threadSwitch(THD *newThread);
 	int				threadSwitchError(void);
@@ -194,12 +212,12 @@ public:
 	StorageConnection*	storageConnection;
 	StorageTable*		storageTable;
 	StorageTableShare*	storageShare;
-	Field					**fieldMap;
+	FieldMap			fieldMap;
 	const char*			errorText;
 	THR_LOCK_DATA		lockData;			// MySQL lock
 	THD					*mySqlThread;
 	TABLE_SHARE			*share;
-	uint					recordLength;
+	uint				recordLength;
 	int					lastRecord;
 	int					nextRecord;
 	int					indexErrorId;
@@ -207,12 +225,12 @@ public:
 	int					maxFields;
 	StorageBlob			*activeBlobs;
 	StorageBlob			*freeBlobs;
-	bool					haveStartKey;
-	bool					haveEndKey;
-	bool					tableLocked;
-	bool					tempTable;
-	bool					lockForUpdate;
-	bool					indexOrder;
+	bool				haveStartKey;
+	bool				haveEndKey;
+	bool				tableLocked;
+	bool				tempTable;
+	bool				lockForUpdate;
+	bool				indexOrder;
 	key_range			startKey;
 	key_range			endKey;
 	uint64				insertCount;

Attachment: [text/bzr-bundle] bzr/kevin.lewis@sun.com-20090708200522-1nd2ln8e335fxfi0.bundle
Thread
bzr push into mysql-6.0-falcon-team branch (kevin.lewis:2743 to 2753)Bug#45746Kevin Lewis8 Jul