summaryrefslogtreecommitdiff
path: root/cpp/src
diff options
context:
space:
mode:
authorJose <jose@zeroc.com>2009-12-04 06:51:23 +0100
committerJose <jose@zeroc.com>2009-12-04 06:51:23 +0100
commit0ad40835182795b5f9bedeea10aeb6f07c666e7d (patch)
tree5dff55b02aefb5854a972eb2cef128d1537d5c47 /cpp/src
parentBug 4408 - plugin does not work with x64 only installation (diff)
downloadice-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.cpp16
-rw-r--r--cpp/src/Freeze/SharedDbEnv.h2
-rw-r--r--cpp/src/IceDB/SqlTypes.cpp8
-rw-r--r--cpp/src/IceDB/SqlTypes.h5
-rw-r--r--cpp/src/IceUtil/Exception.cpp49
-rw-r--r--cpp/src/IceUtil/FileUtil.cpp92
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()
{
}