diff options
author | Jose <jose@zeroc.com> | 2009-12-04 06:51:23 +0100 |
---|---|---|
committer | Jose <jose@zeroc.com> | 2009-12-04 06:51:23 +0100 |
commit | 0ad40835182795b5f9bedeea10aeb6f07c666e7d (patch) | |
tree | 5dff55b02aefb5854a972eb2cef128d1537d5c47 /cpp/src | |
parent | Bug 4408 - plugin does not work with x64 only installation (diff) | |
download | ice-0ad40835182795b5f9bedeea10aeb6f07c666e7d.tar.bz2 ice-0ad40835182795b5f9bedeea10aeb6f07c666e7d.tar.xz ice-0ad40835182795b5f9bedeea10aeb6f07c666e7d.zip |
4089 - IceGrid database corruption.
Diffstat (limited to 'cpp/src')
-rw-r--r-- | cpp/src/Freeze/SharedDbEnv.cpp | 16 | ||||
-rw-r--r-- | cpp/src/Freeze/SharedDbEnv.h | 2 | ||||
-rw-r--r-- | cpp/src/IceDB/SqlTypes.cpp | 8 | ||||
-rw-r--r-- | cpp/src/IceDB/SqlTypes.h | 5 | ||||
-rw-r--r-- | cpp/src/IceUtil/Exception.cpp | 49 | ||||
-rw-r--r-- | cpp/src/IceUtil/FileUtil.cpp | 92 |
6 files changed, 165 insertions, 7 deletions
diff --git a/cpp/src/Freeze/SharedDbEnv.cpp b/cpp/src/Freeze/SharedDbEnv.cpp index 764662d9386..5156b52aa00 100644 --- a/cpp/src/Freeze/SharedDbEnv.cpp +++ b/cpp/src/Freeze/SharedDbEnv.cpp @@ -482,6 +482,14 @@ Freeze::SharedDbEnv::SharedDbEnv(const std::string& envName, } #endif + string propertyPrefix = string("Freeze.DbEnv.") + envName; + string dbHome = properties->getPropertyWithDefault(propertyPrefix + ".DbHome", envName); + + // + // File lock to prevent multiple process open the same db env. + // + _fileLock = new ::IceUtilInternal::FileLock(dbHome + "/Freeze.lock"); + _trace = properties->getPropertyAsInt("Freeze.Trace.DbEnv"); try @@ -497,11 +505,8 @@ Freeze::SharedDbEnv::SharedDbEnv(const std::string& envName, out << "opening database environment \"" << envName << "\""; } - string propertyPrefix = string("Freeze.DbEnv.") + envName; - - _env->set_errpfx(reinterpret_cast<char*>(this)); - + _env->set_errcall(dbErrCallback); #ifdef _WIN32 @@ -552,9 +557,6 @@ Freeze::SharedDbEnv::SharedDbEnv(const std::string& envName, // Threading // flags |= DB_THREAD; - - string dbHome = properties->getPropertyWithDefault( - propertyPrefix + ".DbHome", envName); _env->open(Ice::nativeToUTF8(_communicator, dbHome).c_str(), flags, FREEZE_DB_MODE); diff --git a/cpp/src/Freeze/SharedDbEnv.h b/cpp/src/Freeze/SharedDbEnv.h index 9d249bea6b5..573a537a18a 100644 --- a/cpp/src/Freeze/SharedDbEnv.h +++ b/cpp/src/Freeze/SharedDbEnv.h @@ -11,6 +11,7 @@ #define FREEZE_SHARED_DB_ENV_H #include <Freeze/Map.h> +#include <IceUtil/FileUtil.h> #include <Ice/Ice.h> #include <db_cxx.h> #include <map> @@ -96,6 +97,7 @@ private: SharedDbMap _sharedDbMap; IceUtil::Mutex _mutex; + IceUtilInternal::FileLockPtr _fileLock; }; inline DbEnv* diff --git a/cpp/src/IceDB/SqlTypes.cpp b/cpp/src/IceDB/SqlTypes.cpp index 829e49b0c50..1f288621d7e 100644 --- a/cpp/src/IceDB/SqlTypes.cpp +++ b/cpp/src/IceDB/SqlTypes.cpp @@ -170,6 +170,14 @@ DatabaseCache::DatabaseCache(const Ice::CommunicatorPtr& communicator, bool requiresBlob) { Ice::PropertiesPtr properties = communicator->getProperties(); + + // + // File lock to prevent multiple process open the same db env. + // + if(type == "QSQLITE") + { + _fileLock = new IceUtilInternal::FileLock(name + ".lock"); + } _connection = QSqlDatabase::addDatabase(type.c_str(), IceUtil::generateUUID().c_str()); _connection.setDatabaseName(name.c_str()); diff --git a/cpp/src/IceDB/SqlTypes.h b/cpp/src/IceDB/SqlTypes.h index a2b5600e475..b6613f95f35 100644 --- a/cpp/src/IceDB/SqlTypes.h +++ b/cpp/src/IceDB/SqlTypes.h @@ -14,6 +14,7 @@ #include <IceUtil/Handle.h> #include <IceUtil/Thread.h> +#include <IceUtil/FileUtil.h> #include <Ice/CommunicatorF.h> #include <Ice/Initialize.h> // For ThreadHook @@ -122,6 +123,10 @@ protected: QSqlDatabase _connection; ThreadDatabaseMap _cache; + +private: + + IceUtilInternal::FileLockPtr _fileLock; }; typedef IceUtil::Handle<DatabaseCache> DatabaseCachePtr; diff --git a/cpp/src/IceUtil/Exception.cpp b/cpp/src/IceUtil/Exception.cpp index 6ce81a17c23..7f33bc497a4 100644 --- a/cpp/src/IceUtil/Exception.cpp +++ b/cpp/src/IceUtil/Exception.cpp @@ -401,3 +401,52 @@ IceUtil::SyscallException::error() const { return _error; } + + +IceUtil::FileLockException::FileLockException(const char* file, int line, int err, const string& path): + Exception(file, line), + _error(err), + _path(path) +{ +} + +IceUtil::FileLockException::~FileLockException() throw() +{ +} + +const char* IceUtil::FileLockException::_name = "IceUtil::FileLockedException"; + +string +IceUtil::FileLockException::ice_name() const +{ + return _name; +} + +void +IceUtil::FileLockException::ice_print(ostream& os) const +{ + Exception::ice_print(os); + os << ":\ncould not lock file: `" << _path << "'"; + if(_error != 0) + { + os << "\nsyscall exception: " << IceUtilInternal::errorToString(_error); + } +} + +IceUtil::Exception* +IceUtil::FileLockException::ice_clone() const +{ + return new FileLockException(*this); +} + +void +IceUtil::FileLockException::ice_throw() const +{ + throw *this; +} + +int +IceUtil::FileLockException::error() const +{ + return _error; +} diff --git a/cpp/src/IceUtil/FileUtil.cpp b/cpp/src/IceUtil/FileUtil.cpp index 67f1569fdc0..22628852541 100644 --- a/cpp/src/IceUtil/FileUtil.cpp +++ b/cpp/src/IceUtil/FileUtil.cpp @@ -10,7 +10,13 @@ #include <IceUtil/DisableWarnings.h> #include <IceUtil/FileUtil.h> #include <IceUtil/Unicode.h> +#include <IceUtil/Exception.h> #include <climits> +#include <string.h> + +#ifdef _WIN32 +# include <process.h> +#endif #ifdef _WIN32 # include <io.h> @@ -19,6 +25,7 @@ #ifdef __BCPLUSPLUS__ # include <dir.h> #endif + using namespace std; // @@ -172,6 +179,37 @@ IceUtilInternal::close(int fd) #endif } +IceUtilInternal::FileLock::FileLock(const std::string& path) : + _fd(INVALID_HANDLE_VALUE), + _path(path) +{ + _fd = ::CreateFileW(IceUtil::stringToWstring(path).c_str(), GENERIC_WRITE, 0, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + _path = path; + + if(_fd == INVALID_HANDLE_VALUE) + { + throw IceUtil::FileLockException(__FILE__, __LINE__, GetLastError(), _path); + } + + if(::LockFile(_fd, 0, 0, 0, 0) == 0) + { + ::CloseHandle(_fd); + throw IceUtil::FileLockException(__FILE__, __LINE__, GetLastError(), _path); + } + // + // In Windows implementation we don't write the process pid to the file, as is + // not posible to read the file from other process while it is locked here. + // +} + +IceUtilInternal::FileLock::~FileLock() +{ + assert(_fd != INVALID_HANDLE_VALUE); + CloseHandle(_fd); + unlink(_path); +} + #ifdef _STLP_BEGIN_NAMESPACE namespace { @@ -407,6 +445,60 @@ IceUtilInternal::close(int fd) return ::close(fd); } +IceUtilInternal::FileLock::FileLock(const std::string& path) : + _fd(-1), + _path(path) +{ + _fd = ::open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if(_fd < 0) + { + throw IceUtil::FileLockException(__FILE__, __LINE__, errno, _path); + } + + struct ::flock lock; + lock.l_type = F_WRLCK; // Write lock + lock.l_whence = SEEK_SET; // Begining of file + lock.l_start = 0; + lock.l_len = 0; + + // + // F_SETLK tells fcntl to not block if it cannot + // acquire the lock, if the lock cannot be acquired + // it returns -1 without wait. + // + if(::fcntl(_fd, F_SETLK, &lock) == -1) + { + IceUtil::FileLockException ex(__FILE__, __LINE__, errno, _path); + close(_fd); + throw ex; + } + + // + // If there is an error after here, we close the fd, + // to release the lock. + // + + // + // Now that we have acquire an excluxive write lock, + // write the process pid there. + // + ostringstream os; + os << getpid(); + + if(write(_fd, os.str().c_str(), os.str().size()) == -1) + { + IceUtil::FileLockException ex(__FILE__, __LINE__, errno, _path); + close(_fd); + throw ex; + } +} + +IceUtilInternal::FileLock::~FileLock() +{ + assert(_fd > -1); + unlink(_path); +} + IceUtilInternal::ifstream::ifstream() { } |