| List: | Commits | « Previous MessageNext Message » | |
| From: | Vladislav Vaintroub | Date: | October 21 2008 8:06pm |
| Subject: | bzr commit into mysql-6.0-falcon-team branch (vvaintroub:2875) Bug#38186, Bug#39789 | ||
| View as plain text | |||
#At file:///media/disk/vmware-tools-distrib/mysql-6.0-falcon-team/
2875 Vladislav Vaintroub 2008-10-21
Bug#39789: Falcon recovery failure after several CREATE +
DROP TABLESPACE
Solved in this patch:
-Drop tablespace in REDO phase removed datafiles without
taking into account that some of them should stay after the
recovery. In this case, even if metadata for tablespace
would be present after recovery, the data is lost together
with the file.
Typical scenario for such failed recovery would be something
like
create tablespace A add datafile 'f' engine falcon;
drop tablespace A;
create tablespace B add datafile 'f' engine falcon;
create table T tablespace B;
Recovery for "drop tablespace A" would delete file used
by tablespace B and invalidate table T.
Solution for this problem is to calculate whether datafiles
should stay after recovery or can be deleted. Calculation done
in the pass1 of recovery, deletion in the REDO phase.
While fixing this, other smaller problems were fixed
- failure to recover, when the database crashed after datafile
had been created but before header was written.
- redoCreateTableSpace did not attempt to create tablespaces,
but only opened existing ones.
- fixed a long-standing problem that tablespace file was present
even after "drop tablespace" successfully completed. This was
previously worked around in Bug#38186
modified:
storage/falcon/IO.cpp
storage/falcon/IOx.h
storage/falcon/SRLCreateTableSpace.cpp
storage/falcon/SRLDropTableSpace.cpp
storage/falcon/SerialLog.cpp
storage/falcon/SerialLog.h
storage/falcon/SerialLogFile.cpp
storage/falcon/StorageHandler.cpp
storage/falcon/TableSpace.cpp
storage/falcon/TableSpace.h
storage/falcon/TableSpaceManager.cpp
storage/falcon/TableSpaceManager.h
per-file messages:
storage/falcon/IO.cpp
Support for removing open files on Windows, in a similar how
Unix unlink() works.
New function winOpen()- a posix-style wrapper for CreateFile that calls underlying CreateFile with FILE_SHARE_DELETE
New function winUnlink().
when deleting file, first move it to unique name, open
with FILE_FLAG_DELETE_ON_CLOSE and close the handle. File will
disappear after the last handle to it is closed. This is the only safe method to remove an open file.
- New function IO::minTableSpaceSize() used in recovery (files smaller then this can sefely be deleted and recreated)
- new function dupFile() - wrapper for dup()
- new function isSameFile() - determine whether 2 paths refer to the same file
storage/falcon/SRLCreateTableSpace.cpp
during create/drop tablespace recovery in pass1, calculate the final state of each datafile , whether it should stay or can be deleted
storage/falcon/SRLDropTableSpace.cpp
During create/drop tablespace recovery in pass1, calculate the final state of each datafile , whether it should stay or can be deleted.
Delete file in redo phase if it can safely be deleted.
storage/falcon/SerialLog.cpp
Track creation and removal of datafiles during recovery of createand drop tablespace
storage/falcon/SerialLog.h
Track creation and removal of datafiles during recovery of createand drop tablespace
storage/falcon/SerialLogFile.cpp
initial file size of serial log file is mkeant to be 8K at least
storage/falcon/StorageHandler.cpp
Remove waitForPendingDrop hack
storage/falcon/TableSpace.cpp
Depending on parameter passed, TableSpace::open either open()'s
or dup()'s the datafile.
storage/falcon/TableSpace.h
An extra parameter for open - IO can be passed in this case file descriptor is duplicated. It is necessary because during the recovery phase we can have multiple tablespaces all poining to the same file. In this case we use dup() rather then open() - on Windows multiple open's() for the same file will fail with ERROR_SHARING_VIOLATION, as the datafiles are opened without FILE_SHARE_READ|FILE_SHARE_WRITE.
storage/falcon/TableSpaceManager.cpp
Create/Drop tablespace recovery
- Tablespace::bootstrap might create a missing datafile.
It is necessary because datafile can be physically deleted before metadata stored in system table disappear.
- Tablespace::redoCreateTableSpace() will create datafile that is missing
- waitForPendingDrop() hack is removed
- extra parameter for expungeTableSpace(). expungeTableSpace it is used in redo phase of recovery and the file should stay after the recovery, file will not be removed, it is just closed.
storage/falcon/TableSpaceManager.h
- extra parameter for expungeTableSpace()
- remove waitForPendingDrop hack
=== 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-21 20:05:54 +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)
{
@@ -219,6 +232,70 @@ bool IO::openFile(const char * name, boo
return fileId != -1;
}
+/*
+ Check if two filenames refer to the same existing file.
+ Simple string comparison would not yield correct results, because of symbolic
+ links and filename canonicalization issues.
+*/
+bool IO::isSameFile (const char *filename1, const char *filename2)
+{
+#ifndef _WIN32
+ struct stat stat1;
+ struct stat stat2;
+ if (stat(filename1, &stat1) == 0 && stat(filename2, &stat2) == 0)
+ return (stat1.st_dev == stat2.st_dev &&
+ stat1.st_ino == stat2.st_ino);
+ return false;
+#else
+ HANDLE hFile1 = CreateFile(filename1, FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);
+
+ if(hFile1 == INVALID_HANDLE_VALUE)
+ return false;
+
+ HANDLE hFile2 = CreateFile(filename1, FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);
+
+ if(hFile2 == INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(hFile1);
+ return false;
+ }
+ BY_HANDLE_FILE_INFORMATION info1, info2;
+ bool retval;
+
+ if (GetFileInformationByHandle(hFile1, &info1) &&
+ GetFileInformationByHandle(hFile2, &info2))
+ {
+ retval = (info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber
+ && info1.nFileIndexHigh == info2.nFileIndexHigh
+ && info1.nFileSizeLow == info2.nFileSizeLow );
+ }
+ else
+ retval = false;
+
+ CloseHandle(hFile1);
+ CloseHandle(hFile2);
+
+ return retval;
+#endif
+}
+
+void IO::dupFile(IO *otherFile)
+{
+ fileName = otherFile->fileName;
+ fileId = dup(otherFile->fileId);
+ isReadOnly = false;
+ created = false;
+ if (fileId < 0)
+ {
+ throw SQLEXCEPTION (IO_ERROR, "can't dup file \"%s\", fileId %d: %s (%d)",
+ fileName.getString(), fileId, strerror (errno), errno);
+ }
+}
+
void IO::setWriteFlags(int fileId, bool *forceFsync)
{
#ifndef _WIN32
@@ -241,7 +318,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);
@@ -377,7 +454,12 @@ void IO::readHeader(Hdr * header)
n = ::read (fileId, buffer, maxPageSize);
if (n < (int) sizeof (Hdr))
- FATAL ("read error on database header");
+ {
+ throw SQLError(IO_ERROR,
+ "read header returned %d, filename %s, errno %d",
+ n, (const char*) fileName, errno);
+ }
+
Hdr* hdr = (Hdr*) buffer;
if (falcon_checksums && hdr->pageSize <= n)
@@ -532,6 +614,11 @@ int IO::fileStat(const char *fileName, s
return(retCode);
}
+int IO::minTableSpaceSize()
+{
+ return sizeof(Hdr);
+}
+
void IO::write(uint32 length, const UCHAR *data)
{
uint32 len = ::write (fileId, data, length);
@@ -557,6 +644,7 @@ void IO::writeHeader(Hdr *header)
void IO::deleteFile()
{
deleteFile(fileName);
+ fileName="";
}
int IO::pread(int64 offset, int length, UCHAR* buffer)
@@ -675,10 +763,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 +1020,4 @@ uint16 IO::computeChecksum(Page *page, s
return (uint16) sum;
}
+
=== modified file 'storage/falcon/IOx.h'
--- a/storage/falcon/IOx.h 2008-09-11 10:56:00 +0000
+++ b/storage/falcon/IOx.h 2008-10-21 20:05:54 +0000
@@ -52,6 +52,7 @@ public:
bool trialRead (Bdb *bdb);
void deleteFile();
void writeHeader (Hdr *header);
+ static int minTableSpaceSize();
int read(int length, UCHAR *buffer);
void write(uint32 length, const UCHAR *data);
static bool doesFileExist(const char *fileName);
@@ -67,6 +68,8 @@ public:
static void setBaseDirectory(const char *path);
static void setWriteFlags(int fileId, bool *forceFsync);
bool openFile (const char *name, bool readOnly);
+ static bool isSameFile (const char *filename1, const char *filename2);
+ void dupFile(IO *otherFile);
void longSeek(int64 offset);
void read(int64 offset, int length, UCHAR* buffer);
void write(int64 offset, int length, const UCHAR* buffer);
=== modified file 'storage/falcon/SRLCreateTableSpace.cpp'
--- a/storage/falcon/SRLCreateTableSpace.cpp 2008-07-17 13:52:17 +0000
+++ b/storage/falcon/SRLCreateTableSpace.cpp 2008-10-21 20:05:54 +0000
@@ -87,7 +87,11 @@ void SRLCreateTableSpace::pass1()
{
TableSpaceInit tsInit;
tsInit.comment = comment;
- log->database->tableSpaceManager->redoCreateTableSpace(tableSpaceId, nameLength, name, filenameLength, filename, type, &tsInit);
+ log->database->tableSpaceManager->redoCreateTableSpace(tableSpaceId,
+ nameLength, name, filenameLength, filename, type, &tsInit);
+ TableSpace *tablespace = log->tableSpaceManager->findTableSpace(tableSpaceId);
+ log->setDataFileActive(tablespace->filename);
+
}
void SRLCreateTableSpace::pass2()
=== modified file 'storage/falcon/SRLDropTableSpace.cpp'
--- a/storage/falcon/SRLDropTableSpace.cpp 2008-06-08 22:12:35 +0000
+++ b/storage/falcon/SRLDropTableSpace.cpp 2008-10-21 20:05:54 +0000
@@ -65,7 +65,8 @@ void SRLDropTableSpace::read()
void SRLDropTableSpace::pass1()
{
-
+ TableSpace *tablespace = log->tableSpaceManager->findTableSpace(tableSpaceId);
+ log->setDataFileInactive(tablespace->filename);
}
void SRLDropTableSpace::pass2()
@@ -80,5 +81,11 @@ void SRLDropTableSpace::commit()
void SRLDropTableSpace::redo()
{
- log->tableSpaceManager->expungeTableSpace(tableSpaceId);
+
+ TableSpace *tablespace = log->tableSpaceManager->findTableSpace(tableSpaceId);
+ if(!tablespace)
+ return;
+ bool removeFile = !log->isDataFileActive(tablespace->filename);
+ log->tableSpaceManager->expungeTableSpace(tableSpaceId, removeFile);
+
}
=== modified file 'storage/falcon/SerialLog.cpp'
--- a/storage/falcon/SerialLog.cpp 2008-10-20 21:28:11 +0000
+++ b/storage/falcon/SerialLog.cpp 2008-10-21 20:05:54 +0000
@@ -147,6 +147,8 @@ SerialLog::~SerialLog()
delete logControl;
delete recoveryIndexes;
delete recoverySections;
+ cleanupRecoveryDatafiles();
+
SerialLogWindow *window;
while ( (window = firstWindow) )
@@ -323,6 +325,9 @@ void SerialLog::recover()
recoveryPages = new RecoveryObjects(this);
recoverySections = new RecoveryObjects(this);
recoveryIndexes = new RecoveryObjects(this);
+ recoveryDatafiles = NULL;
+ recoveryDatafilesCount = 0;
+
recoveryPhase = 1; // Take Inventory (serialLogTransactions, recoveryObject states, last checkpoint)
// Make a first pass finding records, transactions, etc.
@@ -395,9 +400,12 @@ void SerialLog::recover()
delete recoveryPages;
delete recoverySections;
delete recoveryIndexes;
+
recoveryPages = NULL;
recoveryIndexes = NULL;
recoverySections = NULL;
+ recoveryDatafiles = NULL;
+ cleanupRecoveryDatafiles();
for (window = firstWindow; window; window = window->next)
if (!(window->inUse == 0 || window == writeWindow))
@@ -1274,6 +1282,78 @@ void SerialLog::setIndexActive(int id, i
recoveryIndexes->deleteObject(id, tableSpaceId);
}
+void SerialLog::setDataFileActive(const char *filename)
+{
+ ASSERT(recovering);
+ int pos = -1;
+ for(int i=0; i< recoveryDatafilesCount;i++)
+ if(recoveryDatafiles[i] == NULL)
+ {
+ pos = i;
+ break;
+ }
+ if(pos == -1)
+ {
+ // No free slot found, reallocate array
+ pos = recoveryDatafilesCount;
+ char **newRecoveryDatafiles = new char* [recoveryDatafilesCount+1];
+
+ if(recoveryDatafiles)
+ {
+ memcpy(newRecoveryDatafiles, recoveryDatafiles, sizeof(char*)*recoveryDatafilesCount);
+ delete recoveryDatafiles;
+ }
+ recoveryDatafiles = newRecoveryDatafiles;
+ recoveryDatafilesCount++;
+ }
+ recoveryDatafiles[pos] = new char[strlen(filename)+1];
+ strcpy(recoveryDatafiles[pos], filename);
+
+}
+
+void SerialLog::setDataFileInactive(const char *filename)
+{
+ ASSERT(recovering);
+ for(int i=0; i< recoveryDatafilesCount; i++)
+ {
+ char *fname = recoveryDatafiles[i];
+
+ if(fname && IO::isSameFile(fname,filename))
+ {
+ delete(fname);
+ recoveryDatafiles[i] = 0;
+ return;
+ }
+ }
+
+}
+
+bool SerialLog::isDataFileActive(const char *filename)
+{
+ ASSERT(recovering);
+ for(int i=0; i< recoveryDatafilesCount; i++)
+ {
+ char *fname = recoveryDatafiles[i];
+ if(fname && IO::isSameFile(fname,filename))
+ return true;
+ }
+ return false;
+}
+
+void SerialLog::cleanupRecoveryDatafiles()
+{
+ if(recoveryDatafiles)
+ {
+ for(int i=0; i< recoveryDatafilesCount;i++)
+ if(recoveryDatafiles[i])
+ delete(recoveryDatafiles[i]);
+
+ delete(recoveryDatafiles);
+ recoveryDatafiles = NULL;
+ recoveryDatafilesCount = 0;
+ }
+}
+
void SerialLog::setIndexInactive(int id, int tableSpaceId)
{
if (!recoveryIndexes)
=== modified file 'storage/falcon/SerialLog.h'
--- a/storage/falcon/SerialLog.h 2008-10-20 21:28:11 +0000
+++ b/storage/falcon/SerialLog.h 2008-10-21 20:05:54 +0000
@@ -126,13 +126,16 @@ public:
void setSectionInactive(int id, int tableSpaceId);
void setIndexActive(int id, int tableSpaceId);
void setIndexInactive(int id, int tableSpaceId);
+ bool isDataFileActive(const char *filename);
+ void setDataFileActive(const char *filename);
+ void setDataFileInactive(const char *filename);
+ void cleanupRecoveryDatafiles();
void updateSectionUseVector(uint sectionId, int tableSpaceId, int delta);
void updateIndexUseVector(uint indexId, int tableSpaceId, int delta);
bool sectionInUse(int sectionId, int tableSpaceId);
bool bumpIndexIncarnation(int indexId, int tableSpaceId, int state);
bool bumpSectionIncarnation (int sectionId, int tableSpaceId, int state);
bool bumpPageIncarnation (int32 pageNumber, int tableSpaceId, int state);
-
void redoFreePage(int32 pageNumber, int tableSpaceId);
bool indexInUse(int indexId, int tableSpaceId);
@@ -170,6 +173,8 @@ public:
RecoveryObjects *recoveryPages;
RecoveryObjects *recoverySections;
RecoveryObjects *recoveryIndexes;
+ char** recoveryDatafiles;
+ int recoveryDatafilesCount;
Dbb *defaultDbb;
Gopher *gophers;
Thread *srlQueue;
=== modified file 'storage/falcon/SerialLogFile.cpp'
--- a/storage/falcon/SerialLogFile.cpp 2008-10-16 02:53:35 +0000
+++ b/storage/falcon/SerialLogFile.cpp 2008-10-21 20:05:54 +0000
@@ -369,8 +369,8 @@ void SerialLogFile::zap()
size_t initialSize = MAX(sectorSize, 8192);
UCHAR *junk = new UCHAR[initialSize +sectorSize];
UCHAR *buffer = ALIGN(junk, sectorSize);
- memset(buffer, 0, sectorSize);
- write(0, sectorSize, (SerialLogBlock*) buffer);
+ memset(buffer, 0, initialSize);
+ write(0, initialSize, (SerialLogBlock*) buffer);
delete junk;
}
=== 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-21 20:05:54 +0000
@@ -508,9 +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
{
=== modified file 'storage/falcon/TableSpace.cpp'
--- a/storage/falcon/TableSpace.cpp 2008-08-18 20:17:15 +0000
+++ b/storage/falcon/TableSpace.cpp 2008-10-21 20:05:54 +0000
@@ -59,21 +59,23 @@ TableSpace::~TableSpace()
delete dbb;
}
-void TableSpace::open()
+void TableSpace::open(IO *file)
{
try
{
- dbb->openFile(filename, false);
+ if(!file)
+ dbb->openFile(filename, false);
+ else
+ {
+ dbb->dupFile(file);
+ dbb->longSeek(0);
+ }
+
active = true;
}
catch (SQLException&)
{
- //if (dbb->doesFileExits(fileName))
throw;
-
- create();
-
- return;
}
Hdr header;
=== modified file 'storage/falcon/TableSpace.h'
--- a/storage/falcon/TableSpace.h 2008-07-17 13:52:17 +0000
+++ b/storage/falcon/TableSpace.h 2008-10-21 20:05:54 +0000
@@ -36,6 +36,7 @@ struct TableSpaceInit
class Dbb;
class Database;
class InfoTable;
+class IO;
class TableSpace
{
@@ -44,7 +45,7 @@ public:
virtual ~TableSpace();
void create();
- void open();
+ void open(IO *file = NULL);
void close(void);
void shutdown(TransId transId);
void dropTableSpace(void);
=== 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-21 20:05:54 +0000
@@ -19,6 +19,7 @@
//////////////////////////////////////////////////////////////////////
#include <memory.h>
+#include <sys/stat.h>
#include "Engine.h"
#include "TableSpaceManager.h"
#include "TableSpace.h"
@@ -42,6 +43,7 @@
#include "Log.h"
#include "InfoTable.h"
#include "Thread.h"
+#include "IOx.h"
#ifdef _DEBUG
#undef THIS_FILE
@@ -58,7 +60,6 @@ TableSpaceManager::TableSpaceManager(Dat
memset(nameHash, 0, sizeof(nameHash));
memset(idHash, 0, sizeof(nameHash));
tableSpaces = NULL;
- pendingDrops = 0;
syncObject.setName("TableSpaceManager::syncObject");
}
@@ -209,12 +210,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);
@@ -222,7 +218,10 @@ void TableSpaceManager::bootstrap(int se
if (tableSpace->type == TABLESPACE_TYPE_TABLESPACE)
try
{
- tableSpace->open();
+ if(!IO::doesFileExist(fileName.getString()))
+ tableSpace->create();
+ else
+ tableSpace->open();
}
catch(SQLException& exception)
{
@@ -252,7 +251,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 +296,13 @@ 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)
@@ -334,7 +332,7 @@ void TableSpaceManager::sync()
tableSpace->sync();
}
-void TableSpaceManager::expungeTableSpace(int tableSpaceId)
+void TableSpaceManager::expungeTableSpace(int tableSpaceId, bool removeFile)
{
Sync sync(&syncObject, "TableSpaceManager::expungeTableSpace");
sync.lock(Exclusive);
@@ -370,12 +368,13 @@ void TableSpaceManager::expungeTableSpac
}
sync.unlock();
- tableSpace->dropTableSpace();
+ if (removeFile)
+ tableSpace->dropTableSpace();
+ else
+ tableSpace->close();
+
delete tableSpace;
- sync.lock(Exclusive);
- if(pendingDrops >0)
- pendingDrops--;
}
void TableSpaceManager::reportWrites(void)
@@ -406,16 +405,52 @@ void TableSpaceManager::redoCreateTableS
file[fileNameLength] = 0;
tableSpace = new TableSpace(database, buffer, id, file, type, tsInit);
tableSpace->needSave = true;
- add(tableSpace);
+
+ // Check if another tablespace already has this file open
+ // if so duplicate the file descriptor (open will fail due to file locking)
+ IO *dupIO = NULL ;
+ for(TableSpace *ts = tableSpaces; ts; ts = ts->next)
+ {
+ if (IO::isSameFile(ts->filename,file) && ts->dbb->fileId != -1)
+ dupIO = ts->dbb;
+ }
+ add(tableSpace);
try
{
- tableSpace->open();
+ if(!IO::doesFileExist(file))
+ {
+ tableSpace->create();
+ return;
+ }
+
+ try
+ {
+ tableSpace->open(dupIO);
+ }
+ catch(SQLException &ex)
+ {
+ // Check if database died during tablespace creation and
+ // file has been created but header was not completely written.
+ // If it was the case, recreate the tablespace.
+ struct stat stats;
+ if (ex.getSqlcode() == IO_ERROR
+ && IO::fileStat(file, &stats) == 0
+ && stats.st_size < IO::minTableSpaceSize())
+ {
+ IO::deleteFile(file);
+ tableSpace->create();
+ }
+ else
+ throw;
+ }
+
}
catch(SQLException& exception)
{
- Log::log("Couldn't open table space file \"%s\" for tablespace \"%s\": %s\n",
- file, buffer, exception.getText());
+ Log::log("Could neither open nor create table space file \"%s\" for tablespace \"%s\": %s\n",
+ file, buffer, exception.getText());
+ throw;
}
}
@@ -565,26 +600,3 @@ 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-09-22 09:24:39 +0000
+++ b/storage/falcon/TableSpaceManager.h 2008-10-21 20:05:54 +0000
@@ -59,11 +59,10 @@ public:
void getTableSpaceFilesInfo(InfoTable* infoTable);
void validate(int optionMask);
void sync();
- void expungeTableSpace(int tableSpaceId);
+ void expungeTableSpace(int tableSpaceId, bool removeFile=true);
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 +70,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_)
