From: Date: September 30 2008 8:17pm Subject: bzr commit into mysql-6.0-falcon-team branch (klewis:2843) Bug#39321 List-Archive: http://lists.mysql.com/commits/54804 X-Bug: 39321 Message-Id: <200809301817.m8UIH3jh011182@mail.mysql.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit #At file:///C:/Work/bzr/Merge/mysql-6.0-falcon-team/ 2843 Kevin Lewis 2008-09-30 Bug#39321 Add an exclusive lock on Database::syncScavenge in Database::truncateTable before the lock of Table::syncObject just in case the truncateTable process has to call Database::forceRecordScavenge. syncScavenge must be locked before Table::syncObject because the scavenger does it that way. According to the Deadlock Predictor (SyncHandler.cpp), syncScavenge must also be locked before Database::syncTables. modified: storage/falcon/Database.cpp === modified file 'storage/falcon/Database.cpp' --- a/storage/falcon/Database.cpp 2008-09-11 10:56:00 +0000 +++ b/storage/falcon/Database.cpp 2008-09-30 18:17:19 +0000 @@ -686,7 +686,6 @@ void Database::createDatabase(const char deleteFilesOnExit = true; throw; } - } void Database::openDatabase(const char * filename) @@ -1455,50 +1454,61 @@ void Database::dropTable(Table *table, T void Database::truncateTable(Table *table, Sequence *sequence, Transaction *transaction) { - Sync syncDDL(&syncSysDDL, "Database::truncateTable(1)"); - syncDDL.lock(Exclusive); - - table->checkDrop(); - // Check for records in active transactions if (hasUncommittedRecords(table, transaction)) throw SQLError(UNCOMMITTED_UPDATES, "table %s.%s has uncommitted updates and cannot be truncated", table->schemaName, table->name); - - // Block table drop/add, table list scans ok - - Sync syncTbl(&syncTables, "Database::truncateTable(2)"); - syncTbl.lock(Shared); + + // Lock SystemDDL first. This lock can happen multiple times in many call stacks, + // both before and after the following locks. So it is important that we get an + // exclusive lock first. + + Sync syncDDLLock(&syncSysDDL, "Database::truncateTable(SysDDL)"); + syncDDLLock.lock(Exclusive); + + // Lock syncScavenge before locking syncSysDDL, syncTables, or table->syncObject. + // The scavenger locks syncScavenge and then syncTables + // If we run out of record memory, forceRecordScavenge will eventually call table->syncObject. + + Sync syncScavengeLock(&syncScavenge, "Database::truncateTable(scavenge)"); + syncScavengeLock.lock(Exclusive); + + table->checkDrop(); + // Block table drop/add, table list scans ok + + Sync syncTablesLock(&syncTables, "Database::truncateTable(tables)"); + syncTablesLock.lock(Shared); + //Lock sections (factored out of SRLDropTable to avoid a deadlock) //The lock order (serialLog->syncSections before table->syncObject) is //important - Sync syncSections(&serialLog->syncSections, "Database::truncateTable(3)"); - syncSections.lock(Exclusive); - + Sync syncSectionsLock(&serialLog->syncSections, "Database::truncateTable(sections)"); + syncSectionsLock.lock(Exclusive); + // No table access until truncate completes - - Sync syncObj(&table->syncObject, "Database::truncateTable(4)"); - syncObj.lock(Exclusive); - + + Sync syncTableLock(&table->syncObject, "Database::truncateTable(table)"); + syncTableLock.lock(Exclusive); + table->deleting = true; - + // Purge records out of committed transactions - + transactionManager->truncateTable(table, transaction); - + Transaction *sysTransaction = getSystemTransaction(); - + // Recreate data/blob sections and indexes - + table->truncate(sysTransaction); - + commitSystemTransaction(); - + // Delete and recreate the sequence - + if (sequence) sequence = sequence->recreate(); }