From: Date: July 17 2008 10:58pm Subject: bzr push into mysql-6.0-falcon branch (vvaintroub:2751 to 2752) Bug#38186 List-Archive: http://lists.mysql.com/commits/49984 X-Bug: 38186 Message-Id: <200807172058.m6HKwUu0005185@mail.mysql.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 2752 Vladislav Vaintroub 2008-07-17 Bug#38186 : CREATE TABLESPACE fails sometimes if called directly after DROP TABLESPACE on the same file The problem is that tablespace files are not deleted directly on client COMMIT. Deletion is done later, by background(Gopher) thread. Thus the file may still exist when "create tablespace" is called. The solution is to to modify CREATE TABLESPACE and if the file is there and there are pending DROP operation, wait for some seconds until the file is deleted. An attempt to solve this problem was done previously, but waiting for deletion was put on the wrong place. Client thread was waiting for gopher in TablespaceManager::dropTablespace, which can caused a "soft-deadlock" : - Client thread was holding syncSysDDL lock and was waiting for Gopher to delete file - Gopher did not run, was stuck in thread->sleep and waited for Scheduler to wakeup - Scheduler was doing scavenge and was stuck waiting for syncSysDDL lock in Database:updateCardinalities() This soft-deadlock was resolved after 10 seconds, client gave up and returned with "tablespace file already exists". The refinement to this solution is given here . Client waits for file to be deleted in StorageHandler::createTablespace while no Falcon locks are held. Thus the soft-deadlock described is not possible with this solution renamed: mysql-test/suite/falcon_team/r/falcon_bug_31295.result => mysql-test/suite/falcon/r/falcon_bug_31295.result mysql-test/suite/falcon_team/t/falcon_bug_31295.test => mysql-test/suite/falcon/t/falcon_bug_31295.test modified: storage/falcon/IOx.h storage/falcon/StorageHandler.cpp storage/falcon/TableSpaceManager.cpp storage/falcon/TableSpaceManager.h 2751 Hakan Kuecuekyilmaz 2008-07-17 [merge] Merge. modified: configure.in mysql-test/suite/rpl/t/disabled.def === renamed file 'mysql-test/suite/falcon_team/r/falcon_bug_31295.result' => 'mysql-test/suite/falcon/r/falcon_bug_31295.result' === renamed file 'mysql-test/suite/falcon_team/t/falcon_bug_31295.test' => 'mysql-test/suite/falcon/t/falcon_bug_31295.test' === modified file 'storage/falcon/IOx.h' --- a/storage/falcon/IOx.h 2008-07-07 14:00:45 +0000 +++ b/storage/falcon/IOx.h 2008-07-17 20:38:45 +0000 @@ -54,8 +54,8 @@ public: void writeHeader (Hdr *header); int read(int length, UCHAR *buffer); void write(uint32 length, const UCHAR *data); - bool doesFileExist(const char *fileName); - int fileStat(const char *fileName, struct stat *stats = NULL, int *errnum = NULL); + 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(); === modified file 'storage/falcon/StorageHandler.cpp' --- a/storage/falcon/StorageHandler.cpp 2008-07-15 18:57:27 +0000 +++ b/storage/falcon/StorageHandler.cpp 2008-07-17 20:38:45 +0000 @@ -35,6 +35,10 @@ #include "InfoTable.h" #include "CmdGen.h" #include "Dbb.h" +#include "Database.h" +#include "TableSpaceManager.h" + + #define DICTIONARY_ACCOUNT "mysql" #define DICTIONARY_PW "mysql" @@ -493,10 +497,16 @@ int StorageHandler::createTablespace(con if (!dictionaryConnection) return StorageErrorTablesSpaceOperationFailed; - - //StorageDatabase *storageDatabase = NULL; + JString tableSpace = JString::upcase(tableSpaceName); - + + TableSpaceManager *tableSpaceManager = + dictionaryConnection->database->tableSpaceManager; + + if (!tableSpaceManager->waitForPendingDrop(tableSpaceName, 10)) + // file still exists after waiting for 10 seconds + return StorageErrorTableSpaceExist; + try { JString cmd = genCreateTableSpace(tableSpaceName, filename, initialSize, extentSize, === modified file 'storage/falcon/TableSpaceManager.cpp' --- a/storage/falcon/TableSpaceManager.cpp 2008-07-15 18:57:27 +0000 +++ b/storage/falcon/TableSpaceManager.cpp 2008-07-17 20:38:45 +0000 @@ -170,32 +170,10 @@ TableSpace* TableSpaceManager::createTab TableSpace *tableSpace = new TableSpace(database, name, id, fileName, type, tsInit); - if (!repository) + if (!repository && IO::doesFileExist(fileName)) { - bool fileExists; - - // Check if table space file already exists. - // Take into account, that tablespace might have been already dropped - // by another transaction, yet file can still be present on the disk, - // if log record is not yet fully committed by the gopher thread). - // So we'll wait for a few seconds if there are pending drops and - // tablespace file exists. - - for (int i=0; i < 10; i++) - { - fileExists = tableSpace->dbb->doesFileExist(fileName); - - if (fileExists && pendingDrops > 0) - Thread::getThread("TableSpaceManager::createTableSpace")->sleep(1000); - else - break; - } - - if (fileExists) - { - delete tableSpace; - throw SQLError(TABLESPACE_DATAFILE_EXIST_ERROR, "table space file name \"%s\" already exists\n", fileName); - } + delete tableSpace; + throw SQLError(TABLESPACE_DATAFILE_EXIST_ERROR, "table space file name \"%s\" already exists\n", fileName); } try @@ -541,4 +519,26 @@ void TableSpaceManager::getTableSpaceFil } } + +// Wait for specified amount of time for a file to be deleted. +// Don't wait if pendingDrops count is 0. +// +// The function returns true, if wait was successfull, i.e file does not exist +//(anymore) +bool TableSpaceManager::waitForPendingDrop(const char *filename, int seconds) +{ + bool fileExists; + + do + { + fileExists = IO::doesFileExist(filename); + if (fileExists && pendingDrops > 0 && seconds-- > 0) + Thread::getThread("TransactionManager::waitForPendingDrop")->sleep(1000); + else + break; + } + while(true); + + return !fileExists; +} === modified file 'storage/falcon/TableSpaceManager.h' --- a/storage/falcon/TableSpaceManager.h 2008-06-08 22:12:35 +0000 +++ b/storage/falcon/TableSpaceManager.h 2008-07-17 20:38:45 +0000 @@ -62,6 +62,7 @@ public: void reportWrites(void); void redoCreateTableSpace(int id, int nameLength, const char* name, int fileNameLength, const char* fileName, int type, TableSpaceInit* tsInit); void initialize(void); + bool waitForPendingDrop(const char *filename, int seconds); Database *database; TableSpace *tableSpaces;