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#45746 | Kevin Lewis | 8 Jul |