|
From: <ale...@us...> - 2012-12-14 17:45:50
|
Revision: 57489
http://firebird.svn.sourceforge.net/firebird/?rev=57489&view=rev
Author: alexpeshkoff
Date: 2012-12-14 17:45:38 +0000 (Fri, 14 Dec 2012)
Log Message:
-----------
Fixed CORE-3935 and CORE-3993
Modified Paths:
--------------
firebird/branches/B2_5_Release/builds/posix/make.shared.variables
firebird/branches/B2_5_Release/src/common/classes/PublicHandle.cpp
firebird/branches/B2_5_Release/src/common/classes/PublicHandle.h
firebird/branches/B2_5_Release/src/common/classes/RefMutex.h
firebird/branches/B2_5_Release/src/common/utils.cpp
firebird/branches/B2_5_Release/src/common/utils_proto.h
firebird/branches/B2_5_Release/src/jrd/Database.cpp
firebird/branches/B2_5_Release/src/jrd/Database.h
firebird/branches/B2_5_Release/src/jrd/DatabaseSnapshot.cpp
firebird/branches/B2_5_Release/src/jrd/cch.cpp
firebird/branches/B2_5_Release/src/jrd/event.cpp
firebird/branches/B2_5_Release/src/jrd/isc_sync.cpp
firebird/branches/B2_5_Release/src/jrd/jrd.cpp
firebird/branches/B2_5_Release/src/jrd/jrd.h
firebird/branches/B2_5_Release/src/jrd/trace/TraceConfigStorage.cpp
firebird/branches/B2_5_Release/src/jrd/trace/TraceLog.cpp
firebird/branches/B2_5_Release/src/jrd/vio.cpp
firebird/branches/B2_5_Release/src/jrd/why.cpp
firebird/branches/B2_5_Release/src/lock/lock.cpp
firebird/branches/B2_5_Release/src/remote/interface.cpp
firebird/branches/B2_5_Release/src/remote/remote.cpp
firebird/branches/B2_5_Release/src/remote/remote.h
firebird/branches/B2_5_Release/src/remote/server.cpp
Modified: firebird/branches/B2_5_Release/builds/posix/make.shared.variables
===================================================================
--- firebird/branches/B2_5_Release/builds/posix/make.shared.variables 2012-12-14 17:40:09 UTC (rev 57488)
+++ firebird/branches/B2_5_Release/builds/posix/make.shared.variables 2012-12-14 17:45:38 UTC (rev 57489)
@@ -261,7 +261,8 @@
FBCOMMON_ClientFiles = fb_exception.cpp thd.cpp classes/MetaName.cpp StatusHolder.cpp classes/init.cpp StatusArg.cpp
FBCOMMON_ServerFiles = utils.cpp
-FBCOMMON_ClientObjects = $(addprefix $(OBJ)/common/, $(addsuffix .o, $(basename $(FBCOMMON_ClientFiles))))
+FBCOMMON_ClientObjects = $(addprefix $(OBJ)/common/, $(addsuffix .o, $(basename $(FBCOMMON_ClientFiles)))) \
+ $(addprefix $(OBJ)/jrd/, $(addsuffix .o, $(basename fbsyslog.cpp)))
FBCOMMON_ServerObjects = $(addprefix $(OBJ)/common/, $(addsuffix .o, $(basename $(FBCOMMON_ServerFiles))))
FBCOMMON_Objects = $(FBCOMMON_ClientObjects) $(FBCOMMON_ServerObjects)
@@ -284,7 +285,7 @@
# Platform Manager
# just in case if make.platform defined some files
-OS_SPECIFIC_Files += config_root.cpp path_utils.cpp mod_loader.cpp fbsyslog.cpp guid.cpp os_utils.cpp
+OS_SPECIFIC_Files += config_root.cpp path_utils.cpp mod_loader.cpp guid.cpp os_utils.cpp
OS_SPECIFIC_Sources = $(addprefix jrd/, $(OS_SPECIFIC_Files)) common/dllinst.cpp
ifneq ($(strip @BINRELOC_CFLAGS@),)
Modified: firebird/branches/B2_5_Release/src/common/classes/PublicHandle.cpp
===================================================================
--- firebird/branches/B2_5_Release/src/common/classes/PublicHandle.cpp 2012-12-14 17:40:09 UTC (rev 57488)
+++ firebird/branches/B2_5_Release/src/common/classes/PublicHandle.cpp 2012-12-14 17:45:38 UTC (rev 57489)
@@ -21,6 +21,7 @@
*/
#include "firebird.h"
+#include "gen/iberror.h"
#include "../jrd/gdsassert.h"
#include "rwlock.h"
#include "PublicHandle.h"
@@ -31,6 +32,7 @@
GlobalPtr<RWLock> PublicHandle::sync;
PublicHandle::PublicHandle()
+ : RefPtr<ExistenceMutex>(FB_NEW(*getDefaultMemoryPool()) ExistenceMutex)
{
WriteLockGuard guard(sync);
@@ -48,6 +50,8 @@
{
WriteLockGuard guard(sync);
+ mutex()->objectExists = false;
+
size_t pos;
if (handles->find(this, pos))
{
@@ -59,15 +63,82 @@
}
}
- bool PublicHandle::isKnownHandle() const
+ ExistenceMutex* PublicHandle::isKnownHandle() const
{
if (!this)
{
- return false;
+ return NULL;
}
ReadLockGuard guard(sync);
- return handles->exist(this);
+ if (handles->exist(this))
+ {
+ mutex()->addRef();
+ return mutex();
+ }
+
+ return NULL;
}
-} // namespace
+ bool PublicHandle::executeWithLock(ExecuteWithLock* operation)
+ {
+ ReadLockGuard guard(sync);
+ if (handles->exist(this))
+ {
+ operation->execute();
+ return true;
+ }
+ return false;
+ }
+
+ PublicHandleHolder::PublicHandleHolder()
+ : mutex(NULL)
+ { }
+
+ PublicHandleHolder::PublicHandleHolder(PublicHandle* handle, const char* from)
+ : mutex(NULL)
+ {
+ if (!hold(handle, from))
+ {
+ fb_assert(false);
+ (Arg::Gds(isc_random) << "Public object unexpectedly lost").raise();
+ }
+ }
+
+ bool PublicHandleHolder::hold(PublicHandle* handle, const char* from)
+ {
+ mutex = handle->isKnownHandle();
+ if (mutex)
+ {
+ mutex->enter(from);
+ if (mutex->objectExists)
+ {
+ return true;
+ }
+ destroy();
+ mutex = NULL;
+ }
+ return false;
+ }
+
+ PublicHandleHolder::~PublicHandleHolder()
+ {
+ if (mutex)
+ {
+ destroy();
+ }
+ }
+
+ void PublicHandleHolder::destroy()
+ {
+ try
+ {
+ mutex->leave();
+ }
+ catch (const Firebird::Exception&)
+ {
+ DtorException::devHalt();
+ }
+ mutex->release();
+ }
+} // namespace Firebird
Modified: firebird/branches/B2_5_Release/src/common/classes/PublicHandle.h
===================================================================
--- firebird/branches/B2_5_Release/src/common/classes/PublicHandle.h 2012-12-14 17:40:09 UTC (rev 57488)
+++ firebird/branches/B2_5_Release/src/common/classes/PublicHandle.h 2012-12-14 17:45:38 UTC (rev 57489)
@@ -25,24 +25,60 @@
#include "../common/classes/init.h"
#include "../common/classes/array.h"
+#include "../common/classes/RefMutex.h"
namespace Firebird
{
class RWLock;
- class PublicHandle
+ class ExecuteWithLock
{
public:
+ virtual void execute() = 0;
+ };
+
+ class ExistenceMutex : public RefMutex
+ {
+ public:
+ bool objectExists;
+
+ ExistenceMutex()
+ : RefMutex(), objectExists(true)
+ { }
+ };
+
+ class PublicHandle : public RefPtr<ExistenceMutex>
+ {
+ public:
PublicHandle();
~PublicHandle();
- bool isKnownHandle() const;
+ ExistenceMutex* isKnownHandle() const;
+ ExistenceMutex* mutex() const
+ {
+ return (ExistenceMutex*)(*const_cast<PublicHandle*>(this));
+ }
+ bool executeWithLock(ExecuteWithLock* operation);
private:
static GlobalPtr<Array<const void*> > handles;
static GlobalPtr<RWLock> sync;
};
+ class PublicHandleHolder
+ {
+ public:
+ PublicHandleHolder();
+ PublicHandleHolder(PublicHandle*, const char* from);
+ ~PublicHandleHolder();
+
+ bool hold(PublicHandle* handle, const char* from);
+
+ private:
+ ExistenceMutex* mutex;
+ void destroy();
+ };
+
} // namespace
#endif // COMMON_PUBLIC_HANDLE
Modified: firebird/branches/B2_5_Release/src/common/classes/RefMutex.h
===================================================================
--- firebird/branches/B2_5_Release/src/common/classes/RefMutex.h 2012-12-14 17:40:09 UTC (rev 57488)
+++ firebird/branches/B2_5_Release/src/common/classes/RefMutex.h 2012-12-14 17:45:38 UTC (rev 57489)
@@ -46,14 +46,20 @@
RefMutex() {}
explicit RefMutex(MemoryPool& pool) : mutex(pool) {}
- void enter()
+ void enter(const char* f)
{
mutex.enter();
+ setFrom(f);
}
- bool tryEnter()
+ bool tryEnter(const char* f)
{
- return mutex.tryEnter();
+ bool rc = mutex.tryEnter();
+ if (rc)
+ {
+ setFrom(f);
+ }
+ return rc;
}
void leave()
@@ -63,16 +69,27 @@
private:
Mutex mutex;
+#ifdef DEV_BUILD
+ const char* from[8];
+ unsigned frIndex;
+ void setFrom(const char* fr)
+ {
+ frIndex %= FB_NELEM(from);
+ from[frIndex++] = fr;
+ }
+#else
+ void setFrom(const char*) { }
+#endif
};
// RAII holder
class RefMutexGuard : public Reference
{
public:
- explicit RefMutexGuard(RefMutex& alock)
+ RefMutexGuard(RefMutex& alock, const char* f)
: Reference(alock), lock(&alock)
{
- lock->enter();
+ lock->enter(f);
}
~RefMutexGuard()
@@ -102,6 +119,16 @@
{
return object->release();
}
+
+ static void enter(T* object, const char* f)
+ {
+ object->enter(f);
+ }
+
+ static bool tryEnter(T* object, const char* f)
+ {
+ return object->tryEnter(f);
+ }
};
template <typename T>
@@ -117,6 +144,16 @@
{
return 0;
}
+
+ static void enter(T* object, const char*)
+ {
+ object->enter();
+ }
+
+ static bool tryEnter(T* object, const char*)
+ {
+ return object->tryEnter();
+ }
};
template <typename Mtx, typename RefCounted = DefaultRefCounted<Mtx> >
@@ -124,10 +161,9 @@
{
public:
explicit EnsureUnlock(Mtx& mutex)
+ : m_mutex(&mutex), m_locked(0)
{
- m_mutex = &mutex;
RefCounted::addRef(m_mutex);
- m_locked = 0;
}
~EnsureUnlock()
@@ -139,13 +175,13 @@
void enter()
{
- m_mutex->enter();
+ RefCounted::enter(m_mutex, "EnsureUnlock");
m_locked++;
}
bool tryEnter()
{
- if (m_mutex->tryEnter())
+ if (RefCounted::tryEnter(m_mutex, "EnsureUnlock::tryEnter"))
{
m_locked++;
return true;
Modified: firebird/branches/B2_5_Release/src/common/utils.cpp
===================================================================
--- firebird/branches/B2_5_Release/src/common/utils.cpp 2012-12-14 17:40:09 UTC (rev 57488)
+++ firebird/branches/B2_5_Release/src/common/utils.cpp 2012-12-14 17:45:38 UTC (rev 57489)
@@ -45,6 +45,7 @@
#include "../common/classes/init.h"
#include "../jrd/constants.h"
#include "../jrd/os/path_utils.h"
+#include "../jrd/os/fbsyslog.h"
#ifdef WIN_NT
#include <direct.h>
@@ -1016,4 +1017,15 @@
return tmp;
}
+void logAndDie(const char* text)
+{
+ gds__log(text);
+ Firebird::Syslog::Record(Firebird::Syslog::Error, text);
+#ifdef WIN_NT
+ exit(3);
+#else
+ abort();
+#endif
+}
+
} // namespace fb_utils
Modified: firebird/branches/B2_5_Release/src/common/utils_proto.h
===================================================================
--- firebird/branches/B2_5_Release/src/common/utils_proto.h 2012-12-14 17:40:09 UTC (rev 57488)
+++ firebird/branches/B2_5_Release/src/common/utils_proto.h 2012-12-14 17:45:38 UTC (rev 57489)
@@ -137,6 +137,8 @@
// Add appropriate file prefix.
Firebird::PathName getPrefix(FB_DIR prefType, const char* name);
+ void logAndDie(const char* text);
+
} // namespace fb_utils
#endif // INCLUDE_UTILS_PROTO_H
Modified: firebird/branches/B2_5_Release/src/jrd/Database.cpp
===================================================================
--- firebird/branches/B2_5_Release/src/jrd/Database.cpp 2012-12-14 17:40:09 UTC (rev 57488)
+++ firebird/branches/B2_5_Release/src/jrd/Database.cpp 2012-12-14 17:45:38 UTC (rev 57489)
@@ -91,7 +91,7 @@
delete dbb_monitoring_data;
delete dbb_backup_manager;
- Checkout dcoHolder(this);
+ fb_assert(!locked());
// This line decrements the usage counter and may cause the destructor to be called.
// It should happen with the dbb_sync unlocked.
LockManager::destroy(dbb_lock_mgr);
@@ -102,6 +102,8 @@
{
if (pool)
{
+ fb_assert(locked() || dbb_flags & DBB_not_in_use);
+
size_t pos;
if (dbb_pools.find(pool, pos))
{
Modified: firebird/branches/B2_5_Release/src/jrd/Database.h
===================================================================
--- firebird/branches/B2_5_Release/src/jrd/Database.h 2012-12-14 17:40:09 UTC (rev 57488)
+++ firebird/branches/B2_5_Release/src/jrd/Database.h 2012-12-14 17:45:38 UTC (rev 57489)
@@ -102,7 +102,7 @@
const ULONG DBB_sweep_in_progress = 0x2000L; // A database sweep operation is in progress
const ULONG DBB_security_db = 0x4000L; // ISC security database
const ULONG DBB_suspend_bgio = 0x8000L; // Suspend I/O by background threads
-const ULONG DBB_being_opened = 0x10000L; // database is being attached to
+const ULONG DBB_new = 0x10000L; // Database object is just created
const ULONG DBB_gc_cooperative = 0x20000L; // cooperative garbage collection
const ULONG DBB_gc_background = 0x40000L; // background garbage collection by gc_thread
const ULONG DBB_no_fs_cache = 0x80000L; // Not using file system cache
@@ -129,6 +129,9 @@
{
public:
Sync() : threadId(0), isAst(false)
+#ifdef DEV_BUILD
+ , lockCount(0)
+#endif
{}
void lock(bool ast = false)
@@ -139,6 +142,9 @@
--waiters;
threadId = getThreadId();
isAst = ast;
+#ifdef DEV_BUILD
+ ++lockCount;
+#endif
}
void unlock()
@@ -146,6 +152,10 @@
ThreadPriorityScheduler::exit();
isAst = false;
threadId = 0;
+#ifdef DEV_BUILD
+ fb_assert(lockCount > 0);
+ --lockCount;
+#endif
syncMutex.leave();
}
@@ -154,6 +164,17 @@
return (waiters.value() > 0);
}
+#ifdef DEV_BUILD
+ bool locked() const
+ {
+ if (!syncMutex.tryEnter())
+ return false;
+ bool rc = lockCount > 0;
+ syncMutex.leave();
+ return rc;
+ }
+#endif
+
private:
~Sync()
{
@@ -167,10 +188,16 @@
Sync(const Sync&);
Sync& operator=(const Sync&);
- Firebird::Mutex syncMutex;
+#ifdef DEV_BUILD
+ mutable
+#endif
+ Firebird::Mutex syncMutex;
Firebird::AtomicCounter waiters;
FB_THREAD_ID threadId;
bool isAst;
+#ifdef DEV_BUILD
+ int lockCount;
+#endif
};
public:
@@ -357,6 +384,7 @@
{
return false;
}
+ mutex()->release();
return TypedHandle<type_dbb>::checkHandle();
}
@@ -486,6 +514,9 @@
MemoryPool* createPool()
{
MemoryPool* const pool = MemoryPool::createPool(dbb_permanent, dbb_memory_stats);
+
+ fb_assert(locked() || dbb_flags & DBB_new);
+
dbb_pools.add(pool);
return pool;
}
@@ -539,6 +570,13 @@
return dbb_shared_counter.generate(tdbb, SharedCounter::STATEMENT_ID_SPACE);
}
+#ifdef DEV_BUILD
+ bool locked() const
+ {
+ return dbb_sync->locked();
+ }
+#endif
+
private:
// The delete operators are no-oped because the Database memory is allocated from the
Modified: firebird/branches/B2_5_Release/src/jrd/DatabaseSnapshot.cpp
===================================================================
--- firebird/branches/B2_5_Release/src/jrd/DatabaseSnapshot.cpp 2012-12-14 17:40:09 UTC (rev 57488)
+++ firebird/branches/B2_5_Release/src/jrd/DatabaseSnapshot.cpp 2012-12-14 17:45:38 UTC (rev 57489)
@@ -288,10 +288,7 @@
TEXT msg[BUFFER_TINY];
sprintf(msg, "MONITOR: mutex %s error, status = %d", string, state);
- gds__log(msg);
-
- //fprintf(stderr, "%s\n", msg);
- exit(FINI_ERROR);
+ fb_utils::logAndDie(msg);
}
}
Modified: firebird/branches/B2_5_Release/src/jrd/cch.cpp
===================================================================
--- firebird/branches/B2_5_Release/src/jrd/cch.cpp 2012-12-14 17:40:09 UTC (rev 57488)
+++ firebird/branches/B2_5_Release/src/jrd/cch.cpp 2012-12-14 17:45:38 UTC (rev 57489)
@@ -439,9 +439,12 @@
if (lock->lck_physical == LCK_EX) {
LCK_convert(tdbb, lock, LCK_PW, LCK_WAIT); // This lets waiting cache manager in first
}
- else {
+ else if (lock->lck_physical == LCK_PW) {
LCK_convert(tdbb, lock, LCK_SW, LCK_WAIT);
}
+ else {
+ fb_assert(lock->lck_physical == 0);
+ }
dbb->dbb_ast_flags &= ~DBB_blocking;
}
@@ -631,7 +634,7 @@
THREAD_SLEEP(CCH_EXCLUSIVE_RETRY_INTERVAL * 1000);
}
- if (tdbb->getAttachment()->att_flags & ATT_cancel_raise)
+ if (tdbb->getAttachment()->cancelRaise())
{
if (JRD_reschedule(tdbb, 0, false))
{
@@ -4023,6 +4026,8 @@
Attachment* const attachment = Attachment::create(dbb);
tdbb->setAttachment(attachment);
attachment->att_filename = dbb->dbb_filename;
+
+ PublicHandleHolder attHolder(attachment, "cache_reader()");
Jrd::ContextPoolHolder context(tdbb, dbb->dbb_bufferpool);
// This try block is specifically to protect the LCK_init call: if
@@ -4185,6 +4190,7 @@
Attachment* const attachment = Attachment::create(dbb);
tdbb->setAttachment(attachment);
attachment->att_filename = dbb->dbb_filename;
+ PublicHandleHolder attHolder(attachment, "cache_writer()");
Jrd::ContextPoolHolder context(tdbb, dbb->dbb_bufferpool);
// This try block is specifically to protect the LCK_init call: if
Modified: firebird/branches/B2_5_Release/src/jrd/event.cpp
===================================================================
--- firebird/branches/B2_5_Release/src/jrd/event.cpp 2012-12-14 17:40:09 UTC (rev 57488)
+++ firebird/branches/B2_5_Release/src/jrd/event.cpp 2012-12-14 17:45:38 UTC (rev 57489)
@@ -598,8 +598,7 @@
if (!header)
{
release_shmem();
- gds__log("Event table remap failed");
- exit(FINI_ERROR);
+ fb_utils::logAndDie("Event table remap failed");
}
m_header = header;
@@ -671,8 +670,7 @@
if (!best)
{
release_shmem();
- gds__log("Event table space exhausted");
- exit(FINI_ERROR);
+ fb_utils::logAndDie("Event table space exhausted");
}
free = (frb*) SRQ_ABS_PTR(*best);
@@ -1244,10 +1242,7 @@
TEXT msg[BUFFER_TINY];
sprintf(msg, "EVENT: %s error, status = %d", string, mutex_state);
- gds__log(msg);
-
- fprintf(stderr, "%s\n", msg);
- exit(FINI_ERROR);
+ fb_utils::logAndDie(msg);
}
Modified: firebird/branches/B2_5_Release/src/jrd/isc_sync.cpp
===================================================================
--- firebird/branches/B2_5_Release/src/jrd/isc_sync.cpp 2012-12-14 17:40:09 UTC (rev 57488)
+++ firebird/branches/B2_5_Release/src/jrd/isc_sync.cpp 2012-12-14 17:45:38 UTC (rev 57489)
@@ -70,7 +70,6 @@
#include "../common/config/config.h"
#include "../common/utils_proto.h"
#include "../common/StatusArg.h"
-#include "../common/classes/RefMutex.h"
static int process_id;
Modified: firebird/branches/B2_5_Release/src/jrd/jrd.cpp
===================================================================
--- firebird/branches/B2_5_Release/src/jrd/jrd.cpp 2012-12-14 17:40:09 UTC (rev 57488)
+++ firebird/branches/B2_5_Release/src/jrd/jrd.cpp 2012-12-14 17:45:38 UTC (rev 57489)
@@ -125,7 +125,6 @@
#include "../jrd/IntlManager.h"
#include "../common/classes/fb_tls.h"
#include "../common/classes/ClumpletReader.h"
-#include "../common/classes/RefMutex.h"
#include "../common/utils_proto.h"
#include "../jrd/DebugInterface.h"
@@ -148,10 +147,33 @@
namespace
{
+ // This mutex is set when new Database block is created. It's global first of all to satisfy
+ // SS requirement - avoid 2 Database blocks for same database (file). Also guarantees no
+ // half-done Database block in databases linked list. Always taken before databases_mutex.
+ GlobalPtr<Mutex> db_init_mutex;
+
Database* databases = NULL;
+ bool engineShuttingDown = false;
+ // This mutex protects both linked list of databases and flag engineShuttingDown.
+ // Flag engineShuttingDown guarantees that no new attachment is created after setting it.
GlobalPtr<Mutex> databases_mutex;
- bool engineShuttingDown = false;
+ // We have 2 more related types of mutexes in database and attachment.
+ // Attachment is using reference counted mutex in PublicHandle, also making it possible
+ // to check does object still exist after locking a mutex. This makes great use when
+ // checking for correctness of attachment handle in jrd8* entrypoints. Attachment mutex
+ // is always taken before databases_mutex (but after db_init_mutex when new attachment
+ // is created). Attachment mutex is never released inside engine. Database mutex (dbb_sync)
+ // is taken when engine starts to work with some database and released when there is no
+ // active job (when waiting for something) or when rescheduling. No other mutex from above
+ // mentioned here can be taken after dbb_sync with an exception of attachment mutex for new
+ // attachment. So finally the order of taking mutexes is:
+ // 1. db_init_mutex (in attach/create database) or attachment mutex in other calls
+ // 2. databases_mutex (when / if needed)
+ // 3. dbb_sync
+ // 4. only for new attachments: attachment mutex
+ // Any of this may be missing when not needed, but order of taking should not be changed.
+
class EngineStartup
{
public:
@@ -168,106 +190,123 @@
InitMutex<EngineStartup> engineStartup;
- inline void validateHandle(thread_db* tdbb, Attachment* const attachment)
+ inline void validateHandle(Service* service)
{
- if (attachment && attachment == tdbb->getAttachment())
+ if (service && service->checkHandle())
return;
- if (!attachment->checkHandle() || !attachment->att_database->checkHandle())
+ status_exception::raise(Arg::Gds(isc_bad_svc_handle));
+ }
+
+ class AttachmentHolder : public PublicHandleHolder
+ {
+ public:
+ AttachmentHolder(Attachment* const attachment, const char* from)
{
- status_exception::raise(Arg::Gds(isc_bad_db_handle));
+ if (!hold(attachment, from))
+ Arg::Gds(isc_bad_db_handle).raise();
}
- tdbb->setAttachment(attachment);
- tdbb->setDatabase(attachment->att_database);
- }
+ AttachmentHolder(thread_db* tdbb, Attachment* const attachment, const char* from)
+ {
+ validateHandle(tdbb, attachment, from);
+ }
- inline void validateHandle(thread_db* tdbb, jrd_tra* const transaction)
- {
- if (!transaction->checkHandle())
- status_exception::raise(Arg::Gds(isc_bad_trans_handle));
+ AttachmentHolder(thread_db* tdbb, jrd_tra* const transaction, const char* from)
+ {
+ validateHandle(tdbb, transaction, from);
+ }
- validateHandle(tdbb, transaction->tra_attachment);
+ AttachmentHolder(thread_db* tdbb, jrd_req* const request, const char* from)
+ {
+ validateHandle(tdbb, request, from);
+ }
- tdbb->setTransaction(transaction);
- }
+ AttachmentHolder(thread_db* tdbb, dsql_req* const statement, const char* from)
+ {
+ validateHandle(tdbb, statement, from);
+ }
- inline void validateHandle(thread_db* tdbb, jrd_req* const request)
- {
- if (!request->checkHandle())
- status_exception::raise(Arg::Gds(isc_bad_req_handle));
+ AttachmentHolder(thread_db* tdbb, blb* blob, const char* from)
+ {
+ validateHandle(tdbb, blob, from);
+ }
- validateHandle(tdbb, request->req_attachment);
- }
+ private:
+ thread_db* tdbb;
- inline void validateHandle(thread_db* tdbb, dsql_req* const statement)
- {
- if (!statement->checkHandle())
- status_exception::raise(Arg::Gds(isc_bad_req_handle));
+ private:
+ inline void validateHandle(thread_db* tdbb, Attachment* const attachment, const char* from)
+ {
+ if (attachment && attachment == tdbb->getAttachment())
+ return;
- validateHandle(tdbb, statement->req_dbb->dbb_attachment);
- }
+ if (attachment)
+ {
+ if (engineShuttingDown) // this is optimization check, engineShuttingDown
+ { // does not guarantee threads not to enter engine
+ status_exception::raise(Arg::Gds(isc_att_shutdown));
+ }
+ }
- inline void validateHandle(thread_db* tdbb, blb* blob)
- {
- if (!blob->checkHandle())
- status_exception::raise(Arg::Gds(isc_bad_segstr_handle));
+ if (!hold(attachment, from) || !attachment->checkHandle() || !attachment->att_database->checkHandle())
+ {
+ status_exception::raise(Arg::Gds(isc_bad_db_handle));
+ }
- validateHandle(tdbb, blob->blb_transaction);
- validateHandle(tdbb, blob->blb_attachment);
- }
+ tdbb->setAttachment(attachment);
+ tdbb->setDatabase(attachment->att_database);
+ }
- inline void validateHandle(Service* service)
- {
- if (service && service->checkHandle())
- return;
+public:
+ inline void validateHandle(thread_db* tdbb, jrd_tra* const transaction, const char* from)
+ {
+ if (!transaction->checkHandle())
+ status_exception::raise(Arg::Gds(isc_bad_trans_handle));
- status_exception::raise(Arg::Gds(isc_bad_svc_handle));
- }
+ validateHandle(tdbb, transaction->tra_attachment, from);
- class AttachmentHolder
- {
- public:
- AttachmentHolder(thread_db* arg, bool lockAtt)
- : tdbb(arg)
+ tdbb->setTransaction(transaction);
+ }
+
+private:
+ inline void validateHandle(thread_db* tdbb, jrd_req* const request, const char* from)
{
- Attachment* attachment = tdbb->getAttachment();
- if (lockAtt && attachment)
- {
- if (engineShuttingDown)
- status_exception::raise(Arg::Gds(isc_att_shutdown));
+ if (!request->checkHandle())
+ status_exception::raise(Arg::Gds(isc_bad_req_handle));
- attachment->att_mutex.enter();
- attLocked = true;
- }
- else
- attLocked = false;
+ validateHandle(tdbb, request->req_attachment, from);
}
- ~AttachmentHolder()
+ inline void validateHandle(thread_db* tdbb, dsql_req* const statement, const char* from)
{
- Attachment* attachment = tdbb->getAttachment();
- if (attLocked && attachment)
- attachment->att_mutex.leave();
+ if (!statement->checkHandle())
+ status_exception::raise(Arg::Gds(isc_bad_req_handle));
+
+ validateHandle(tdbb, statement->req_dbb->dbb_attachment, from);
}
- private:
- thread_db* tdbb;
- bool attLocked;
+ inline void validateHandle(thread_db* tdbb, blb* blob, const char* from)
+ {
+ if (!blob->checkHandle())
+ status_exception::raise(Arg::Gds(isc_bad_segstr_handle));
+ validateHandle(tdbb, blob->blb_transaction, from);
+ validateHandle(tdbb, blob->blb_attachment, from);
+ }
+
private:
// copying is prohibited
AttachmentHolder(const AttachmentHolder&);
AttachmentHolder& operator =(const AttachmentHolder&);
};
- class DatabaseContextHolder : public AttachmentHolder, Database::SyncGuard,
+ class DatabaseContextHolder : public Database::SyncGuard,
public Jrd::ContextPoolHolder
{
public:
- explicit DatabaseContextHolder(thread_db* arg, bool lockAtt = true)
- : AttachmentHolder(arg, lockAtt),
- Database::SyncGuard(arg->getDatabase()),
+ explicit DatabaseContextHolder(thread_db* arg)
+ : Database::SyncGuard(arg->getDatabase()),
Jrd::ContextPoolHolder(arg, arg->getDatabase()->dbb_permanent),
tdbb(arg)
{
@@ -515,8 +554,11 @@
const DatabaseOptions* m_options;
};
-static void cancel_attachments();
-static void check_database(thread_db* tdbb);
+namespace {
+ const unsigned CHECK_ASYNC = 1;
+ const unsigned CHECK_DISCONNECT = 2;
+}
+static void check_database(thread_db* tdbb, unsigned flags = 0);
static void check_transaction(thread_db*, jrd_tra*);
static void commit(thread_db*, jrd_tra*, const bool);
static bool drop_files(const jrd_file*);
@@ -541,72 +583,21 @@
static void ExtractDriveLetter(const TEXT*, ULONG*);
#endif
-static Database* init(thread_db*, const PathName&, bool);
+static void init(thread_db*, const PathName&, const PathName&, bool, const DatabaseOptions&);
+static Attachment* create_attachment(const PathName&, Database*, const DatabaseOptions&);
static void prepare(thread_db*, jrd_tra*, USHORT, const UCHAR*);
static void release_attachment(thread_db*, Attachment*);
static void detachLocksFromAttachment(Attachment*);
static void rollback(thread_db*, jrd_tra*, const bool);
static void shutdown_database(Database*, const bool);
+static bool unlink_database(Database*);
static void strip_quotes(string&);
static void purge_attachment(thread_db*, Attachment*, const bool);
static void getUserInfo(UserId&, const DatabaseOptions&);
-static bool shutdown_dbb(thread_db*, Database*);
static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM);
-static void cancel_attachments()
-{
- MutexLockGuard guard(databases_mutex);
- engineShuttingDown = true;
-
- for (Database* dbb = databases; dbb; dbb = dbb->dbb_next)
- {
- if ( !(dbb->dbb_flags & (DBB_bugcheck | DBB_not_in_use | DBB_security_db)) )
- {
- Database::SyncGuard dsGuard(dbb);
- Attachment* lockedAtt = NULL;
- Attachment* att = dbb->dbb_attachments;
-
- while (att)
- {
- // Try to cancel attachment and lock it. Handle case when attachment
- // deleted while waiting for lock.
- while (true)
- {
- if (att->att_mutex.tryEnter() || (att->att_flags & ATT_purge_error))
- {
- lockedAtt = att;
- break;
- }
-
- {
- const bool cancel_disable = (att->att_flags & ATT_cancel_disable);
- Database::Checkout dcoHolder(dbb);
- if (!cancel_disable)
- {
- ISC_STATUS_ARRAY status;
- jrd8_cancel_operation(status, &att, fb_cancel_enable);
- jrd8_cancel_operation(status, &att, fb_cancel_raise);
- }
- THREAD_SLEEP(10);
- }
-
- // check if attachment still exist
- if (lockedAtt && lockedAtt->att_next != att) {
- break;
- }
- if (dbb->dbb_attachments != att) {
- break;
- }
- }
- att = lockedAtt ? lockedAtt->att_next : dbb->dbb_attachments;
- }
- }
- }
-}
-
-
//____________________________________________________________
//
// check whether we need to perform an autocommit;
@@ -832,7 +823,12 @@
bool invalid_client_SQL_dialect = false;
PathName file_name, expanded_name;
bool is_alias = false;
+ MutexEnsureUnlock guardDbInit(db_init_mutex);
+#ifdef WIN_NT
+ guardDbInit.enter(); // Required to correctly expand name of just created database
+#endif
+
try
{
// Process database parameter block
@@ -905,49 +901,47 @@
}
Database* dbb = NULL;
- MutexEnsureUnlock guardDatabases(databases_mutex);
- guardDatabases.enter();
+ Attachment* attachment = NULL;
+ // Initialize special error handling
+
try
{
- // Unless we're already attached, do some initialization
- dbb = init(tdbb, expanded_name, true);
- }
- catch (const Exception& ex)
+ // If database to be opened is security database, then only
+ // gsec or SecurityDatabase may open it. This protects from use
+ // of old gsec to write wrong password hashes into it. */
+ if (vdn == VDN_SECURITY && !options.dpb_gsec_attach && !options.dpb_sec_attach)
{
- return ex.stuff_exception(user_status);
+ ERR_post(Arg::Gds(isc_no_priv) << Arg::Str("direct") <<
+ Arg::Str("security database") <<
+ Arg::Str(file_name));
}
+#ifndef WIN_NT
+ guardDbInit.enter();
+#endif
+
+ // Unless we're already attached, do some initialization
+ init(tdbb, expanded_name, is_alias ? file_name : expanded_name, true, options);
+ dbb = tdbb->getDatabase();
fb_assert(dbb);
+ attachment = tdbb->getAttachment();
+ fb_assert(attachment);
- tdbb->setDatabase(dbb);
DatabaseContextHolder dbbHolder(tdbb);
- dbb->dbb_flags |= DBB_being_opened;
-
- // Initialize special error handling
-
- Attachment* attachment = NULL;
-
- bool initing_security = false;
-
- try {
-
-/* If database to be opened is security database, then only
- gsec or SecurityDatabase may open it. This protects from use
- of old gsec to write wrong password hashes into it. */
- if (vdn == VDN_SECURITY && !options.dpb_gsec_attach && !options.dpb_sec_attach)
+ if (!(dbb->dbb_flags & DBB_new))
{
- ERR_post(Arg::Gds(isc_no_priv) << Arg::Str("direct") <<
- Arg::Str("security database") <<
- Arg::Str(file_name));
+ // That's already initialized DBB
+ // No need keeping db_init_mutex locked any more
+ guardDbInit.leave();
}
// Worry about encryption key
if (dbb->dbb_decrypt)
{
- if (dbb->dbb_filename.hasData() &&
+ if (!(dbb->dbb_flags & DBB_new) &&
(dbb->dbb_encrypt_key.hasData() || options.dpb_key.hasData()))
{
if ((dbb->dbb_encrypt_key.hasData() && options.dpb_key.isEmpty()) ||
@@ -965,22 +959,10 @@
}
}
- attachment = Attachment::create(dbb);
- tdbb->setAttachment(attachment);
- attachment->att_filename = is_alias ? file_name : expanded_name;
- attachment->att_network_protocol = options.dpb_network_protocol;
- attachment->att_remote_address = options.dpb_remote_address;
- attachment->att_remote_pid = options.dpb_remote_pid;
- attachment->att_remote_process = options.dpb_remote_process;
- attachment->att_next = dbb->dbb_attachments;
- attachment->att_ext_call_depth = options.dpb_ext_call_depth;
-
// make attachment keep sec_db fini info
attachment->att_fini_sec_db = userId.usr_fini_sec_db;
userId.usr_fini_sec_db = false;
- dbb->dbb_attachments = attachment;
- dbb->dbb_flags &= ~DBB_being_opened;
dbb->dbb_sys_trans->tra_attachment = attachment;
attachment->att_charset = options.dpb_interp;
@@ -1001,25 +983,9 @@
attachment->att_working_directory = options.dpb_working_directory;
}
- // If we're a not a secondary attachment, initialize some stuff
-
- bool first = false;
-
- if (dbb->dbb_filename.empty())
+ if (dbb->dbb_flags & DBB_new)
{
-#if defined(DEV_BUILD) && defined(SUPERSERVER)
- // make sure we do not reopen same DB twice
- for (Database* d = databases; d; d = d->dbb_next)
- {
- if (d->dbb_filename == expanded_name)
- {
- fatal_exception::raise(("Attempt to reopen " + expanded_name).c_str());
- }
- }
-#endif
- first = true;
- dbb->dbb_filename = expanded_name;
- dbb->dbb_flags |= options.dpb_flags;
+ // If we're a not a secondary attachment, initialize some stuff
// NS: Use alias as database ID only if accessing database using file name is not possible.
//
@@ -1079,6 +1045,10 @@
// Turn monitoring on
init_monitoring_lock(tdbb);
+
+ // Init complete - we can release db_init_mutex
+ dbb->dbb_flags &= ~DBB_new;
+ guardDbInit.leave();
}
else
{
@@ -1114,8 +1084,6 @@
TRA_cleanup(tdbb);
}
- initing_security = true;
-
if (invalid_client_SQL_dialect)
{
ERR_post(Arg::Gds(isc_inv_client_dialect_specified) << Arg::Num(options.dpb_sql_dialect) <<
@@ -1209,8 +1177,6 @@
SCL_init(tdbb, false, userId);
- initing_security = false;
-
// This pair (SHUT_database/SHUT_online) checks itself for valid user name
if (options.dpb_shutdown)
{
@@ -1399,8 +1365,6 @@
// if there was an error, the status vector is all set
- guardDatabases.leave();
-
if (options.dpb_sweep & isc_dpb_records) {
TRA_sweep(tdbb);
}
@@ -1457,10 +1421,12 @@
}
}
- // guardDatabases.leave();
-
*handle = attachment;
- attachment->att_mutex.leave();
+ if (attachment->att_flags & ATT_manual_lock)
+ {
+ attachment->att_flags &= ~ATT_manual_lock;
+ attachment->mutex()->leave();
+ }
} // try
catch (const Exception& ex)
@@ -1498,7 +1464,7 @@
ThreadContextHolder tdbb(user_status);
blb* const blob = *blob_handle;
- validateHandle(tdbb, blob);
+ AttachmentHolder attHolder(tdbb, blob, "GDS_BLOB_INFO");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -1539,7 +1505,7 @@
ThreadContextHolder tdbb(user_status);
blb* const blob = *blob_handle;
- validateHandle(tdbb, blob);
+ AttachmentHolder attHolder(tdbb, blob, "GDS_CANCEL_BLOB");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -1578,7 +1544,7 @@
{
ThreadContextHolder tdbb(user_status);
- validateHandle(tdbb, *handle);
+ AttachmentHolder attHolder(tdbb, *handle, "GDS_CANCEL_EVENTS");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -1621,37 +1587,59 @@
{
ThreadContextHolder tdbb(user_status);
- Attachment* const attachment = *handle;
- validateHandle(tdbb, attachment);
- DatabaseContextHolder dbbHolder(tdbb, false);
-
- switch (option)
+ class CancelOperation : public ExecuteWithLock
{
- case fb_cancel_disable:
- attachment->att_flags |= ATT_cancel_disable;
- attachment->att_flags &= ~ATT_cancel_raise;
- break;
+ public:
+ CancelOperation(thread_db* arg, Attachment* att, USHORT opt)
+ : tdbb(arg), attachment(att), option(opt)
+ { }
- case fb_cancel_enable:
- if (attachment->att_flags & ATT_cancel_disable)
+ void execute()
{
- // avoid leaving ATT_cancel_raise set when cleaning ATT_cancel_disable
- // to avoid unexpected CANCEL (though it should not be set, but...)
- attachment->att_flags &= ~(ATT_cancel_disable | ATT_cancel_raise);
- }
- break;
+ tdbb->setDatabase(attachment->att_database);
- case fb_cancel_raise:
- if (!(attachment->att_flags & ATT_cancel_disable))
- {
- attachment->att_flags |= ATT_cancel_raise;
- attachment->cancelExternalConnection(tdbb);
- LCK_cancel_wait(attachment);
+ switch (option)
+ {
+ case fb_cancel_disable:
+ attachment->att_flags |= ATT_cancel_disable;
+ attachment->att_flags &= ~ATT_cancel_raise;
+ break;
+
+ case fb_cancel_enable:
+ if (attachment->att_flags & ATT_cancel_disable)
+ {
+ // avoid leaving ATT_cancel_raise set when cleaning ATT_cancel_disable
+ // to avoid unexpected CANCEL (though it should not be set, but...)
+ attachment->att_flags &= ~(ATT_cancel_disable | ATT_cancel_raise);
+ }
+ break;
+
+ case fb_cancel_raise:
+ if (!(attachment->att_flags & ATT_cancel_disable))
+ {
+ attachment->att_flags |= ATT_cancel_raise;
+ attachment->cancelExternalConnection(tdbb);
+ LCK_cancel_wait(attachment);
+ }
+ break;
+
+ default:
+ fb_assert(false);
+ }
}
- break;
- default:
- fb_assert(false);
+ private:
+ thread_db* tdbb;
+ Attachment* attachment;
+ USHORT option;
+ };
+
+ Attachment* const attachment = *handle;
+ CancelOperation cancelOperation(tdbb, attachment, option);
+
+ if (!attachment->executeWithLock(&cancelOperation))
+ {
+ Arg::Gds(isc_bad_db_handle).raise();
}
}
catch (const Exception& ex)
@@ -1680,7 +1668,7 @@
ThreadContextHolder tdbb(user_status);
blb* const blob = *blob_handle;
- validateHandle(tdbb, blob);
+ AttachmentHolder attHolder(tdbb, blob, "GDS_CLOSE_BLOB");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -1719,7 +1707,7 @@
{
ThreadContextHolder tdbb(user_status);
- validateHandle(tdbb, *tra_handle);
+ AttachmentHolder attHolder(tdbb, *tra_handle, "GDS_COMMIT");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -1757,7 +1745,7 @@
{
ThreadContextHolder tdbb(user_status);
- validateHandle(tdbb, *tra_handle);
+ AttachmentHolder attHolder(tdbb, *tra_handle, "GDS_COMMIT_RETAINING");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -1799,7 +1787,7 @@
ThreadContextHolder tdbb(user_status);
Attachment* const attachment = *db_handle;
- validateHandle(tdbb, attachment);
+ AttachmentHolder attHolder(tdbb, attachment, "GDS_COMPILE");
DatabaseContextHolder dbbHolder(tdbb);
check_database(tdbb);
@@ -1858,8 +1846,8 @@
ThreadContextHolder tdbb(user_status);
- validateHandle(tdbb, *db_handle);
- validateHandle(tdbb, *tra_handle);
+ AttachmentHolder attHolder(tdbb, *db_handle, "GDS_CREATE_BLOB2");
+ attHolder.validateHandle(tdbb, *tra_handle, "GDS_CREATE_BLOB2 (should not happen)");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -1900,6 +1888,7 @@
*
**************************************/
ThreadContextHolder tdbb(user_status);
+ MutexEnsureUnlock guardDbInit(db_init_mutex);
if (*handle)
{
@@ -1911,6 +1900,12 @@
PathName file_name, expanded_name;
bool is_alias = false;
+#ifdef WIN_NT
+ // In windows expanded filename depend upon file existence
+ // Therefore have to keep lock longer
+ guardDbInit.enter();
+#endif
+
try {
// Process database parameter block
bool invalid_client_SQL_dialect = false;
@@ -1969,70 +1964,55 @@
trace_failed_attach(NULL, filename, options, true, user_status);
ex.sleep();
- return ret;
+ return ret;
}
catch (const Exception& ex)
{
const ISC_STATUS ret = ex.stuff_exception(user_status);
trace_failed_attach(NULL, filename, options, true, user_status);
- return ret;
+ return ret;
}
// Check database against conf file.
const VdnResult vdn = verifyDatabaseName(expanded_name, user_status, is_alias);
if (!is_alias && vdn == VDN_FAIL)
{
- trace_failed_attach(NULL, filename, options, true, false);
+ trace_failed_attach(NULL, filename, options, true, user_status);
return user_status[1];
}
Database* dbb = NULL;
- MutexEnsureUnlock guardDatabases(databases_mutex);
- guardDatabases.enter();
+ Attachment* attachment = NULL;
+ // Initialize special error handling
+
try
{
- dbb = init(tdbb, expanded_name, false);
- }
- catch (const Exception& ex)
- {
- return ex.stuff_exception(user_status);
- }
+#ifndef WIN_NT
+ guardDbInit.enter();
+#endif
+
+ // Unless we're already attached, do some initialization
+ init(tdbb, expanded_name, is_alias ? file_name : expanded_name, false, options);
+ dbb = tdbb->getDatabase();
fb_assert(dbb);
+ attachment = tdbb->getAttachment();
+ fb_assert(attachment);
- tdbb->setDatabase(dbb);
DatabaseContextHolder dbbHolder(tdbb);
- dbb->dbb_flags |= (DBB_being_opened | options.dpb_flags);
+ fb_assert(dbb->dbb_flags & DBB_new);
- Attachment* attachment = NULL;
-
- bool initing_security = false;
-
- try {
-
if (options.dpb_key.hasData())
{
dbb->dbb_encrypt_key = options.dpb_key;
}
- attachment = Attachment::create(dbb);
- tdbb->setAttachment(attachment);
- attachment->att_filename = is_alias ? file_name : expanded_name;
- attachment->att_network_protocol = options.dpb_network_protocol;
- attachment->att_remote_address = options.dpb_remote_address;
- attachment->att_remote_pid = options.dpb_remote_pid;
- attachment->att_remote_process = options.dpb_remote_process;
- attachment->att_ext_call_depth = options.dpb_ext_call_depth;
- attachment->att_next = dbb->dbb_attachments;
-
// make attachment keep sec_db fini info
attachment->att_fini_sec_db = userId.usr_fini_sec_db;
userId.usr_fini_sec_db = false;
- dbb->dbb_attachments = attachment;
- dbb->dbb_flags &= ~DBB_being_opened;
dbb->dbb_sys_trans->tra_attachment = attachment;
if (options.dpb_working_directory.hasData()) {
@@ -2079,8 +2059,6 @@
dbb->dbb_page_size = (page_size > MAX_PAGE_SIZE) ? MAX_PAGE_SIZE : page_size;
- initing_security = false;
-
PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
try
{
@@ -2128,6 +2106,10 @@
const jrd_file* const first_dbb_file = pageSpace->file;
+#ifdef WIN_NT
+ dbb->dbb_filename.assign(first_dbb_file->fil_string);
+#endif
+
// Initialize the lock manager
dbb->dbb_lock_mgr = LockManager::create(dbb->getUniqueFileId());
@@ -2142,7 +2124,6 @@
INI_init(tdbb);
PAG_init(tdbb);
- initing_security = true;
attachment->att_requested_role = userId.usr_sql_role_name;
SCL_init(tdbb, true, userId);
@@ -2152,12 +2133,6 @@
CCH_init(tdbb, options.dpb_buffers);
-#ifdef WIN_NT
- dbb->dbb_filename.assign(first_dbb_file->fil_string);
-#else
- dbb->dbb_filename = expanded_name;
-#endif
-
// NS: Use alias as database ID only if accessing database using file name is not possible.
//
// This way we:
@@ -2240,6 +2215,10 @@
dbb->dbb_backup_manager->dbCreating = false;
+ // Init complete - we can release db_init_mutex
+ dbb->dbb_flags &= ~DBB_new;
+ guardDbInit.leave();
+
// Report that we created attachment to Trace API
if (attachment->att_trace_manager->needs().event_attach)
{
@@ -2247,10 +2226,12 @@
attachment->att_trace_manager->event_attach(&conn, true, res_successful);
}
- guardDatabases.leave();
-
*handle = attachment;
- attachment->att_mutex.leave();
+ if (attachment->att_flags & ATT_manual_lock)
+ {
+ attachment->att_flags &= ~ATT_manual_lock;
+ attachment->mutex()->leave();
+ }
} // try
catch (const Exception& ex)
@@ -2288,7 +2269,7 @@
ThreadContextHolder tdbb(user_status);
Attachment* const attachment = *handle;
- validateHandle(tdbb, attachment);
+ AttachmentHolder attHolder(tdbb, attachment, "GDS_DATABASE_INFO");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -2332,8 +2313,8 @@
ThreadContextHolder tdbb(user_status);
Attachment* const attachment = *db_handle;
- validateHandle(tdbb, attachment);
- validateHandle(tdbb, *tra_handle);
+ AttachmentHolder attHolder(tdbb, attachment, "GDS_DDL");
+ attHolder.validateHandle(tdbb, *tra_handle, "GDS_DDL (should not happen)");
DatabaseContextHolder dbbHolder(tdbb);
check_database(tdbb);
@@ -2378,38 +2359,14 @@
{
ThreadContextHolder tdbb(user_status);
- { // scope
- MutexLockGuard guard(databases_mutex);
+ Attachment* const attachment = *handle;
+ AttachmentHolder attHolder(tdbb, attachment, "GDS_DETACH");
- Attachment* const attachment = *handle;
- validateHandle(tdbb, attachment);
+ DatabaseContextHolder dbbHolder(tdbb);
+ check_database(tdbb, CHECK_DISCONNECT);
- { // holder scope
- DatabaseContextHolder dbbHolder(tdbb);
-
- Database* dbb = tdbb->getDatabase();
-
- // if this is the last attachment, mark dbb as not in use
- if (dbb->dbb_attachments == attachment && !attachment->att_next &&
- !(dbb->dbb_flags & DBB_being_opened))
- {
- dbb->dbb_flags |= DBB_not_in_use;
- }
-
- try
- {
- // Purge attachment, don't rollback open transactions
- attachment->att_flags |= ATT_cancel_disable;
- purge_attachment(tdbb, attachment, false);
- }
- catch (const Exception&)
- {
- dbb->dbb_flags &= ~DBB_not_in_use;
- throw;
- }
- }
- }
-
+ attachment->att_flags |= ATT_protected;
+ purge_attachment(tdbb, attachment, false);
*handle = NULL;
}
catch (const Exception& ex)
@@ -2437,100 +2394,103 @@
{
ThreadContextHolder tdbb(user_status);
- MutexLockGuard guard(databases_mutex);
+ Attachment* const attachment = *handle;
+ AttachmentHolder attHolder(tdbb, attachment, "GDS_DROP_DATABASE");
- Attachment* const attachment = *handle;
- validateHandle(tdbb, attachment);
- DatabaseContextHolder dbbHolder(tdbb);
try
{
Database* const dbb = tdbb->getDatabase();
- const PathName& file_name = attachment->att_filename;
+ { // scope
+ DatabaseContextHolder dbbHolder(tdbb);
+ check_database(tdbb, CHECK_DISCONNECT);
- if (!attachment->locksmith())
- {
- ERR_post(Arg::Gds(isc_no_priv) << Arg::Str("drop") <<
- Arg::Str("database") <<
- Arg::Str(file_name));
- }
+ const PathName& file_name = attachment->att_filename;
- if (attachment->att_flags & ATT_shutdown)
- {
- if (dbb->dbb_ast_flags & DBB_shutdown)
+ if (!attachment->locksmith())
{
- ERR_post(Arg::Gds(isc_shutdown) << Arg::Str(file_name));
+ ERR_post(Arg::Gds(isc_no_priv) << Arg::Str("drop") <<
+ Arg::Str("database") <<
+ Arg::Str(file_name));
}
- else
+
+ if (attachment->att_flags & ATT_shutdown)
{
- ERR_post(Arg::Gds(isc_att_shutdown));
+ if (dbb->dbb_ast_flags & DBB_shutdown)
+ {
+ ERR_post(Arg::Gds(isc_shutdown) << Arg::Str(file_name));
+ }
+ else
+ {
+ ERR_post(Arg::Gds(isc_att_shutdown));
+ }
}
- }
- if (!CCH_exclusive(tdbb, LCK_PW, WAIT_PERIOD))
- {
- ERR_post(Arg::Gds(isc_lock_timeout) <<
- Arg::Gds(isc_obj_in_use) << Arg::Str(file_name));
- }
+ if (!CCH_exclusive(tdbb, LCK_PW, WAIT_PERIOD))
+ {
+ ERR_post(Arg::Gds(isc_lock_timeout) <<
+ Arg::Gds(isc_obj_in_use) << Arg::Str(file_name));
+ }
- // Check if same process has more attachments
+ // Check if same process has more attachments
- if (dbb->dbb_attachments && dbb->dbb_attachments->att_next)
- {
- ERR_post(Arg::Gds(isc_no_meta_update) <<
- Arg::Gds(isc_obj_in_use) << Arg::Str("DATABASE"));
- }
+ if (dbb->dbb_attachments && dbb->dbb_attachments->att_next)
+ {
+ ERR_post(Arg::Gds(isc_no_meta_update) <<
+ Arg::Gds(isc_obj_in_use) << Arg::Str("DATABASE"));
+ }
- // Forced release of all transactions
- purge_transactions(tdbb, attachment, true, attachment->att_flags);
+ // Forced release of all transactions
+ purge_transactions(tdbb, attachment, true, attachment->att_flags);
- attachment->att_flags |= ATT_cancel_disable;
+ attachment->att_flags |= ATT_protected;
- // Here we have database locked in exclusive mode.
- // Just mark the header page with an 0 ods version so that no other
- // process can attach to this database once we release our exclusive
- // lock and start dropping files.
+ // Here we have database locked in exclusive mode.
+ // Just mark the header page with an 0 ods version so that no other
+ // process can attach to this database once we release our exclusive
+ // lock and start dropping files.
- WIN window(HEADER_PAGE_NUMBER);
- Ods::header_page* header = (Ods::header_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_header);
- CCH_MARK_MUST_WRITE(tdbb, &window);
- header->hdr_ods_version = 0;
- CCH_RELEASE(tdbb, &window);
+ WIN window(HEADER_PAGE_NUMBER);
+ Ods::header_page* header = (Ods::header_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_header);
+ CCH_MARK_MUST_WRITE(tdbb, &window);
+ header->hdr_ods_version = 0;
+ CCH_RELEASE(tdbb, &window);
- // This point on database is useless
- // mark the dbb unusable
+ // Notify Trace API manager about successful drop of database
+ if (attachment->att_trace_manager->needs().event_detach)
+ {
+ TraceConnectionImpl conn(attachment);
+ attachment->att_trace_manager->event_detach(&conn, true);
+ }
- dbb->dbb_flags |= DBB_not_in_use;
- *handle = NULL;
+ // Unlink attachment from database
+ release_attachment(tdbb, attachment);
+ *handle = 0;
+ }
- PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
- const jrd_file* file = pageSpace->file;
- const Shadow* shadow = dbb->dbb_shadow;
-
- // Notify Trace API manager about successful drop of database
- if (attachment->att_trace_manager->needs().event_detach)
+ // This point on database is useless
+ // mark the dbb unusable and remove it from linked list
+ if (unlink_database(dbb))
{
- TraceConnectionImpl conn(attachment);
- attachment->att_trace_manager->event_detach(&conn, true);
- }
+ PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
+ const jrd_file* file = pageSpace->file;
+ const Shadow* shadow = dbb->dbb_shadow;
- // Unlink attachment from database
- release_attachment(tdbb, attachment);
+ shutdown_database(dbb, false);
- shutdown_database(dbb, false);
+ // drop the files here
+ bool err = drop_files(file);
+ for (; shadow; shadow = shadow->sdw_next)
+ {
+ err = err || drop_files(shadow->sdw_file);
+ }
- // drop the files here
- bool err = drop_files(file);
- for (; shadow; shadow = shadow->sdw_next)
- {
- err = err || drop_files(shadow->sdw_file);
- }
+ tdbb->setDatabase(NULL);
+ Database::destroy(dbb);
- tdbb->setDatabase(NULL);
- Database::destroy(dbb);
-
- if (err) {
- ERR_build_status(user_status, Arg::Gds(isc_drdb_completed_with_errs));
+ if (err) {
+ ERR_build_status(user_status, Arg::Gds(isc_drdb_completed_with_errs));
+ }
}
}
catch (const Exception& ex)
@@ -2568,7 +2528,7 @@
ThreadContextHolder tdbb(user_status);
blb* const blob = *blob_handle;
- validateHandle(tdbb, blob);
+ AttachmentHolder attHolder(tdbb, blob, "GDS_GET_SEGMENT");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -2626,8 +2586,8 @@
{
ThreadContextHolder tdbb(user_status);
- validateHandle(tdbb, *db_handle);
- validateHandle(tdbb, *tra_handle);
+ AttachmentHolder attHolder(tdbb, *db_handle, "GDS_GET_SLICE");
+ attHolder.validateHandle(tdbb, *tra_handle, "GDS_GET_SLICE (should not happen)");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -2687,8 +2647,8 @@
ThreadContextHolder tdbb(user_status);
- validateHandle(tdbb, *db_handle);
- validateHandle(tdbb, *tra_handle);
+ AttachmentHolder attHolder(tdbb, *db_handle, "GDS_OPEN_BLOB2");
+ attHolder.validateHandle(tdbb, *tra_handle, "GDS_OPEN_BLOB2 (should not happen)");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -2730,7 +2690,7 @@
ThreadContextHolder tdbb(user_status);
jrd_tra* const transaction = *tra_handle;
- validateHandle(tdbb, transaction);
+ AttachmentHolder attHolder(tdbb, transaction, "GDS_PREPARE");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -2772,7 +2732,7 @@
ThreadContextHolder tdbb(user_status);
blb* const blob = *blob_handle;
- validateHandle(tdbb, blob);
+ AttachmentHolder attHolder(tdbb, blob, "GDS_PUT_SEGMENT");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -2819,8 +2779,8 @@
{
ThreadContextHolder tdbb(user_status);
- validateHandle(tdbb, *db_handle);
- validateHandle(tdbb, *tra_handle);
+ AttachmentHolder attHolder(tdbb, *db_handle, "GDS_PUT_SLICE");
+ attHolder.validateHandle(tdbb, *tra_handle, "GDS_PUT_SLICE (should not happen)");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -2868,7 +2828,7 @@
ThreadContextHolder tdbb(user_status);
Attachment* const attachment = *handle;
- validateHandle(tdbb, attachment);
+ AttachmentHolder attHolder(tdbb, attachment, "GDS_QUE_EVENTS");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -2925,7 +2885,7 @@
ThreadContextHolder tdbb(user_status);
jrd_req* const request = *req_handle;
- validateHandle(tdbb, request);
+ AttachmentHolder attHolder(tdbb, request, "GDS_RECEIVE");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -2977,7 +2937,7 @@
ThreadContextHolder tdbb(user_status);
Attachment* const attachment = *db_handle;
- validateHandle(tdbb, attachment);
+ AttachmentHolder attHolder(tdbb, attachment, "GDS_RECONNECT");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -3016,7 +2976,7 @@
ThreadContextHolder tdbb(user_status);
jrd_req* const request = *req_handle;
- validateHandle(tdbb, request);
+ AttachmentHolder attHolder(tdbb, request, "GDS_RELEASE_REQUEST");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -3062,7 +3022,7 @@
ThreadContextHolder tdbb(user_status);
jrd_req* const request = *req_handle;
- validateHandle(tdbb, request);
+ AttachmentHolder attHolder(tdbb, request, "GDS_REQUEST_INFO");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -3104,7 +3064,7 @@
{
ThreadContextHolder tdbb(user_status);
- validateHandle(tdbb, *tra_handle);
+ AttachmentHolder attHolder(tdbb, *tra_handle, "GDS_ROLLBACK_RETAINING");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -3142,7 +3102,7 @@
{
ThreadContextHolder tdbb(user_status);
- validateHandle(tdbb, *tra_handle);
+ AttachmentHolder attHolder(tdbb, *tra_handle, "GDS_ROLLBACK");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -3185,7 +3145,7 @@
ThreadContextHolder tdbb(user_status);
blb* const blob = *blob_handle;
- validateHandle(tdbb, blob);
+ AttachmentHolder attHolder(tdbb, blob, "GDS_SEEK_BLOB");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -3229,7 +3189,7 @@
ThreadContextHolder tdbb(user_status);
jrd_req* request = *req_handle;
- validateHandle(tdbb, request);
+ AttachmentHolder attHolder(tdbb, request, "GDS_SEND");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -3474,8 +3434,8 @@
ThreadContextHolder tdbb(user_status);
jrd_req* const request = *req_handle;
- validateHandle(tdbb, request);
- validateHandle(tdbb, *tra_handle);
+ AttachmentHolder attHolder(tdbb, request, "GDS_START_AND_SEND");
+ attHolder.validateHandle(tdbb, *tra_handle, "GDS_START_AND_SEND (should not happen)");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -3532,8 +3492,8 @@
ThreadContextHolder tdbb(user_status);
jrd_req* const request = *req_handle;
- validateHandle(tdbb, request);
- validateHandle(tdbb, *tra_handle);
+ AttachmentHolder attHolder(tdbb, request, "GDS_START");
+ attHolder.validateHandle(tdbb, *tra_handle, "GDS_START (should not happen)");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -3729,8 +3689,8 @@
ThreadContextHolder tdbb(user_status);
Attachment* const attachment = *db_handle;
- validateHandle(tdbb, attachment);
- validateHandle(tdbb, *tra_handle);
+ AttachmentHolder attHolder(tdbb, attachment, "GDS_TRANSACT_REQUEST");
+ attHolder.validateHandle(tdbb, *tra_handle, "GDS_TRANSACT_REQUEST (should not happen)");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -3866,7 +3826,7 @@
ThreadContextHolder tdbb(user_status);
jrd_tra* const transaction = *tra_handle;
- validateHandle(tdbb, transaction);
+ AttachmentHolder attHolder(tdbb, transaction, "GDS_TRANSACTION_INFO");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -3908,7 +3868,7 @@
ThreadContextHolder tdbb(user_status);
jrd_req* const request = *req_handle;
- validateHandle(tdbb, request);
+ AttachmentHolder attHolder(tdbb, request, "GDS_UNWIND");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -3942,7 +3902,7 @@
ThreadContextHolder tdbb(user_status);
Attachment* const attachment = *db_handle;
- validateHandle(tdbb, attachment);
+ AttachmentHolder attHolder(tdbb, attachment, "GDS_DSQL_ALLOCATE");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -3978,10 +3938,10 @@
ThreadContextHolder tdbb(user_status);
dsql_req* const statement = *stmt_handle;
- validateHandle(tdbb, statement);
+ AttachmentHolder attHolder(tdbb, statement, "GDS_DSQL_EXECUTE");
if (*tra_handle)
{
- validateHandle(tdbb, *tra_handle);
+ attHolder.validateHandle(tdbb, *tra_handle, "GDS_DSQL_EXECUTE (should not happen)");
}
DatabaseContextHolder dbbHolder(tdbb);
try
@@ -4023,10 +3983,10 @@
ThreadContextHolder tdbb(user_status);
Attachment* const attachment = *db_handle;
- validateHandle(tdbb, attachment);
+ AttachmentHolder attHolder(tdbb, attachment, "GDS_DSQL_EXECUTE_IMMEDIATE");
if (*tra_handle)
{
- validateHandle(tdbb, *tra_handle);
+ attHolder.validateHandle(tdbb, *tra_handle, "GDS_DSQL_EXECUTE_IMMEDIATE (should not happen)");
}
DatabaseContextHolder dbbHolder(tdbb);
try
@@ -4071,8 +4031,8 @@
ThreadContextHolder tdbb(user_status);
dsql_req* const statement = *stmt_handle;
- validateHandle(tdbb, statement);
- validateHandle(tdbb, statement->req_transaction);
+ AttachmentHolder attHolder(tdbb, statement, "GDS_DSQL_FETCH");
+ attHolder.validateHandle(tdbb, statement->req_transaction, "GDS_DSQL_FETCH (should not happen)");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -4107,7 +4067,7 @@
ThreadContextHolder tdbb(user_status);
dsql_req* const statement = *stmt_handle;
- validateHandle(tdbb, statement);
+ AttachmentHolder attHolder(tdbb, statement, "GDS_DSQL_FREE");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -4143,7 +4103,7 @@
ThreadContextHolder tdbb(user_status);
dsql_req* const statement = *stmt_handle;
- validateHandle(tdbb, statement);
+ AttachmentHolder attHolder(tdbb, statement, "GDS_DSQL_INSERT");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -4179,10 +4139,10 @@
ThreadContextHolder tdbb(user_status);
dsql_req* const statement = *stmt_handle;
- validateHandle(tdbb, statement);
+ AttachmentHolder attHolder(tdbb, statement, "GDS_DSQL_PREPARE");
if (*tra_handle)
{
- validateHandle(tdbb, *tra_handle);
+ attHolder.validateHandle(tdbb, *tra_handle, "GDS_DSQL_PREPARE (should not happen)");
}
DatabaseContextHolder dbbHolder(tdbb);
try
@@ -4218,7 +4178,7 @@
ThreadContextHolder tdbb(user_status);
dsql_req* const statement = *stmt_handle;
- validateHandle(tdbb, statement);
+ AttachmentHolder attHolder(tdbb, statement, "GDS_DSQL_SET_CURSOR");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -4251,7 +4211,7 @@
ThreadContextHolder tdbb(user_status);
dsql_req* const statement = *stmt_handle;
- validateHandle(tdbb, statement);
+ AttachmentHolder attHolder(tdbb, statement, "GDS_DSQL_SQL_INFO");
DatabaseContextHolder dbbHolder(tdbb);
try
{
@@ -4342,7 +4302,7 @@
* control so that somebody else may run.
*
**************************************/
-
+
Database* dbb = tdbb->getDatabase();
if (dbb->dbb_sync->hasContention())
@@ -4438,7 +4398,7 @@
}
-static void check_database(thread_db* tdbb)
+static void check_database(thread_db* tdbb, unsigned flags)
{
/**************************************
*
@@ -4455,44 +4415,52 @@
Database* dbb = tdbb->getDatabase();
Attachment* attachment = tdbb->getAttachment();
- const Attachment* attach = dbb->dbb_attachments;
- while (attach && attach != attachment)
- attach = attach->att_next;
+ if (!(flags & CHECK_ASYNC))
+ {
+ fb_assert(dbb->locked());
+ const Attachment* attach = dbb->dbb_attachments;
+ while (attach && attach != attachment)
+ attach = attach->att_next;
- if (!attach)
- status_exception::raise(Arg::Gds(isc_bad_db_handle));
-
- if (dbb->dbb_flags & DBB_bugcheck)
- {
- static const char string[] = "can't continue after bugcheck";
- status_exception::raise(Arg::Gds(isc_bug_check) << Arg::Str(string));
+ if (!attach)
+ status_exception::raise(Arg::Gds(isc_bad_db_handle));
}
- if ((attachment->att_flags & ATT_shutdown) ||
- ((dbb->dbb_ast_flags & DBB_shutdown) &&
- ((dbb->dbb_ast_flags & DBB_shutdown_full) || !attachment->locksmith())))
+ if (!(flags & CHECK_DISCONNECT))
{
- if (dbb->dbb_ast_flags & DBB_shutdown)
+ if (dbb->dbb_fl...
[truncated message content] |