From: Date: October 30 2008 3:08pm Subject: bzr commit into mysql-6.0-falcon-team branch (vvaintroub:2889) Bug#38186 List-Archive: http://lists.mysql.com/commits/57464 X-Bug: 38186 Message-Id: <200810301408.m9UE8Ws0002989@mail.mysql.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit #At file:///G:/bzr/mysql-6.0-falcon-team/ 2889 Vladislav Vaintroub 2008-10-30 Fixed a long-standing problem that tablespace file was present even after "drop tablespace" successfully completed. This problem was previously worked around in Bug#38186. modified: storage/falcon/IO.cpp storage/falcon/StorageHandler.cpp storage/falcon/TableSpaceManager.cpp storage/falcon/TableSpaceManager.h === modified file 'storage/falcon/IO.cpp' --- a/storage/falcon/IO.cpp 2008-09-11 10:56:00 +0000 +++ b/storage/falcon/IO.cpp 2008-10-30 14:08:19 +0000 @@ -117,6 +117,19 @@ static char baseDir[PATH_MAX+1]={0}; bool deleteFilesOnExit = false; bool inCreateDatabase = false; +#ifdef _WIN32 +static int winUnlink(const char *file); +static int winOpen(const char *filename, int flags,...); +#endif + +#ifdef _WIN32 +#define POSIX_OPEN_FILE winOpen +#define POSIX_UNLINK_FILE winUnlink +#else +#define POSIX_OPEN_FILE ::open +#define POSIX_UNLINK_FILE ::unlink +#endif + #ifdef _DEBUG #undef THIS_FILE static const char THIS_FILE[]=__FILE__; @@ -186,7 +199,7 @@ bool IO::openFile(const char * name, boo ASSERT(!inCreateDatabase); fileName = getPath(name); - fileId = ::open (fileName, (readOnly) ? (O_RDONLY | O_BINARY) : (O_RDWR | O_BINARY)); + fileId = POSIX_OPEN_FILE(fileName, (readOnly) ? (O_RDONLY | O_BINARY) : (O_RDWR | O_BINARY)); if (fileId < 0) { @@ -241,7 +254,7 @@ bool IO::createFile(const char *name) Log::debug("IO::createFile: creating file \"%s\"\n", name); fileName = getPath(name); - fileId = ::open (fileName.getString(),O_CREAT | O_RDWR | O_RANDOM | O_EXCL | O_BINARY, + fileId = POSIX_OPEN_FILE (fileName.getString(),O_CREAT | O_RDWR | O_RANDOM | O_EXCL | O_BINARY, S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP); @@ -557,6 +570,7 @@ void IO::writeHeader(Hdr *header) void IO::deleteFile() { deleteFile(fileName); + fileName=""; } int IO::pread(int64 offset, int length, UCHAR* buffer) @@ -675,10 +689,132 @@ void IO::sync(void) traceOperation(TRACE_SYNC_END); } +#ifdef _WIN32 +#define FALCON_DELETED_FILE "fdf" + +/* + The only safe way to delete file on Windows without invalidating open file + handles is that: + - rename file to be deleted to a unique temporary name. + - open file it with FILE_FLAG_DELETE_ON_CLOSE + - close the file handle + Temp file will disappear as soon as last handle on it is closed. + This works only if files are opened with FILE_SHARE_DELETE flag. +*/ + +static int winUnlink(const char *file) +{ + DWORD attributes = GetFileAttributes(file); + + // Bail out, if file does not exist. + if (attributes == INVALID_FILE_ATTRIBUTES) + return -1; + + // If file is a symbolic link, just delete the link, but not the link target + if (attributes & FILE_ATTRIBUTE_REPARSE_POINT) + { + if(DeleteFile(file)) + return 0; + return -1; + } + + // Rename the file to unique name, then open with FILE_FLAG_DELETE_ON_CLOSE + // and close. + char tmpDir[MAX_PATH]; + strncpy(tmpDir, file, sizeof(tmpDir)-1); + char *p = strrchr(tmpDir ,SEPARATOR); + if (p) + *p = 0; + else + strcpy(tmpDir,"."); + + char tmpFile[MAX_PATH]; + if (GetTempFileName(tmpDir, FALCON_DELETED_FILE, 0, tmpFile)) + { + if (MoveFileEx(file, tmpFile, MOVEFILE_REPLACE_EXISTING)) + { + HANDLE hFile = CreateFile(tmpFile, 0, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL); + + if (hFile != INVALID_HANDLE_VALUE) + { + CloseHandle(hFile); + return 0; + } + } + else + DeleteFile(tmpFile); + } + + // Something went wrong. Try DeleteFile(), even if it can invalidate + // open file handles. + if(DeleteFile(file)) + return 0; + + return -1; +} + +/* + A wrapper for Posix open(). The reason it is there is the FILE_SHARE_DELETE + flag used in CreateFile, which allows for posixly-correct unlink + (that works with open files) +*/ +static int winOpen(const char *filename, int flags,...) +{ + DWORD access; + if (flags & O_WRONLY) + access = GENERIC_WRITE; + else if (flags & O_RDWR) + access = GENERIC_READ|GENERIC_WRITE; + else + access = GENERIC_READ; + + DWORD disposition; + if (flags & O_CREAT) + disposition = CREATE_NEW; + else + disposition = OPEN_EXISTING; + + DWORD attributes; + if (flags & O_RANDOM) + attributes = FILE_FLAG_RANDOM_ACCESS; + else + attributes = FILE_ATTRIBUTE_NORMAL; + + HANDLE hFile = CreateFile(filename, access, + FILE_SHARE_DELETE, NULL, disposition, attributes, NULL); + + if (hFile == INVALID_HANDLE_VALUE) + { + switch(GetLastError()) + { + case ERROR_ACCESS_DENIED: + errno = EACCES; + break; + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + errno = ENOENT; + break; + default: + errno = EINVAL; + break; + } + return -1; + } + return _open_osfhandle((intptr_t)hFile, + flags & (_O_APPEND|_O_RDONLY|_O_TEXT)); +} + +#endif + void IO::deleteFile(const char* fileName) { - JString path = getPath(fileName); - unlink(path.getString()); + if(fileName && *fileName) + { + JString path = getPath(fileName); + POSIX_UNLINK_FILE(path.getString()); + } } void IO::tracePage(Bdb* bdb) @@ -810,3 +946,4 @@ uint16 IO::computeChecksum(Page *page, s return (uint16) sum; } + === modified file 'storage/falcon/StorageHandler.cpp' --- a/storage/falcon/StorageHandler.cpp 2008-10-01 03:13:44 +0000 +++ b/storage/falcon/StorageHandler.cpp 2008-10-30 14:08:19 +0000 @@ -508,10 +508,6 @@ int StorageHandler::createTablespace(con TableSpaceManager *tableSpaceManager = dictionaryConnection->database->tableSpaceManager; - if (!tableSpaceManager->waitForPendingDrop(filename, 10)) - // file still exists after waiting for 10 seconds - return StorageErrorTableSpaceDataFileExist; - try { JString cmd = genCreateTableSpace(tableSpaceName, filename, comment); === modified file 'storage/falcon/TableSpaceManager.cpp' --- a/storage/falcon/TableSpaceManager.cpp 2008-09-22 09:24:39 +0000 +++ b/storage/falcon/TableSpaceManager.cpp 2008-10-30 14:08:19 +0000 @@ -58,7 +58,6 @@ TableSpaceManager::TableSpaceManager(Dat memset(nameHash, 0, sizeof(nameHash)); memset(idHash, 0, sizeof(nameHash)); tableSpaces = NULL; - pendingDrops = 0; syncObject.setName("TableSpaceManager::syncObject"); } @@ -209,12 +208,7 @@ void TableSpaceManager::bootstrap(int se p = EncodedDataStream::decode(p, &id, true); p = EncodedDataStream::decode(p, &fileName, true); p = EncodedDataStream::decode(p, &type, true); - /*** - p = EncodedDataStream::decode(p, &comment, true); - TableSpaceInit tsInit; - tsInit.comment = comment.getString(); - ***/ TableSpace *tableSpace = new TableSpace(database, name.getString(), id.getInt(), fileName.getString(), type.getInt(), NULL); Log::debug("New table space %s, id %d, type %d, filename %s\n", (const char*) tableSpace->name, tableSpace->tableSpaceId, tableSpace->type, (const char*) tableSpace->filename); @@ -252,7 +246,6 @@ TableSpace* TableSpaceManager::getTableS throw SQLError(COMPILE_ERROR, "can't find table space %d", id); if (!tableSpace->active) - //throw SQLError(RUNTIME_ERROR, "table space \"%s\" is not active", (const char*) tableSpace->name); tableSpace->open(); return tableSpace; @@ -298,13 +291,14 @@ void TableSpaceManager::dropTableSpace(T break; } - pendingDrops++; syncObj.unlock(); + tableSpace->active = false; + JString filename = tableSpace->dbb->fileName; database->serialLog->logControl->dropTableSpace.append(tableSpace, transaction); database->commitSystemTransaction(); + IO::deleteFile(filename); - tableSpace->active = false; } void TableSpaceManager::reportStatistics(void) @@ -370,12 +364,10 @@ void TableSpaceManager::expungeTableSpac } sync.unlock(); - tableSpace->dropTableSpace(); + //File already deleted, just close the file descriptor + tableSpace->close(); delete tableSpace; - sync.lock(Exclusive); - if(pendingDrops >0) - pendingDrops--; } void TableSpaceManager::reportWrites(void) @@ -563,28 +555,5 @@ void TableSpaceManager::getTableSpaceFil infoTable->setNull(37); // EXTRA infoTable->putRecord(); } -} - - -// 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-09-22 09:24:39 +0000 +++ b/storage/falcon/TableSpaceManager.h 2008-10-30 14:08:19 +0000 @@ -63,7 +63,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; @@ -71,7 +71,6 @@ public: TableSpace *idHash[TS_HASH_SIZE]; SyncObject syncObject; void postRecovery(void); - int pendingDrops; }; #endif // !defined(AFX_TABLESPACEMANAGER_H__BD1D39F6_2201_4136_899C_7CB106E99B8C__INCLUDED_)