#At file:///G:/bzr/mysql-6.0-falcon/
2937 Vladislav Vaintroub 2008-12-15 [merge]
merge from 6.0-falcon-team
modified:
.bzr-mysql/default.conf
mysql-test/suite/falcon/r/falcon_bug_32398.result
mysql-test/suite/falcon/t/disabled.def
mysql-test/suite/falcon/t/falcon_bug_32398.test
storage/falcon/Transaction.cpp
storage/falcon/Transaction.h
storage/falcon/TransactionManager.cpp
storage/falcon/TransactionManager.h
storage/falcon/TransformLib/StringTransform.cpp
storage/falcon/ha_falcon.cpp
=== modified file '.bzr-mysql/default.conf'
--- a/.bzr-mysql/default.conf 2008-12-09 20:23:30 +0000
+++ b/.bzr-mysql/default.conf 2008-12-11 10:57:28 +0000
@@ -1,5 +1,5 @@
[MYSQL]
-tree_location = bzr+ssh://bk-internal.mysql.com/bzrroot/server/mysql-6.0-falcon
+tree_location = bzr+ssh://bk-internal.mysql.com/bzrroot/server/mysql-6.0-falcon-team
post_commit_to = commits@stripped
post_push_to = commits@stripped
-tree_name = mysql-6.0-falcon
+tree_name = mysql-6.0-falcon-team
=== modified file 'mysql-test/suite/falcon/r/falcon_bug_32398.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_32398.result 2008-04-10 11:28:11 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_32398.result 2008-12-15 08:36:44 +0000
@@ -1,7 +1,20 @@
-CREATE TABLESPACE ts1 ADD DATAFILE 'test/ts1.fts' ENGINE=falcon;
-ERROR HY000: Incorrect arguments to DATAFILE
-CREATE TABLESPACE ts1 ADD DATAFILE 'TEST_DIR/master-data/test/ts1.fts'
-ENGINE=falcon;
-ERROR HY000: Incorrect arguments to DATAFILE
-CREATE TABLESPACE ts1 ADD DATAFILE 'ts1.fts' ENGINE=falcon;
-DROP TABLESPACE ts1 ENGINE=falcon;
+*** Bug #32398 ***
+SET @@storage_engine = 'Falcon';
+CREATE TABLESPACE ts1 ADD DATAFILE 'ts1.fts' ENGINE=Falcon;
+CREATE TABLESPACE ts2 ADD DATAFILE 'ts2.MYD' ENGINE=Falcon;
+CREATE TABLESPACE ts3 ADD DATAFILE 'ts3' ENGINE=Falcon;
+CREATE TABLESPACE ts4 ADD DATAFILE 'ts4test' ENGINE=Falcon;
+CREATE TABLESPACE ts5 ADD DATAFILE '' ENGINE=Falcon;
+ERROR HY000: Malformed file path ''
+SELECT TABLESPACE_NAME, FILE_NAME FROM INFORMATION_SCHEMA.FILES;
+TABLESPACE_NAME FILE_NAME
+FALCON_USER falcon_user.fts
+FALCON_TEMPORARY falcon_temporary.fts
+ts1 ts1.fts
+ts2 ts2.MYD.fts
+ts3 ts3.fts
+ts4 ts4test.fts
+DROP TABLESPACE ts1 ENGINE=Falcon;
+DROP TABLESPACE ts2 ENGINE=Falcon;
+DROP TABLESPACE ts3 ENGINE=Falcon;
+DROP TABLESPACE ts4 ENGINE=Falcon;
=== modified file 'mysql-test/suite/falcon/t/disabled.def'
--- a/mysql-test/suite/falcon/t/disabled.def 2008-12-10 16:55:09 +0000
+++ b/mysql-test/suite/falcon/t/disabled.def 2008-12-15 08:36:44 +0000
@@ -10,5 +10,4 @@
#
##############################################################################
-falcon_bug_32398 : Bug#32398 2008-08-28 HF HF disabled until new fix for this bug is developed
falcon_bug_28095 : Bug#40636 2008-12-10 hky Disabled until soft server restart works reliable
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_32398.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_32398.test 2008-04-10 11:28:11 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_32398.test 2008-12-15 08:36:44 +0000
@@ -1,14 +1,35 @@
--source include/have_falcon.inc
#
-# BUG#32398 - Falcon: tablespace file can be table file
+# Bug #32398: Falcon: tablespace file can be table file
#
-#CREATE TABLE t1(a INT) DATA DIRECTORY='mysql';
---error ER_WRONG_ARGUMENTS
-CREATE TABLESPACE ts1 ADD DATAFILE 'test/ts1.fts' ENGINE=falcon;
---replace_result $MYSQLTEST_VARDIR TEST_DIR
---error ER_WRONG_ARGUMENTS
-eval CREATE TABLESPACE ts1 ADD DATAFILE '$MYSQLTEST_VARDIR/master-data/test/ts1.fts'
-ENGINE=falcon;
-CREATE TABLESPACE ts1 ADD DATAFILE 'ts1.fts' ENGINE=falcon;
-DROP TABLESPACE ts1 ENGINE=falcon;
+--echo *** Bug #32398 ***
+
+# ----------------------------------------------------- #
+# --- Initialisation --- #
+# ----------------------------------------------------- #
+let $engine = 'Falcon';
+eval SET @@storage_engine = $engine;
+
+# ----------------------------------------------------- #
+# --- Test --- #
+# ----------------------------------------------------- #
+CREATE TABLESPACE ts1 ADD DATAFILE 'ts1.fts' ENGINE=Falcon;
+CREATE TABLESPACE ts2 ADD DATAFILE 'ts2.MYD' ENGINE=Falcon;
+CREATE TABLESPACE ts3 ADD DATAFILE 'ts3' ENGINE=Falcon;
+CREATE TABLESPACE ts4 ADD DATAFILE 'ts4test' ENGINE=Falcon;
+--error ER_BAD_PATH
+CREATE TABLESPACE ts5 ADD DATAFILE '' ENGINE=Falcon;
+
+# ----------------------------------------------------- #
+# --- Check --- #
+# ----------------------------------------------------- #
+SELECT TABLESPACE_NAME, FILE_NAME FROM INFORMATION_SCHEMA.FILES;
+
+# ----------------------------------------------------- #
+# --- Final cleanup --- #
+# ----------------------------------------------------- #
+DROP TABLESPACE ts1 ENGINE=Falcon;
+DROP TABLESPACE ts2 ENGINE=Falcon;
+DROP TABLESPACE ts3 ENGINE=Falcon;
+DROP TABLESPACE ts4 ENGINE=Falcon;
=== modified file 'storage/falcon/Transaction.cpp'
--- a/storage/falcon/Transaction.cpp 2008-11-20 17:05:50 +0000
+++ b/storage/falcon/Transaction.cpp 2008-12-09 23:11:13 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -49,6 +49,10 @@
extern uint falcon_lock_wait_timeout;
+extern volatile int Talloc; // These are temporary for debug tracing
+extern volatile int Tdelete; // of number of allocated transaction objects.
+
+
static const char *stateNames [] = {
"Active",
"Limbo",
@@ -78,8 +82,8 @@ static const char THIS_FILE[]=__FILE__;
Transaction::Transaction(Connection *cnct, TransId seq)
{
- states = NULL;
- statesAllocated = 0;
+ Talloc++;
+
savePoints = NULL;
freeSavePoints = NULL;
useCount = 1;
@@ -90,7 +94,6 @@ Transaction::Transaction(Connection *cnc
syncSavepoints.setName("Transaction::syncSavepoints");
firstRecord = NULL;
lastRecord = NULL;
- dependencies = 0;
initialize(cnct, seq);
}
@@ -101,7 +104,6 @@ void Transaction::initialize(Connection*
ASSERT(savePoints == NULL);
ASSERT(freeSavePoints == NULL);
ASSERT(firstRecord == NULL);
- ASSERT(dependencies == 0);
connection = cnct;
isolationLevel = connection->isolationLevel;
mySqlThreadId = connection->mySqlThreadId;
@@ -109,6 +111,7 @@ void Transaction::initialize(Connection*
TransactionManager *transactionManager = database->transactionManager;
systemTransaction = database->systemConnection == connection;
transactionId = seq;
+ commitId = 0;
chillPoint = &firstRecord;
commitTriggers = false;
hasUpdates = false;
@@ -132,7 +135,6 @@ void Transaction::initialize(Connection*
debugThawedRecords = 0;
debugThawedBytes = 0;
committedRecords = 0;
- numberStates = 0;
blockedBy = 0;
deletedRecords = 0;
inList = true;
@@ -160,46 +162,13 @@ void Transaction::initialize(Connection*
syncIsActive.lock(NULL, Exclusive);
Transaction *oldest = transactionManager->findOldest();
oldestActive = (oldest) ? oldest->transactionId : transactionId;
- int count = transactionManager->activeTransactions.count;
-
- if (count > statesAllocated)
- {
- delete [] states;
- statesAllocated = count;
- states = new TransState[statesAllocated];
- }
-
- if (count)
- for (Transaction *transaction = transactionManager->activeTransactions.first; transaction; transaction = transaction->next)
- if (transaction->isActive() &&
- !transaction->systemTransaction &&
- transaction->transactionId < transactionId)
- {
- Sync syncDependency(&transaction->syncObject, "Transaction::initialize(2)");
- syncDependency.lock(Shared);
-
- if (transaction->isActive() &&
- !transaction->systemTransaction &&
- transaction->transactionId < transactionId)
- {
- transaction->addRef();
- INTERLOCKED_INCREMENT(transaction->dependencies);
- TransState *state = states + numberStates;
- state->transaction = transaction;
- state->transactionId = transaction->transactionId;
- state->state = transaction->state;
- ++numberStates;
- ASSERT(transaction->transactionId == state->transactionId);
- }
- }
-
state = Active;
}
Transaction::~Transaction()
{
- ASSERT(dependencies == 0);
-
+ Tdelete++;
+
if (state == Active)
{
Log::debug("Deleting apparently active transaction %d\n", transactionId);
@@ -212,7 +181,6 @@ Transaction::~Transaction()
if (inList)
database->transactionManager->removeTransaction(this);
- delete [] states;
delete [] xid;
delete backloggedRecords;
chillPoint = &firstRecord;
@@ -244,7 +212,6 @@ void Transaction::commit()
if (!hasUpdates)
{
commitNoUpdates();
-
return;
}
@@ -297,7 +264,6 @@ void Transaction::commit()
}
syncRec.unlock();
- releaseDependencies();
database->flushInversion(this);
// Transfer transaction from active list to committed list, set committed state
@@ -308,10 +274,21 @@ void Transaction::commit()
syncActiveTransactions.lock(Exclusive);
syncCommitted.lock(Exclusive);
+ // Set the commit transition id for this transaction
+
+ commitId = INTERLOCKED_INCREMENT(transactionManager->transactionSequence);
+
transactionManager->activeTransactions.remove(this);
transactionManager->committedTransactions.append(this);
state = Committed;
+ // This is one of the few points where we have an exclusive lock on both the
+ // active and committed transaction list. Although this has nothing to do
+ // with the commit of this transaction we use the opportunity to clean up
+ // old transaction objects
+
+ transactionManager->purgeTransactionsWithLocks();
+
syncCommitted.unlock();
syncActiveTransactions.unlock();
@@ -324,9 +301,6 @@ void Transaction::commit()
xidLength = 0;
// If there's no reason to stick around, just go away
-
- if ((dependencies == 0) && !writePending)
- commitRecords();
connection = NULL;
@@ -352,7 +326,6 @@ void Transaction::commitNoUpdates(void)
Sync syncActiveTransactions(&transactionManager->activeTransactions.syncObject, "Transaction::commitNoUpdates(2)");
syncActiveTransactions.lock(Shared);
- releaseDependencies();
if (xid)
{
@@ -363,10 +336,7 @@ void Transaction::commitNoUpdates(void)
Sync sync(&syncObject, "Transaction::commitNoUpdates(3)");
sync.lock(Exclusive);
-
- if (dependencies)
- transactionManager->expungeTransaction(this);
-
+
// If there's no reason to stick around, just go away
connection = NULL;
@@ -441,7 +411,6 @@ void Transaction::rollback()
ASSERT(writePending);
writePending = false;
- releaseDependencies();
if (hasUpdates)
database->serialLog->preCommit(this);
@@ -458,11 +427,7 @@ void Transaction::rollback()
Sync syncActiveTransactions (&transactionManager->activeTransactions.syncObject, "Transaction::rollback(active)");
syncActiveTransactions.lock (Exclusive);
++transactionManager->rolledBack;
-
- while (dependencies)
- transactionManager->expungeTransaction(this);
-
- ASSERT(dependencies == 0);
+
inList = false;
transactionManager->activeTransactions.remove(this);
syncActiveTransactions.unlock();
@@ -472,20 +437,6 @@ void Transaction::rollback()
}
-void Transaction::expungeTransaction(Transaction * transaction)
-{
- ASSERT(states != NULL || numberStates == 0);
-
- for (TransState *s = states, *end = s + numberStates; s < end; ++s)
- if (s->transaction == transaction)
- {
- if (COMPARE_EXCHANGE_POINTER(&s->transaction, transaction, NULL))
- transaction->releaseDependency();
-
- break;
- }
-}
-
void Transaction::prepare(int xidLen, const UCHAR *xidPtr)
{
if (state != Active)
@@ -750,11 +701,11 @@ bool Transaction::visible(Transaction *
if (transId > transactionId)
return false;
- // If the transaction was active when we started, use it's state at that point
+ // If the other transaction committed after we started then it should not
+ // be visible to us
- for (int n = 0; n < numberStates; ++n)
- if (states [n].transactionId == transId)
- return false;
+ if (transaction->commitId > transactionId)
+ return false;
return true;
}
@@ -790,26 +741,6 @@ bool Transaction::needToLock(Record* rec
return false;
}
-void Transaction::releaseDependencies()
-{
- if (!numberStates)
- return;
-
- for (TransState *state = states, *end = states + numberStates; state < end; ++state)
- {
- Transaction *transaction = state->transaction;
-
- if (transaction)
- {
- if (COMPARE_EXCHANGE_POINTER(&state->transaction, transaction, NULL))
- {
- ASSERT(transaction->transactionId == state->transactionId || transaction->transactionId == 0);
- ASSERT(transaction->state != Initializing);
- transaction->releaseDependency();
- }
- }
- }
-}
/*
* Transaction is fully mature and about to go away.
@@ -852,6 +783,14 @@ void Transaction::commitRecords()
State Transaction::getRelativeState(Record* record, uint32 flags)
{
+ // If this is a Record object it has no assosiated transaction
+ // and is always visible
+
+ if (!record->isVersion())
+ {
+ return CommittedVisible;
+ }
+
blockingRecord = record;
State state = getRelativeState(record->getTransaction(), record->getTransactionId(), flags);
blockingRecord = NULL;
@@ -880,14 +819,22 @@ State Transaction::getRelativeState(Tran
// If the transaction is no longer around, and the record is,
// then it must be committed.
+ // Check if the transaction started after us.
+ // With the old dependency manager this test might have been
+ // hit but with the new dependency manager this will never
+ // happen. Still leave it in until further evaluation.
+
if (transactionId < transId)
return CommittedInvisible;
// Be sure it was not active when we started.
- for (int n = 0; n < numberStates; ++n)
- if (states [n].transactionId == transId)
- return CommittedInvisible;
+ // The dependency manager ensures that transactions that were
+ // active at the time this transaction started will not be
+ // deleted at least not until also we are committed.
+ // Since the transaction pointer is NULL here,
+ // the transaction is not deleted and hence was not active at
+ // the time we started.
}
return CommittedVisible;
@@ -962,9 +909,6 @@ void Transaction::writeComplete(void)
ASSERT(writePending);
ASSERT(state == Committed);
releaseDeferredIndexes();
-
- if (dependencies == 0)
- commitRecords();
// Log::log(LogXARecovery, "%d: WriteComplete %sTransaction %d\n",
// database->deltaTime, (systemTransaction ? "System " : ""), transactionId);
@@ -1371,9 +1315,9 @@ void Transaction::releaseRecordLocks(voi
void Transaction::print(void)
{
- Log::debug(" %p Id %d, state %d, updates %d, wrtPend %d, states %d, dependencies %d, records %d\n",
+ Log::debug(" %p Id %d, state %d, updates %d, wrtPend %d, records %d\n",
this, transactionId, state, hasUpdates, writePending,
- numberStates, dependencies, firstRecord != NULL);
+ firstRecord != NULL);
}
void Transaction::printBlocking(int level)
@@ -1439,7 +1383,12 @@ void Transaction::printBlocking(int leve
void Transaction::getInfo(InfoTable* infoTable)
{
- if (!(state == Available && dependencies == 0))
+ // NOTE: The field for number of dependencies will be removed in
+ // a follow-up patch.
+ // Need to decide if we want to include the startEvent and endEvent
+ // in this table.
+
+ if (!(state == Available))
{
int n = 0;
infoTable->putString(n++, stateNames[state]);
@@ -1447,7 +1396,7 @@ void Transaction::getInfo(InfoTable* inf
infoTable->putInt(n++, transactionId);
infoTable->putInt(n++, hasUpdates);
infoTable->putInt(n++, writePending);
- infoTable->putInt(n++, dependencies);
+ infoTable->putInt(n++, 0); // Number of dependencies, will be removed
infoTable->putInt(n++, oldestActive);
infoTable->putInt(n++, firstRecord != NULL);
infoTable->putInt(n++, (waitingFor) ? waitingFor->transactionId : 0);
@@ -1464,17 +1413,6 @@ void Transaction::getInfo(InfoTable* inf
}
}
-void Transaction::releaseDependency(void)
-{
- ASSERT(useCount >= 2);
- ASSERT(dependencies > 0);
- INTERLOCKED_DECREMENT(dependencies);
-
- if ((dependencies == 0) && !writePending && firstRecord)
- commitRecords();
- releaseCommittedTransaction();
-}
-
void Transaction::fullyCommitted(void)
{
ASSERT(inList);
@@ -1488,22 +1426,13 @@ void Transaction::fullyCommitted(void)
void Transaction::releaseCommittedTransaction(void)
{
- release();
+ // NOTE: consider to just move the call to release() to where this method is called.
+ // Leave it in here in case we want to check for being able to delete the transaction
+ // object here.
- if ((useCount == 1) && (state == Committed) && (dependencies == 0) && !writePending)
- if (COMPARE_EXCHANGE(&inList, (INTERLOCK_TYPE) true, (INTERLOCK_TYPE) false))
- database->transactionManager->removeCommittedTransaction(this);
+ release();
}
-void Transaction::validateDependencies(bool noDependencies)
-{
- for (TransState *state = states, *end = states + numberStates; state < end; ++state)
- if (state->transaction)
- {
- ASSERT(!noDependencies);
- ASSERT(state->transaction->transactionId == state->transactionId);
- }
-}
void Transaction::printBlockage(void)
{
=== modified file 'storage/falcon/Transaction.h'
--- a/storage/falcon/Transaction.h 2008-10-02 23:20:47 +0000
+++ b/storage/falcon/Transaction.h 2008-12-03 13:20:17 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -90,9 +90,7 @@ public:
void removeRecordNoLock (RecordVersion *record);
void removeRecord(RecordVersion *record);
void removeRecord (RecordVersion *record, RecordVersion **ptr);
- void expungeTransaction (Transaction *transaction);
void commitRecords();
- void releaseDependencies();
bool visible (Transaction *transaction, TransId transId, int forWhat);
bool needToLock(Record* record);
void addRecord (RecordVersion *record);
@@ -108,7 +106,6 @@ public:
void truncateTable(Table* table);
bool hasRecords(Table* table);
void writeComplete(void);
- void releaseDependency(void);
int createSavepoint();
void releaseSavepoint(int savepointId);
void releaseSavepoints(void);
@@ -127,7 +124,6 @@ public:
void fullyCommitted(void);
void releaseCommittedTransaction(void);
void commitNoUpdates(void);
- void validateDependencies(bool noDependencies);
void validateRecords(void);
void printBlocking(int level);
void releaseDeferredIndexes(void);
@@ -141,7 +137,8 @@ public:
Connection *connection;
Database *database;
- TransId transactionId;
+ TransId transactionId; // used also as startEvent by dep.mgr.
+ TransId commitId; // used as commitEvent by dep.mgr.
TransId oldestActive;
TransId blockedBy;
int curSavePointId;
@@ -157,12 +154,10 @@ public:
Bitmap *backloggedRecords;
time_t startTime;
int deferredIndexCount;
- int statesAllocated;
int isolationLevel;
int xidLength;
int mySqlThreadId;
UCHAR *xid;
- TransState *states;
bool commitTriggers;
bool systemTransaction;
bool hasUpdates;
@@ -187,9 +182,7 @@ public:
RecordVersion **chillPoint; // points to a pointer to the first non-chilled record
int scanIndexCount;
- volatile int numberStates;
volatile INTERLOCK_TYPE state;
- volatile INTERLOCK_TYPE dependencies;
volatile INTERLOCK_TYPE useCount;
volatile INTERLOCK_TYPE inList;
=== modified file 'storage/falcon/TransactionManager.cpp'
--- a/storage/falcon/TransactionManager.cpp 2008-10-24 10:20:10 +0000
+++ b/storage/falcon/TransactionManager.cpp 2008-12-10 15:53:21 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -15,6 +15,7 @@
#include <memory.h>
+#include <limits.h>
#include "Engine.h"
#include "TransactionManager.h"
#include "Transaction.h"
@@ -31,11 +32,16 @@
static const int EXTRA_TRANSACTIONS = 10;
+static TransId OLD = 0; // Temporary for debugging
+
#ifdef _DEBUG
#undef THIS_FILE
static const char THIS_FILE[]=__FILE__;
#endif
+volatile int Talloc = 0; // Temp. will be removed. Used for tracing
+volatile int Tdelete = 0; // new and delete of trans objects.
+
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
@@ -108,42 +114,65 @@ Transaction* TransactionManager::findOld
return oldest;
}
+
+TransId TransactionManager::findOldestInActiveList() const
+{
+ // Find the transaction id of the oldest active transaction in the
+ // active transaction list. If the list is empty, the
+ // latest allocated transaction id will be returned.
+ // This method assumes that the caller have set at least a shared lock
+ // on the active list.
+
+ // Note: Here we operate on a transaction list where we allow
+ // non-locking transaction allocations and de-allocations from so be
+ // careful when updating this method.
+
+ // NOTE: This needs to be updated when we allow transaction id to wrap
+
+ TransId oldest = transactionSequence;
+
+ for (Transaction *transaction = activeTransactions.first; transaction; transaction = transaction->next)
+ {
+ TransId transId = transaction->transactionId;
+ if (transaction->isActive() && (transId != 0 && transId < oldest))
+ oldest = transId;
+ }
+
+ return oldest;
+}
+
+
Transaction* TransactionManager::startTransaction(Connection* connection)
{
+ // Go through the active transaction list to check if there are any
+ // transaction objects in state "Available" that can be re-used.
+ // Note that this is done using a shared lock on the active transaction
+ // list.
+
Sync sync (&activeTransactions.syncObject, "TransactionManager::startTransaction");
- sync.lock (Shared);
+ sync.lock(Shared);
Transaction *transaction;
- for (transaction = activeTransactions.first; transaction; transaction = transaction->next)
- if (transaction->state == Available && transaction->dependencies == 0)
+ for(transaction = activeTransactions.first; transaction; transaction = transaction->next)
+ if (transaction->state == Available)
if (COMPARE_EXCHANGE(&transaction->state, Available, Initializing))
{
- // Check again that the dependencies are zero. The transaction
- // object might have been re-use between the previous if-test
- // and the actual change of state
-
- if (transaction->dependencies != 0)
- {
- // Return the transaction object back to the list
-
- transaction->state = Available;
- }
- else
- {
- ASSERT(transaction->dependencies == 0);
- transaction->initialize(connection, INTERLOCKED_INCREMENT(transactionSequence));
-
- return transaction;
- }
+ transaction->initialize(connection, INTERLOCKED_INCREMENT(transactionSequence));
+ return transaction;
}
sync.unlock();
+
+ // We did not find an available transaction object to re-use,
+ // so we allocate a new and add to the active list
+
sync.lock(Exclusive);
- transaction = new Transaction (connection, INTERLOCKED_INCREMENT(transactionSequence));
+ transaction = new Transaction(connection, INTERLOCKED_INCREMENT(transactionSequence));
activeTransactions.append(transaction);
- // And, just for yucks, add another 10 Available transactions
+ // Since we have acquired the exclusive lock on the active transaction
+ // list we allocate some extra transaction objects for future use
for (int n = 0; n < EXTRA_TRANSACTIONS; ++n)
{
@@ -300,32 +329,70 @@ void TransactionManager::getTransactionI
transaction->getInfo(infoTable);
}
+
void TransactionManager::purgeTransactions()
{
+ // This method is called by the scavenger to clean up old committed
+ // transactions.
+
+ // To purge the committed transaction list requires at least
+ // a shared lock on the active transaction list and an exclusive
+ // lock on the committed transaction list
+
+ Sync syncActive(&activeTransactions.syncObject, "TransactionManager::purgeTransaction");
+ syncActive.lock(Shared);
+
Sync syncCommitted(&committedTransactions.syncObject, "Transaction::purgeTransactions");
syncCommitted.lock(Exclusive);
-
+
+ purgeTransactionsWithLocks();
+
+}
+
+
+void TransactionManager::purgeTransactionsWithLocks()
+{
+ // Removes old committed transaction from the committed transaction list
+ // that no longer is visible by any currently active transactions.
+ // Note that this method relies on that the caller have at least a
+ // shared lock on the active transaction list and an exclusive lock on
+ // the committed transaction list
+
+ // Find the transaction id of the oldest active transaction
+
+ TransId oldestActive = findOldestInActiveList();
+
+ ASSERT(oldestActive >= OLD); // Temporary for debugging
+ OLD = oldestActive; // Please ignore
+
// Check for any fully mature transactions to ditch
-
- for (Transaction *transaction, *next = committedTransactions.first; (transaction = next);)
+
+ Transaction* transaction = committedTransactions.first;
+
+ while ((transaction != NULL) &&
+ (transaction->state == Committed) &&
+ (transaction->commitId < oldestActive) &&
+ !transaction->writePending)
{
- next = transaction->next;
+ transaction->commitRecords();
- if ((transaction->state == Committed) &&
- (transaction->dependencies == 0) &&
- !transaction->writePending)
+ if (COMPARE_EXCHANGE(&transaction->inList, (INTERLOCK_TYPE) true, (INTERLOCK_TYPE) false))
{
- transaction->commitRecords();
+ committedTransactions.remove(transaction);
+ transaction->release();
+ }
+ else
+ {
+ // If the compare and exchange operation failed we re-try this transaction on the next call
- if (COMPARE_EXCHANGE(&transaction->inList, (INTERLOCK_TYPE) true, (INTERLOCK_TYPE) false))
- {
- committedTransactions.remove(transaction);
- transaction->release();
- }
+ break;
}
+
+ transaction = committedTransactions.first;
}
}
+
void TransactionManager::getSummaryInfo(InfoTable* infoTable)
{
Sync syncActive (&activeTransactions.syncObject, "TransactionManager::getSummaryInfo(2)");
@@ -374,7 +441,6 @@ void TransactionManager::reportStatistic
Transaction *transaction;
int active = 0;
int available = 0;
- int dependencies = 0;
time_t maxTime = 0;
for (transaction = activeTransactions.first; transaction; transaction = transaction->next)
@@ -387,9 +453,6 @@ void TransactionManager::reportStatistic
else if (transaction->state == Available)
{
++available;
-
- if (transaction->dependencies)
- ++dependencies;
}
int pendingCleanup = committedTransactions.count;
@@ -399,8 +462,8 @@ void TransactionManager::reportStatistic
priorRolledBack = rolledBack;
if ((active || numberCommitted || numberRolledBack) && Log::isActive(LogInfo))
- Log::log (LogInfo, "%d: Transactions: %d committed, %d rolled back, %d active, %d/%d available, %d post-commit, oldest %d seconds\n",
- database->deltaTime, numberCommitted, numberRolledBack, active, available, dependencies, pendingCleanup, maxTime);
+ Log::log (LogInfo, "%d: Transactions: %d committed, %d rolled back, %d active, %d available, %d post-commit, oldest %d seconds\n",
+ database->deltaTime, numberCommitted, numberRolledBack, active, available, pendingCleanup, maxTime);
}
void TransactionManager::removeCommittedTransaction(Transaction* transaction)
@@ -412,16 +475,6 @@ void TransactionManager::removeCommitted
transaction->release();
}
-void TransactionManager::expungeTransaction(Transaction *transaction)
-{
- Sync syncActiveTrans(&activeTransactions.syncObject, "TransactionManager::removeTransaction");
- syncActiveTrans.lock(Shared);
-
- for (Transaction *trans = activeTransactions.first; trans; trans = trans->next)
- if ((trans->state != Available && trans->state != Initializing))
- //&& trans->transactionId > transaction->transactionId)
- trans->expungeTransaction(transaction);
-}
Transaction* TransactionManager::findTransaction(TransId transactionId)
{
@@ -445,24 +498,6 @@ Transaction* TransactionManager::findTra
return NULL;
}
-void TransactionManager::validateDependencies(void)
-{
- Sync syncActive(&activeTransactions.syncObject, "TransactionManager::validateDepedendencies(1)");
- syncActive.lock(Shared);
- Transaction *transaction;
-
- for (transaction = activeTransactions.first; transaction; transaction = transaction->next)
- if (transaction->isActive())
- transaction->validateDependencies(false);
-
- syncActive.unlock();
-
- Sync syncCommitted(&committedTransactions.syncObject, "TransactionManager::validateDepedendencies(2)");
- syncCommitted.lock(Shared);
-
- for (transaction = committedTransactions.first; transaction; transaction = transaction->next)
- transaction->validateDependencies(true);
-}
void TransactionManager::removeTransaction(Transaction* transaction)
{
=== modified file 'storage/falcon/TransactionManager.h'
--- a/storage/falcon/TransactionManager.h 2008-08-11 13:22:53 +0000
+++ b/storage/falcon/TransactionManager.h 2008-12-09 09:01:41 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -40,13 +40,13 @@ public:
void rollbackByXid(int xidLength, const UCHAR* xid);
void print(void);
Transaction* findOldest(void);
+ TransId findOldestInActiveList() const;
void getTransactionInfo(InfoTable* infoTable);
void purgeTransactions();
+ void purgeTransactionsWithLocks();
void getSummaryInfo(InfoTable* infoTable);
void reportStatistics(void);
- void expungeTransaction(Transaction *transaction);
Transaction* findTransaction(TransId transactionId);
- void validateDependencies(void);
void removeCommittedTransaction(Transaction* transaction);
void removeTransaction(Transaction* transaction);
void printBlockage(void);
=== modified file 'storage/falcon/TransformLib/StringTransform.cpp'
--- a/storage/falcon/TransformLib/StringTransform.cpp 2007-09-20 15:44:25 +0000
+++ b/storage/falcon/TransformLib/StringTransform.cpp 2008-12-10 14:11:41 +0000
@@ -39,7 +39,7 @@ StringTransform::StringTransform()
StringTransform::~StringTransform()
{
- delete data;
+ delete [] data;
}
StringTransform::StringTransform(const char *string, bool copyFlag)
=== modified file 'storage/falcon/ha_falcon.cpp'
--- a/storage/falcon/ha_falcon.cpp 2008-12-01 22:18:34 +0000
+++ b/storage/falcon/ha_falcon.cpp 2008-12-15 08:36:44 +0000
@@ -2105,7 +2105,8 @@ int StorageInterface::alter_tablespace(h
{
DBUG_ENTER("NfsStorageEngine::alter_tablespace");
int ret = 0;
-
+ const char *data_file_name= ts_info->data_file_name;
+ char buff[FN_REFLEN];
/*
CREATE TABLESPACE tablespace
ADD DATAFILE 'file'
@@ -2125,28 +2126,30 @@ int StorageInterface::alter_tablespace(h
for NDB only.
*/
- /*
- Sergey Vojtovich is to reconsider this code
-
- if (ts_info->data_file_name)
+ if (data_file_name)
{
- char buff[FN_REFLEN];
- size_t dirname_part_length;
- dirname_part(buff, ts_info->data_file_name, &dirname_part_length);
- fn_format(buff, buff, mysql_real_data_home, "",
- MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
- if (test_if_data_home_dir(buff))
+ size_t length= strlen(data_file_name);
+ if (length <= 4 || strcmp(data_file_name + length - 4, ".fts"))
{
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "DATAFILE");
- DBUG_RETURN(1);
+ if (!length || length > FN_REFLEN - 5)
+ {
+ my_error(ER_BAD_PATH, MYF(0), data_file_name);
+ DBUG_RETURN(1);
+ }
+ memcpy(buff, data_file_name, length);
+ buff[length]= '.';
+ buff[length + 1]= 'f';
+ buff[length + 2]= 't';
+ buff[length + 3]= 's';
+ buff[length + 4]= '\0';
+ data_file_name= buff;
}
}
- */
switch (ts_info->ts_cmd_type)
{
case CREATE_TABLESPACE:
- ret = storageHandler->createTablespace( ts_info->tablespace_name, ts_info->data_file_name, ts_info->ts_comment);
+ ret = storageHandler->createTablespace( ts_info->tablespace_name, data_file_name, ts_info->ts_comment);
break;
case DROP_TABLESPACE:
@@ -3673,7 +3676,7 @@ static MYSQL_SYSVAR_UINT(allocation_exte
static MYSQL_SYSVAR_ULONGLONG(page_cache_size, falcon_page_cache_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"The amount of memory to be used for the database page cache.",
- NULL, NULL, LL(4)<<20, LL(2)<<20, (ulonglong) ~0, LL(1)<<20);
+ NULL, NULL, LL(4)<<20, LL(2)<<20, (ulonglong) max_memory_address, LL(1)<<20);
static MYSQL_THDVAR_BOOL(consistent_read, PLUGIN_VAR_OPCMDARG,
"Enable Consistent Read Mode for Repeatable Reads",
| Thread |
|---|
| • bzr commit into mysql-6.0-falcon-team branch (vvaintroub:2937) | Vladislav Vaintroub | 15 Dec |