#At file:///C:/bzr/mysql-6.0-falcon/
2752 Vladislav Vaintroub 2008-07-17
Bug#31295 : 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
=== 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 19:35:38 +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 19:35:38 +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 19:35:38 +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(--seconds > 0);
+
+ 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 19:35:38 +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;