List:Commits« Previous MessageNext Message »
From:Kevin Lewis Date:August 25 2008 8:35pm
Subject:RE: bzr commit into mysql-6.0-falcon branch (vvaintroub:2798) Bug#38933
View as plain text  
Vlad,

It looks like Transaction::dropTable still locks syncIndexes outside
releaseDeferredIndexes().

>-----Original Message-----
>From: Vladislav Vaintroub [mailto:vvaintroub@stripped]
>Sent: Friday, August 22, 2008 3:34 PM
>To: commits@stripped
>Subject: bzr commit into mysql-6.0-falcon branch (vvaintroub:2798)
Bug#38933
>
>#At file:///C:/bzr/mysql-6.0-falcon-team/
>
> 2798 Vladislav Vaintroub	2008-08-22
>      Bug#38933 - Falcon crash in Transaction::hasRecords during concurrent
>DDL
>
>      The problem is that Transaction::hasRecords traverses  transaction's
>record
>      list while a concurrent operation (rollback, writeComplete,addRecord)
>may
>      concurrently modify it.
>
>      This patch removed whacko-reuse of the Transaction::syncIndexes to
>protect
>      the record list and introduces new lock Transaction::syncRecords for
>exactly
>      this purpose.
>
>      (hopefully) all places where the list is read or modified are now
>protected
>      by this lock. When the list is freed, firstRecord  is set to NULL to
>prevent
>      crash in parallel Transaction::hasRecords() can crash.
>modified:
>  storage/falcon/Transaction.cpp
>  storage/falcon/Transaction.h
>
>=== modified file 'storage/falcon/Transaction.cpp'
>--- a/storage/falcon/Transaction.cpp	2008-08-22 15:01:12 +0000
>+++ b/storage/falcon/Transaction.cpp	2008-08-22 20:33:40 +0000
>@@ -86,6 +86,7 @@ Transaction::Transaction(Connection *cnc
> 	syncObject.setName("Transaction::syncObject");
> 	syncActive.setName("Transaction::syncActive");
> 	syncIndexes.setName("Transaction::syncIndexes");
>+	syncRecords.setName("Transaction::syncRecords");
> 	syncSavepoints.setName("Transaction::syncSavepoints");
> 	firstRecord = NULL;
> 	lastRecord = NULL;
>@@ -216,20 +217,19 @@ Transaction::~Transaction()
> 	delete backloggedRecords;
> 	chillPoint = &firstRecord;
>
>+	Sync syncRec(&syncRecords,"Transaction::~Transaction");
>+	syncRec.lock(Exclusive);
> 	for (RecordVersion *record; (record = firstRecord);)
> 		{
>-		removeRecord(record);
>+		removeRecordNoLock(record);
> 		}
>+	firstRecord = NULL;
>+	syncRec.unlock();
>
> 	releaseSavepoints();
>
> 	if (deferredIndexes)
>-		{
>-		Sync sync(&syncIndexes, "Transaction::~Transaction");
>-		sync.lock(Exclusive);
>-
> 		releaseDeferredIndexes();
>-		}
> }
>
> void Transaction::commit()
>@@ -279,6 +279,8 @@ void Transaction::commit()
>
>
>
>+	Sync syncRec(&syncRecords,"Transaction::commit(1.5)");
>+	syncRec.lock(Shared);
> 	for (RecordVersion *record = firstRecord; record; record = record-
>>nextInTrans)
> 	{
> 		Table * table = record->format->table;
>@@ -295,7 +297,8 @@ void Transaction::commit()
> 		if (record->state == recDeleted && table->cardinality > 0)
> 			--table->cardinality;
> 	}
>-
>+	syncRec.unlock();
>+
> 	releaseDependencies();
> 	database->flushInversion(this);
>
>@@ -341,11 +344,7 @@ void Transaction::commitNoUpdates(void)
> 	++transactionManager->committed;
>
> 	if (deferredIndexes)
>-		{
>-		Sync sync(&syncIndexes, "Transaction::commitNoUpdates(1)");
>-		sync.lock(Exclusive);
> 		releaseDeferredIndexes();
>-		}
>
> 	if (hasLocks)
> 		releaseRecordLocks();
>@@ -387,11 +386,7 @@ void Transaction::rollback()
> 		throw SQLEXCEPTION (RUNTIME_ERROR, "transaction is not
active");
>
> 	if (deferredIndexes)
>-		{
>-		Sync sync(&syncIndexes, "Transaction::rollback(1)");
>-		sync.lock(Exclusive);
> 		releaseDeferredIndexes();
>-		}
>
> 	releaseSavepoints();
> 	TransactionManager *transactionManager =
database->transactionManager;
>@@ -403,8 +398,8 @@ void Transaction::rollback()
> 	// Rollback pending record versions from newest to oldest in case
> 	// there are multiple record versions on a prior record chain
>
>-	Sync sync(&syncIndexes, "Transaction::rollback(1.5)");
>-	sync.lock(Exclusive);
>+	Sync syncRec(&syncRecords, "Transaction::rollback(1.5)");
>+	syncRec.lock(Exclusive);
>
> 	while (firstRecord)
> 		{
>@@ -432,7 +427,7 @@ void Transaction::rollback()
> 		record->release();
> 		}
> 	firstRecord = NULL;
>-	sync.unlock();
>+	syncRec.unlock();
>
> 	for (SavePoint *savePoint = savePoints; savePoint; savePoint =
>savePoint->next)
> 		if (savePoint->backloggedRecords)
>@@ -626,6 +621,8 @@ void Transaction::addRecord(RecordVersio
>
> 	record->addRef();
>
>+	Sync syncRec(&syncRecords,"Transaction::addRecord");
>+	syncRec.lock(Exclusive);
> 	if ( (record->prevInTrans = lastRecord) )
> 		lastRecord->nextInTrans = record;
> 	else
>@@ -633,6 +630,7 @@ void Transaction::addRecord(RecordVersio
>
> 	record->nextInTrans = NULL;
> 	lastRecord = record;
>+	syncRec.unlock();
>
> 	if (database->lowMemory && deletedRecords > MAX_LOW_MEMORY_RECORDS)
> 		backlogRecords();
>@@ -640,6 +638,12 @@ void Transaction::addRecord(RecordVersio
>
> void Transaction::removeRecord(RecordVersion *record)
> {
>+	Sync syncRec(&syncRecords,"Transaction::removeRecord");
>+	syncRec.lock(Exclusive);
>+	removeRecordNoLock(record);
>+}
>+void Transaction::removeRecordNoLock(RecordVersion *record)
>+{
> 	RecordVersion **ptr;
>
> 	if (record->nextInTrans)
>@@ -805,6 +809,8 @@ void Transaction::releaseDependencies()
>
> void Transaction::commitRecords()
> {
>+	Sync syncRec(&syncRecords,"Transaction::commitRecords");
>+	syncRec.lock(Exclusive);
> 	for (RecordVersion *recordList; (recordList = firstRecord);)
> 		{
> 		if (recordList && COMPARE_EXCHANGE_POINTER(&firstRecord,
>recordList, NULL))
>@@ -912,9 +918,11 @@ void Transaction::dropTable(Table* table
> 	sync.lock(Exclusive);
>
> 	releaseDeferredIndexes(table);
>+	sync.unlock();
>
>-	// Keep exclusive lock to avoid race condition with writeComplete
>-
>+
>+	Sync syncRec(&syncRecords,"Transaction::dropTable(2)");
>+	syncRec.lock(Exclusive);
> 	for (RecordVersion **ptr = &firstRecord, *rec; (rec = *ptr);)
> 		if (rec->format->table == table)
> 			removeRecord(rec);
>@@ -928,9 +936,10 @@ void Transaction::truncateTable(Table* t
> 	sync.lock(Exclusive);
>
> 	releaseDeferredIndexes(table);
>+	sync.unlock();
>
>-	// Keep exclusive lock to avoid race condition with writeComplete
>-
>+	Sync syncRec(&syncRecords,"Transaction::truncateTable(2)");
>+	syncRec.lock(Exclusive);
> 	for (RecordVersion **ptr = &firstRecord, *rec; (rec = *ptr);)
> 		if (rec->format->table == table)
> 			removeRecord(rec);
>@@ -940,9 +949,8 @@ void Transaction::truncateTable(Table* t
>
> bool Transaction::hasRecords(Table* table)
> {
>-	// This lock is to avoid race with writeComplete
>-	Sync sync(&syncIndexes, "Transaction::hasRecords");
>-	sync.lock(Exclusive);
>+	Sync syncRec(&syncRecords, "Transaction::hasRecords");
>+	syncRec.lock(Shared);
> 	for (RecordVersion *rec = firstRecord; rec; rec = rec->nextInTrans)
> 		if (rec->format->table == table)
> 			return true;
>@@ -957,14 +965,12 @@ void Transaction::writeComplete(void)
> 	Sync sync(&syncIndexes, "Transaction::writeComplete");
> 	sync.lock(Exclusive);
> 	releaseDeferredIndexes();
>-
>-	// Keep the synIndexes lock to avoid a race condition with dropTable
>+	sync.unlock();
>
> 	if (dependencies == 0)
> 		commitRecords();
>
> 	writePending = false;
>-	sync.unlock();
> }
>
> bool Transaction::waitForTransaction(TransId transId)
>@@ -1248,6 +1254,7 @@ void Transaction::rollbackSavepoint(int
>
> 	savePoint = savePoints;
>
>+
> 	while (savePoint)
> 		{
> 		//validateRecords();
>@@ -1256,6 +1263,8 @@ void Transaction::rollbackSavepoint(int
> 			break;
>
> 		// Purge out records from this savepoint
>+		Sync
syncRec(&syncRecords,"Transaction::rollbackSavepoint(2)");
>+		sync.lock(Exclusive);
>
> 		RecordVersion *record = *savePoint->records;
> 		RecordVersion *stack = NULL;
>@@ -1295,6 +1304,7 @@ void Transaction::rollbackSavepoint(int
> 			rec->transaction = NULL;
> 			rec->release();
> 			}
>+		syncRec.unlock();
>
> 		// Handle any backlogged records
>
>@@ -1340,6 +1350,8 @@ void Transaction::releaseRecordLocks(voi
> 	RecordVersion **ptr;
> 	RecordVersion *record;
>
>+	Sync syncRec(&syncRecords,"Transaction::releaseRecordLocks");
>+	syncRec.lock(Exclusive);
> 	for (ptr = &firstRecord; (record = *ptr);)
> 		if (record->state == recLock)
> 			{
>@@ -1348,6 +1360,7 @@ void Transaction::releaseRecordLocks(voi
> 			}
> 		else
> 			ptr = &record->nextInTrans;
>+	syncRec.unlock();
> }
>
> void Transaction::print(void)
>@@ -1365,6 +1378,8 @@ void Transaction::printBlocking(int leve
> 	int deletes = 0;
> 	RecordVersion *record;
>
>+	Sync syncRec(&syncRecords,"Transaction::printBlocking");
>+	syncRec.lock(Shared);
> 	for (record = firstRecord; record; record = record->nextInTrans)
> 		if (record->state == recLock)
> 			++locks;
>@@ -1412,7 +1427,7 @@ void Transaction::printBlocking(int leve
> 				   record->recordNumber,
> 				   what);
> 		}
>-
>+	syncRec.unlock();
> 	database->transactionManager->printBlocking(this, level);
> }
>
>@@ -1450,14 +1465,7 @@ void Transaction::releaseDependency(void
> 	INTERLOCKED_DECREMENT(dependencies);
>
> 	if ((dependencies == 0) && !writePending && firstRecord)
>-		{
>-		// The Sync is to avoid a race with writeComplete().  It
looks
>whacko, but does the trick
>-
>-		Sync sync(&syncIndexes, "Transaction::releaseDependency");
>-		sync.lock(Exclusive);
> 		commitRecords();
>-		}
>-
> 	releaseCommittedTransaction();
> }
>
>@@ -1502,6 +1510,8 @@ void Transaction::printBlockage(void)
>
> void Transaction::releaseDeferredIndexes(void)
> {
>+	Sync sync(&syncIndexes, "Transaction::releaseDeferredIndexes");
>+	sync.lock(Exclusive);
> 	for (DeferredIndex *deferredIndex; (deferredIndex =
deferredIndexes);)
> 		{
> 		ASSERT(deferredIndex->transaction == this);
>@@ -1559,7 +1569,8 @@ void Transaction::backlogRecords(void)
> void Transaction::validateRecords(void)
> {
> 	RecordVersion *record;
>-
>+	Sync syncRec(&syncRecords,"Transaction::validateRecords");
>+	syncRec.lock(Shared);
> 	for (record = firstRecord; record && record->nextInTrans; record =
>record->nextInTrans)
> 		;
>
>
>=== modified file 'storage/falcon/Transaction.h'
>--- a/storage/falcon/Transaction.h	2008-08-11 13:22:53 +0000
>+++ b/storage/falcon/Transaction.h	2008-08-22 20:33:40 +0000
>@@ -87,7 +87,8 @@ public:
>
> 	State		getRelativeState(Record* record, uint32 flags);
> 	State		getRelativeState (Transaction *transaction, TransId
>transId, uint32 flags);
>-	void		removeRecord (RecordVersion *record);
>+	void		removeRecordNoLock (RecordVersion *record);
>+	void		removeRecord(RecordVersion *record);
> 	void		removeRecord (RecordVersion *record, RecordVersion
>**ptr);
> 	void		expungeTransaction (Transaction *transaction);
> 	void		commitRecords();
>@@ -171,6 +172,7 @@ public:
> 	SyncObject		syncObject;
> 	SyncObject		syncActive;
> 	SyncObject		syncIndexes;
>+	SyncObject		syncRecords;
> 	SyncObject		syncSavepoints;
> 	uint64			totalRecordData;	// total bytes of
record data
>for this transaction (unchilled + thawed)
> 	uint32			totalRecords;		// total record
count
>
>
>--
>MySQL Code Commits Mailing List
>For list archives: http://lists.mysql.com/commits
>To unsubscribe:    http://lists.mysql.com/commits?unsub=1

Thread
bzr commit into mysql-6.0-falcon branch (vvaintroub:2798) Bug#38933Vladislav Vaintroub22 Aug
  • RE: bzr commit into mysql-6.0-falcon branch (vvaintroub:2798) Bug#38933Kevin Lewis25 Aug
  • RE: bzr commit into mysql-6.0-falcon branch (vvaintroub:2798) Bug#38933Kevin Lewis25 Aug
    • RE: bzr commit into mysql-6.0-falcon branch (vvaintroub:2798) Bug#38933Vladislav Vaintroub25 Aug
      • RE: bzr commit into mysql-6.0-falcon branch (vvaintroub:2798) Bug#38933Kevin Lewis25 Aug