MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Christopher Powers Date:January 22 2009 6:40pm
Subject:bzr commit into mysql-6.0-falcon-team branch (christopher.powers:2970)
Bug#39678
View as plain text  
#At file:///home/cpowers/work/dev/dev-04/mysql/

 2970 Christopher Powers	2009-01-22
      Bug #39678 Assertion (bdb) fails in IndexRootPage::indexMerge during recovery
            
      Improved synchronization between concurrent DROP INDEX and INSERT/UPDATE operations
      on the same table.
modified:
  storage/falcon/Index.cpp
  storage/falcon/SRLUpdateIndex.cpp
  storage/falcon/SerialLog.cpp
  storage/falcon/Table.cpp

per-file messages:
  storage/falcon/Index.cpp
    Index::deleteIndex()
    - Set indexId == -1 before writing SRLDeleteIndex to the serial log.
  storage/falcon/SRLUpdateIndex.cpp
    SRLUpdateIndex::append()
    - Check indexId == -1 inside of the syncIndexes lock
    - Ignore DeferredIndexes with indexId == -1
  storage/falcon/SerialLog.cpp
    Added recovery progress log messages
  storage/falcon/Table.cpp
    Table::insertIndexes()
    - Protect Index::insert() from concurrent DDL
=== modified file 'storage/falcon/Index.cpp'
--- a/storage/falcon/Index.cpp	2009-01-15 20:29:54 +0000
+++ b/storage/falcon/Index.cpp	2009-01-22 18:40:02 +0000
@@ -406,8 +406,14 @@ void Index::deleteIndex(Transaction *tra
 {
 	if (!damaged && indexId != -1)
 		{
-		dbb->deleteIndex(indexId, indexVersion, TRANSACTION_ID(transaction));
+
+		// The Index class does not use a Sync object. To ensure that concurrent
+		// SRLUpdateIndex operations ignore DeferredIndexes associated with
+		// this index, set indexId to -1 before writing to the Serial Log.
+
+		int id = indexId;
 		indexId = -1;
+		dbb->deleteIndex(id, indexVersion, TRANSACTION_ID(transaction));
 		}
 }
 

=== modified file 'storage/falcon/SRLUpdateIndex.cpp'
--- a/storage/falcon/SRLUpdateIndex.cpp	2008-11-14 15:38:44 +0000
+++ b/storage/falcon/SRLUpdateIndex.cpp	2009-01-22 18:40:02 +0000
@@ -40,21 +40,28 @@ SRLUpdateIndex::~SRLUpdateIndex(void)
 
 void SRLUpdateIndex::append(DeferredIndex* deferredIndex)
 {
+	// To ensure coordination with a concurrent SRLDeleteIndex, grab syncIndexes
+	// before getting the index id from the DeferredIndex.
+
+	Sync syncIndexes(&log->syncIndexes, "SRLUpdateIndex::append(Indexes)");
+	syncIndexes.lock(Shared);
+	
 	Sync syncDI(&deferredIndex->syncObject, "SRLUpdateIndex::append(DI)");
 	syncDI.lock(Shared);
 
-	if (!deferredIndex->index)
-		return;
+	Index* index = deferredIndex->index;
 
-	uint indexId = deferredIndex->index->indexId;
-	int idxVersion = deferredIndex->index->indexVersion;
-	int tableSpaceId = deferredIndex->index->dbb->tableSpaceId;
+	// A null index or indexId == -1 means that the index has been deleted
+	
+	if (!index || index->indexId == -1)
+		return;
+	
+	int idxId = index->indexId;
+	int idxVersion = index->indexVersion;
+	int tableSpaceId = index->dbb->tableSpaceId;
 
 	syncDI.unlock();
 
-	Sync syncIndexes(&log->syncIndexes, "SRLUpdateIndex::append(Indexes)");
-	syncIndexes.lock(Shared);
-
 	Transaction *transaction = deferredIndex->transaction;
 	DeferredIndexWalker walker(deferredIndex, NULL);
 	uint64 virtualOffset = 0;
@@ -70,7 +77,7 @@ void SRLUpdateIndex::append(DeferredInde
 		if (virtualOffset == 0)
 			virtualOffset = log->startRecordVirtualOffset;
 
-		log->updateIndexUseVector(indexId, tableSpaceId, 1);
+		log->updateIndexUseVector(idxId, tableSpaceId, 1);
 		SerialLogTransaction *srlTrans = log->getTransaction(transaction->transactionId);
 		srlTrans->setTransaction(transaction);
 		ASSERT(transaction->writePending);
@@ -79,7 +86,7 @@ void SRLUpdateIndex::append(DeferredInde
 		
 		putInt(tableSpaceId);
 		putInt(transaction->transactionId);
-		putInt(indexId);
+		putInt(idxId);
 		putInt(idxVersion);
 		
 		// Initialize the length field, adjust with correct length later.
@@ -105,7 +112,7 @@ void SRLUpdateIndex::append(DeferredInde
 			}
 		
 		int len = (int) (log->writePtr - start);
-		//printf("SRLUpdateIndex::append tid %d, index %d, length %d, ptr %x (%x)\n",  transaction->transactionId, indexId, len, lengthPtr, org);
+		//printf("SRLUpdateIndex::append tid %d, index %d, length %d, ptr %x (%x)\n",  transaction->transactionId, idxId, len, lengthPtr, org);
 		ASSERT(len >= 0);
 
 		// Update the length field

=== modified file 'storage/falcon/SerialLog.cpp'
--- a/storage/falcon/SerialLog.cpp	2008-11-20 17:05:50 +0000
+++ b/storage/falcon/SerialLog.cpp	2009-01-22 18:40:02 +0000
@@ -51,6 +51,7 @@ static const char THIS_FILE[]=__FILE__;
 #endif
 
 static const int TRACE_PAGE = 0;
+static const int RECORD_MAX = 100000;
 
 extern uint falcon_gopher_threads;
 extern uint64 falcon_serial_log_file_size;
@@ -284,9 +285,9 @@ void SerialLog::recover()
 	SerialLogBlock *recoveryBlock = recoveryWindow->firstBlock();
 	recoveryBlockNumber = recoveryBlock->blockNumber;
 	SerialLogBlock *lastBlock = findLastBlock(recoveryWindow);
-	Log::log("first recovery block is " I64FORMAT "\n", 
+	Log::log("/nFirst recovery block is " I64FORMAT "\n", 
 			(otherWindow) ? otherWindow->firstBlock()->blockNumber : recoveryBlockNumber);
-	Log::log("last recovery block is " I64FORMAT "\n", lastBlock->blockNumber);
+	Log::log("Last recovery block is " I64FORMAT "\n", lastBlock->blockNumber);
 
 	if (otherWindow)
 		{
@@ -306,7 +307,7 @@ void SerialLog::recover()
 	if (readBlockNumber == 0)
 		readBlockNumber = lastBlock->blockNumber;
 		
-	Log::log("recovery read block is " I64FORMAT "\n", readBlockNumber);
+	Log::log("Recovery read block is " I64FORMAT "\n", readBlockNumber);
 	nextBlockNumber = lastBlock->blockNumber + 1;
 	lastWindow->deactivateWindow();
 	SerialLogWindow *window = findWindowGivenBlock(readBlockNumber);
@@ -328,11 +329,20 @@ void SerialLog::recover()
 	recoveryIndexes = new RecoveryObjects(this);
 	recoveryPhase = 1;	// Take Inventory (serialLogTransactions, recoveryObject states, last checkpoint)
 	
-	// Make a first pass finding records, transactions, etc.
+	Log::log("Recovery phase 1...\n");
+
+	unsigned long int recordCount = 0;
 
 	while ( (record = control.nextRecord()) )
+		{
+		if (++recordCount % RECORD_MAX == 0)
+			Log::log("Processed: %8ld\n", recordCount);
+			
 		record->pass1();
+		}
 
+	Log::log("Processed: %8ld\n", recordCount);
+	
 	//control.debug = false;
 	pass1 = false;
 	control.setWindow(window, block, 0);
@@ -344,9 +354,19 @@ void SerialLog::recover()
 
 	// Next, make a second pass to reallocate any necessary pages
 
+	Log::log("\nRecovery phase 2...\n");
+	recordCount = 0;
+	
 	while ( (record = control.nextRecord()) )
+		{
+		if (++recordCount % RECORD_MAX == 0)
+			Log::log("Processed: %8ld\n", recordCount);
+			
 		if (!isTableSpaceDropped(record->tableSpaceId) || record->type == srlDropTableSpace)
 			record->pass2();
+		}
+
+	Log::log("Processed: %8ld\n", recordCount);
 
 	recoveryPages->reset();
 	recoveryIndexes->reset();
@@ -363,10 +383,19 @@ void SerialLog::recover()
 
 	// Make a third pass doing things
 
+	Log::log("\nRecovery phase 3...\n");
+	recordCount = 0;
+	
 	while ( (record = control.nextRecord()) )
+		{
+		if (++recordCount % RECORD_MAX == 0)
+			Log::log("Processed: %8ld\n", recordCount);
+			
 		if (!isTableSpaceDropped(record->tableSpaceId))
 			record->redo();
-
+		}
+		
+	Log::log("Processed: %8ld\n", recordCount);
 
 	for (SerialLogTransaction *action, **ptr = &running.first; (action = *ptr);)
 		if (action->completedRecovery())

=== modified file 'storage/falcon/Table.cpp'
--- a/storage/falcon/Table.cpp	2009-01-17 08:51:59 +0000
+++ b/storage/falcon/Table.cpp	2009-01-22 18:40:02 +0000
@@ -1255,24 +1255,33 @@ void Table::insertIndexes(Transaction *t
 {
 	if (indexes)
 		{
+		Sync syncTable(&syncObject, "Table::insertIndexes");
+		
 		FOR_INDEXES(index, this);
-			Sync sync(&index->syncUnique, "Table::insertIndexes");
+			Sync syncUnique(&index->syncUnique, "Table::insertIndexes");
 			
 			if (needUniqueCheck(index,record))
 				for(;;)
 					{
-					sync.lock(Exclusive);
+					syncUnique.lock(Exclusive);
 					
-					if(!checkUniqueIndex(index, transaction, record, &sync))
+					if(!checkUniqueIndex(index, transaction, record, &syncUnique))
 						break;
 					}
 				
-			index->insert(record, transaction);
+			// Block concurrent DDL with a shared lock. Double-check the
+			// index id in case the index was deleted.
+			
+			syncTable.lock(Shared);
+
+			if (index->indexId != -1)
+				index->insert(record, transaction);
+
+				syncTable.unlock();
 		END_FOR;
 		}
 }
 
-
 void Table::update(Transaction * transaction, Record * oldRecord, int numberFields, Field** updateFields, Value * * values)
 {
 	database->preUpdate();

Thread
bzr commit into mysql-6.0-falcon-team branch (christopher.powers:2970)Bug#39678Christopher Powers22 Jan