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] |