8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 18:03:04 +01:00

Backported fix for #6947: Query to mon$ tables does not return data when the encryption/decryption thread is running

This commit is contained in:
AlexPeshkoff 2022-06-24 17:59:46 +03:00
parent d9d3c6cf65
commit 77118ed5fb
14 changed files with 212 additions and 104 deletions

View File

@ -210,7 +210,10 @@ void Thread::kill(Handle& thread)
ThreadId Thread::getId() ThreadId Thread::getId()
{ {
#ifdef USE_LWP_AS_THREAD_ID #ifdef USE_LWP_AS_THREAD_ID
return syscall(SYS_gettid); static __thread int tid = 0;
if (!tid)
tid = syscall(SYS_gettid);
return tid;
#else #else
return pthread_self(); return pthread_self();
#endif #endif

View File

@ -101,7 +101,7 @@ namespace Firebird
} }
}; };
template <typename Mtx, typename RefCounted = DefaultRefCounted<Mtx> > template <typename Mtx, template <typename T> class RefCounted = DefaultRefCounted >
class EnsureUnlock class EnsureUnlock
{ {
public: public:
@ -114,14 +114,14 @@ namespace Firebird
#define FB_LOCKED_FROM NULL #define FB_LOCKED_FROM NULL
#endif #endif
{ {
RefCounted::addRef(m_mutex); RefCounted<Mtx>::addRef(m_mutex);
} }
~EnsureUnlock() ~EnsureUnlock()
{ {
while (m_locked) while (m_locked)
leave(); leave();
RefCounted::release(m_mutex); RefCounted<Mtx>::release(m_mutex);
} }
void enter() void enter()
@ -155,7 +155,7 @@ namespace Firebird
}; };
#undef FB_LOCKED_FROM #undef FB_LOCKED_FROM
typedef EnsureUnlock<Mutex, NotRefCounted<Mutex> > MutexEnsureUnlock; typedef EnsureUnlock<Mutex, NotRefCounted> MutexEnsureUnlock;
typedef EnsureUnlock<RefMutex> RefMutexEnsureUnlock; typedef EnsureUnlock<RefMutex> RefMutexEnsureUnlock;
} // namespace } // namespace

View File

@ -89,7 +89,7 @@ private:
}; };
typedef RaiiLockGuard<XThreadMutex> XThreadLockGuard; typedef RaiiLockGuard<XThreadMutex> XThreadLockGuard;
typedef EnsureUnlock<XThreadMutex, NotRefCounted<XThreadMutex> > XThreadEnsureUnlock; typedef EnsureUnlock<XThreadMutex, NotRefCounted> XThreadEnsureUnlock;
} }

View File

@ -320,7 +320,7 @@ typedef Mutex Spinlock;
#endif //WIN_NT #endif //WIN_NT
// RAII holder // RAII holders
template <typename M> template <typename M>
class RaiiLockGuard class RaiiLockGuard
{ {
@ -363,10 +363,12 @@ private:
typedef RaiiLockGuard<Mutex> MutexLockGuard; typedef RaiiLockGuard<Mutex> MutexLockGuard;
class MutexUnlockGuard
template <typename M>
class RaiiUnlockGuard
{ {
public: public:
explicit MutexUnlockGuard(Mutex& aLock, const char* aReason) explicit RaiiUnlockGuard(M& aLock, const char* aReason)
: lock(&aLock) : lock(&aLock)
#ifdef DEV_BUILD #ifdef DEV_BUILD
, saveReason(aReason) , saveReason(aReason)
@ -375,7 +377,7 @@ public:
lock->leave(); lock->leave();
} }
~MutexUnlockGuard() ~RaiiUnlockGuard()
{ {
try try
{ {
@ -393,15 +395,17 @@ public:
private: private:
// Forbid copying // Forbid copying
MutexUnlockGuard(const MutexUnlockGuard&); RaiiUnlockGuard(const RaiiUnlockGuard&);
MutexUnlockGuard& operator=(const MutexUnlockGuard&); RaiiUnlockGuard& operator=(const RaiiUnlockGuard&);
Mutex* lock; M* lock;
#ifdef DEV_BUILD #ifdef DEV_BUILD
const char* saveReason; const char* saveReason;
#endif #endif
}; };
typedef RaiiUnlockGuard<Mutex> MutexUnlockGuard;
class MutexCheckoutGuard class MutexCheckoutGuard
{ {

View File

@ -989,10 +989,10 @@ void Jrd::Attachment::SyncGuard::init(const char* f, bool
if (jStable) if (jStable)
{ {
jStable->getMutex()->enter(f); jStable->getSync()->enter(f);
if (!jStable->getHandle()) if (!jStable->getHandle())
{ {
jStable->getMutex()->leave(); jStable->getSync()->leave();
Arg::Gds(isc_att_shutdown).raise(); Arg::Gds(isc_att_shutdown).raise();
} }
} }
@ -1004,13 +1004,13 @@ void StableAttachmentPart::manualLock(ULONG& flags, const ULONG whatLock)
if (whatLock & ATT_async_manual_lock) if (whatLock & ATT_async_manual_lock)
{ {
asyncMutex.enter(FB_FUNCTION); async.enter(FB_FUNCTION);
flags |= ATT_async_manual_lock; flags |= ATT_async_manual_lock;
} }
if (whatLock & ATT_manual_lock) if (whatLock & ATT_manual_lock)
{ {
mainMutex.enter(FB_FUNCTION); mainSync.enter(FB_FUNCTION);
flags |= ATT_manual_lock; flags |= ATT_manual_lock;
} }
} }
@ -1020,7 +1020,7 @@ void StableAttachmentPart::manualUnlock(ULONG& flags)
if (flags & ATT_manual_lock) if (flags & ATT_manual_lock)
{ {
flags &= ~ATT_manual_lock; flags &= ~ATT_manual_lock;
mainMutex.leave(); mainSync.leave();
} }
manualAsyncUnlock(flags); manualAsyncUnlock(flags);
} }
@ -1030,7 +1030,7 @@ void StableAttachmentPart::manualAsyncUnlock(ULONG& flags)
if (flags & ATT_async_manual_lock) if (flags & ATT_async_manual_lock)
{ {
flags &= ~ATT_async_manual_lock; flags &= ~ATT_async_manual_lock;
asyncMutex.leave(); async.leave();
} }
} }
@ -1038,7 +1038,7 @@ void StableAttachmentPart::onIdleTimer(TimerImpl*)
{ {
// Ensure attachment is still alive and still idle // Ensure attachment is still alive and still idle
MutexEnsureUnlock guard(*this->getMutex(), FB_FUNCTION); EnsureUnlock<Sync, NotRefCounted> guard(*this->getSync(), FB_FUNCTION);
if (!guard.tryEnter()) if (!guard.tryEnter())
return; return;

View File

@ -203,6 +203,107 @@ private:
class StableAttachmentPart : public Firebird::RefCounted, public Firebird::GlobalStorage class StableAttachmentPart : public Firebird::RefCounted, public Firebird::GlobalStorage
{ {
public: public:
class Sync
{
public:
Sync()
: waiters(0), threadId(0), totalLocksCounter(0), currentLocksCounter(0)
{ }
void enter(const char* aReason)
{
ThreadId curTid = getThreadId();
if (threadId == curTid)
{
currentLocksCounter++;
return;
}
if (threadId || !syncMutex.tryEnter(aReason))
{
// we have contention with another thread
waiters.fetch_add(1, std::memory_order_relaxed);
syncMutex.enter(aReason);
waiters.fetch_sub(1, std::memory_order_relaxed);
}
threadId = curTid;
totalLocksCounter++;
fb_assert(currentLocksCounter == 0);
currentLocksCounter++;
}
bool tryEnter(const char* aReason)
{
ThreadId curTid = getThreadId();
if (threadId == curTid)
{
currentLocksCounter++;
return true;
}
if (threadId || !syncMutex.tryEnter(aReason))
return false;
threadId = curTid;
totalLocksCounter++;
fb_assert(currentLocksCounter == 0);
currentLocksCounter++;
return true;
}
void leave()
{
fb_assert(currentLocksCounter > 0);
if (--currentLocksCounter == 0)
{
threadId = 0;
syncMutex.leave();
}
}
bool hasContention() const
{
return (waiters.load(std::memory_order_relaxed) > 0);
}
FB_UINT64 getLockCounter() const
{
return totalLocksCounter;
}
#ifdef DEV_BUILD
bool locked() const
{
return threadId == getThreadId();
}
#endif
~Sync()
{
if (threadId == getThreadId())
{
syncMutex.leave();
}
}
private:
// copying is prohibited
Sync(const Sync&);
Sync& operator=(const Sync&);
Firebird::Mutex syncMutex;
std::atomic<int> waiters;
ThreadId threadId;
volatile FB_UINT64 totalLocksCounter;
int currentLocksCounter;
};
typedef Firebird::RaiiLockGuard<StableAttachmentPart> SyncGuard;
explicit StableAttachmentPart(Attachment* handle) explicit StableAttachmentPart(Attachment* handle)
: att(handle), jAtt(NULL), shutError(0) : att(handle), jAtt(NULL), shutError(0)
{ } { }
@ -226,13 +327,13 @@ public:
shutError = 0; shutError = 0;
} }
Firebird::Mutex* getMutex(bool useAsync = false, bool forceAsync = false) Sync* getSync(bool useAsync = false, bool forceAsync = false)
{ {
if (useAsync && !forceAsync) if (useAsync && !forceAsync)
{ {
fb_assert(!mainMutex.locked()); fb_assert(!mainSync.locked());
} }
return useAsync ? &asyncMutex : &mainMutex; return useAsync ? &async : &mainSync;
} }
Firebird::Mutex* getBlockingMutex() Firebird::Mutex* getBlockingMutex()
@ -242,8 +343,8 @@ public:
void cancel() void cancel()
{ {
fb_assert(asyncMutex.locked()); fb_assert(async.locked());
fb_assert(mainMutex.locked()); fb_assert(mainSync.locked());
att = NULL; att = NULL;
} }
@ -279,13 +380,16 @@ private:
JAttachment* jAtt; JAttachment* jAtt;
ISC_STATUS shutError; ISC_STATUS shutError;
// These mutexes guarantee attachment existence. After releasing both of them with possibly // These syncs guarantee attachment existence. After releasing both of them with possibly
// zero att_use_count one should check does attachment still exists calling getHandle(). // zero att_use_count one should check does attachment still exists calling getHandle().
Firebird::Mutex mainMutex, asyncMutex; Sync mainSync, async;
// This mutex guarantees attachment is not accessed by more than single external thread. // This mutex guarantees attachment is not accessed by more than single external thread.
Firebird::Mutex blockingMutex; Firebird::Mutex blockingMutex;
}; };
typedef Firebird::RaiiLockGuard<StableAttachmentPart::Sync> AttSyncLockGuard;
typedef Firebird::RaiiUnlockGuard<StableAttachmentPart::Sync> AttSyncUnlockGuard;
// //
// the attachment block; one is created for each attachment to a database // the attachment block; one is created for each attachment to a database
// //
@ -310,7 +414,7 @@ public:
~SyncGuard() ~SyncGuard()
{ {
if (jStable) if (jStable)
jStable->getMutex()->leave(); jStable->getSync()->leave();
} }
private: private:

View File

@ -266,6 +266,7 @@ namespace Jrd {
sync(this), sync(this),
keyName(getPool()), keyName(getPool()),
pluginName(getPool()), pluginName(getPool()),
currentPage(0),
keyProviders(getPool()), keyProviders(getPool()),
keyConsumers(getPool()), keyConsumers(getPool()),
hash(getPool()), hash(getPool()),
@ -850,7 +851,7 @@ namespace Jrd {
if (!LCK_lock(tdbb, threadLock, LCK_EX, LCK_NO_WAIT)) if (!LCK_lock(tdbb, threadLock, LCK_EX, LCK_NO_WAIT))
{ {
// Cleanup lock manager error // Cleanup lock manager error
fb_utils::init_status(tdbb->tdbb_status_vector); tdbb->tdbb_status_vector->init();
return; return;
} }
@ -915,36 +916,13 @@ namespace Jrd {
return; return;
} }
// Establish temp context // Establish temp context needed to take crypt thread lock
// Needed to take crypt thread lock ThreadContextHolder tempDbb(&dbb, nullptr, &status_vector);
UserId user;
user.setUserName("Database Crypter");
Jrd::Attachment* const attachment = Jrd::Attachment::create(&dbb, nullptr);
RefPtr<SysStableAttachment> sAtt(FB_NEW SysStableAttachment(attachment));
attachment->setStable(sAtt);
attachment->att_filename = dbb.dbb_filename;
attachment->att_user = &user;
BackgroundContextHolder tempDbb(&dbb, attachment, &status_vector, FB_FUNCTION);
LCK_init(tempDbb, LCK_OWNER_attachment);
PAG_header(tempDbb, true);
PAG_attachment_id(tempDbb);
Monitoring::publishAttachment(tempDbb);
sAtt->initDone();
// Take exclusive threadLock // Take exclusive threadLock
// If can't take that lock - nothing to do, cryptThread already runs somewhere // If can't take that lock - nothing to do, cryptThread already runs somewhere
if (!LCK_lock(tempDbb, threadLock, LCK_EX, LCK_NO_WAIT)) if (!LCK_lock(tempDbb, threadLock, LCK_EX, LCK_NO_WAIT))
{
Monitoring::cleanupAttachment(tempDbb);
attachment->releaseLocks(tempDbb);
LCK_fini(tempDbb, LCK_OWNER_attachment);
return; return;
}
try try
{ {
@ -971,7 +949,7 @@ namespace Jrd {
dbb.dbb_database_name.c_str(), writer.getBufferLength(), writer.getBuffer())); dbb.dbb_database_name.c_str(), writer.getBufferLength(), writer.getBuffer()));
check(&status_vector); check(&status_vector);
MutexLockGuard attGuard(*(jAtt->getStable()->getMutex()), FB_FUNCTION); AttSyncLockGuard attGuard(*(jAtt->getStable()->getSync()), FB_FUNCTION);
Attachment* att = jAtt->getHandle(); Attachment* att = jAtt->getHandle();
if (!att) if (!att)
Arg::Gds(isc_att_shutdown).raise(); Arg::Gds(isc_att_shutdown).raise();
@ -1073,9 +1051,6 @@ namespace Jrd {
// Release exclusive lock on StartCryptThread // Release exclusive lock on StartCryptThread
lckRelease = true; lckRelease = true;
LCK_release(tempDbb, threadLock); LCK_release(tempDbb, threadLock);
Monitoring::cleanupAttachment(tempDbb);
attachment->releaseLocks(tempDbb);
LCK_fini(tempDbb, LCK_OWNER_attachment);
} }
catch (const Exception&) catch (const Exception&)
{ {
@ -1085,9 +1060,6 @@ namespace Jrd {
{ {
// Release exclusive lock on StartCryptThread // Release exclusive lock on StartCryptThread
LCK_release(tempDbb, threadLock); LCK_release(tempDbb, threadLock);
Monitoring::cleanupAttachment(tempDbb);
attachment->releaseLocks(tempDbb);
LCK_fini(tempDbb, LCK_OWNER_attachment);
} }
} }
catch (const Exception&) catch (const Exception&)
@ -1322,9 +1294,16 @@ namespace Jrd {
return 0; return 0;
} }
ULONG CryptoManager::getCurrentPage() const ULONG CryptoManager::getCurrentPage(thread_db* tdbb) const
{ {
return process ? currentPage : 0; if (!process)
return 0;
if (currentPage)
return currentPage;
CchHdr hdr(tdbb, LCK_read);
return hdr->hdr_crypt_page;
} }
ULONG CryptoManager::getLastPage(thread_db* tdbb) ULONG CryptoManager::getLastPage(thread_db* tdbb)
@ -1332,9 +1311,19 @@ namespace Jrd {
return PAG_last_page(tdbb) + 1; return PAG_last_page(tdbb) + 1;
} }
UCHAR CryptoManager::getCurrentState() const UCHAR CryptoManager::getCurrentState(thread_db* tdbb) const
{ {
return (crypt ? fb_info_crypt_encrypted : 0) | (process ? fb_info_crypt_process : 0); bool p = process;
bool c = crypt;
if (!currentPage)
{
CchHdr hdr(tdbb, LCK_read);
p = hdr->hdr_flags & Ods::hdr_crypt_process;
c = hdr->hdr_flags & Ods::hdr_encrypted;
}
return (c ? fb_info_crypt_encrypted : 0) | (p ? fb_info_crypt_process : 0);
} }
const char* CryptoManager::getKeyName() const const char* CryptoManager::getKeyName() const

View File

@ -297,8 +297,8 @@ public:
bool checkValidation(Firebird::IDbCryptPlugin* crypt); bool checkValidation(Firebird::IDbCryptPlugin* crypt);
void setDbInfo(Firebird::IDbCryptPlugin* cp); void setDbInfo(Firebird::IDbCryptPlugin* cp);
ULONG getCurrentPage() const; ULONG getCurrentPage(thread_db* tdbb) const;
UCHAR getCurrentState() const; UCHAR getCurrentState(thread_db* tdbb) const;
const char* getKeyName() const; const char* getKeyName() const;
const char* getPluginName() const; const char* getPluginName() const;

View File

@ -901,8 +901,8 @@ void Monitoring::putDatabase(thread_db* tdbb, SnapshotData::DumpRecord& record)
// crypt thread status // crypt thread status
if (dbb->dbb_crypto_manager) if (dbb->dbb_crypto_manager)
{ {
record.storeInteger(f_mon_db_crypt_page, dbb->dbb_crypto_manager->getCurrentPage()); record.storeInteger(f_mon_db_crypt_page, dbb->dbb_crypto_manager->getCurrentPage(tdbb));
record.storeInteger(f_mon_db_crypt_state, dbb->dbb_crypto_manager->getCurrentState()); record.storeInteger(f_mon_db_crypt_state, dbb->dbb_crypto_manager->getCurrentState(tdbb));
} }
// database owner // database owner

View File

@ -2543,10 +2543,10 @@ void EngineCallbackGuard::init(thread_db* tdbb, Connection& conn, const char* fr
{ {
m_saveConnection = attachment->att_ext_connection; m_saveConnection = attachment->att_ext_connection;
m_stable = attachment->getStable(); m_stable = attachment->getStable();
m_stable->getMutex()->leave(); m_stable->getSync()->leave();
MutexLockGuard guardAsync(*m_stable->getMutex(true, true), FB_FUNCTION); Jrd::AttSyncLockGuard guardAsync(*m_stable->getSync(true, true), FB_FUNCTION);
MutexLockGuard guardMain(*m_stable->getMutex(), FB_FUNCTION); Jrd::AttSyncLockGuard guardMain(*m_stable->getSync(), FB_FUNCTION);
if (m_stable->getHandle() == attachment) if (m_stable->getHandle() == attachment)
attachment->att_ext_connection = &conn; attachment->att_ext_connection = &conn;
} }
@ -2568,13 +2568,13 @@ EngineCallbackGuard::~EngineCallbackGuard()
Jrd::Attachment* attachment = m_tdbb->getAttachment(); Jrd::Attachment* attachment = m_tdbb->getAttachment();
if (attachment && m_stable.hasData()) if (attachment && m_stable.hasData())
{ {
MutexLockGuard guardAsync(*m_stable->getMutex(true, true), FB_FUNCTION); Jrd::AttSyncLockGuard guardAsync(*m_stable->getSync(true, true), FB_FUNCTION);
m_stable->getMutex()->enter(FB_FUNCTION); m_stable->getSync()->enter(FB_FUNCTION);
if (m_stable->getHandle() == attachment) if (m_stable->getHandle() == attachment)
attachment->att_ext_connection = m_saveConnection; attachment->att_ext_connection = m_saveConnection;
else else
m_stable->getMutex()->leave(); m_stable->getSync()->leave();
} }
jrd_tra* transaction = m_tdbb->getTransaction(); jrd_tra* transaction = m_tdbb->getTransaction();

View File

@ -823,7 +823,7 @@ void INF_database_info(thread_db* tdbb,
case fb_info_crypt_state: case fb_info_crypt_state:
length = INF_convert(dbb->dbb_crypto_manager ? length = INF_convert(dbb->dbb_crypto_manager ?
dbb->dbb_crypto_manager->getCurrentState() : 0, buffer); dbb->dbb_crypto_manager->getCurrentState(tdbb) : 0, buffer);
break; break;
case fb_info_crypt_key: case fb_info_crypt_key:

View File

@ -745,7 +745,7 @@ namespace
try try
{ {
if (!nolock) if (!nolock)
sAtt->getMutex(async)->enter(from); sAtt->getSync(async)->enter(from);
Jrd::Attachment* attachment = sAtt->getHandle(); // Must be done after entering mutex Jrd::Attachment* attachment = sAtt->getHandle(); // Must be done after entering mutex
@ -776,7 +776,7 @@ namespace
catch (const Firebird::Exception&) catch (const Firebird::Exception&)
{ {
if (!nolock) if (!nolock)
sAtt->getMutex(async)->leave(); sAtt->getSync(async)->leave();
throw; throw;
} }
} }
@ -800,7 +800,7 @@ namespace
} }
if (!nolock) if (!nolock)
sAtt->getMutex(async)->leave(); sAtt->getSync(async)->leave();
if (blocking) if (blocking)
sAtt->getBlockingMutex()->leave(); sAtt->getBlockingMutex()->leave();
@ -3404,12 +3404,12 @@ void JAttachment::internalDropDatabase(CheckStatusWrapper* user_status)
try try
{ {
EngineContextHolder tdbb(user_status, this, FB_FUNCTION, AttachmentHolder::ATT_LOCK_ASYNC); EngineContextHolder tdbb(user_status, this, FB_FUNCTION, AttachmentHolder::ATT_LOCK_ASYNC);
Jrd::Attachment* attachment = getHandle(); Attachment* attachment = getHandle();
Database* const dbb = tdbb->getDatabase(); Database* const dbb = tdbb->getDatabase();
try try
{ {
MutexEnsureUnlock guard(*(getStable()->getMutex()), FB_FUNCTION); EnsureUnlock<StableAttachmentPart::Sync, NotRefCounted> guard(*(getStable()->getSync()), FB_FUNCTION);
if (!guard.tryEnter()) if (!guard.tryEnter())
{ {
status_exception::raise(Arg::Gds(isc_attachment_in_use)); status_exception::raise(Arg::Gds(isc_attachment_in_use));
@ -5031,8 +5031,8 @@ void SysStableAttachment::destroy(Attachment* attachment)
} }
// Make Attachment::destroy() happy // Make Attachment::destroy() happy
MutexLockGuard async(*getMutex(true), FB_FUNCTION); AttSyncLockGuard async(*getSync(true), FB_FUNCTION);
MutexLockGuard sync(*getMutex(), FB_FUNCTION); AttSyncLockGuard sync(*getSync(), FB_FUNCTION);
setInterface(NULL); setInterface(NULL);
Jrd::Attachment::destroy(attachment); Jrd::Attachment::destroy(attachment);
@ -8161,8 +8161,8 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
Mutex* const attMutex = sAtt->getMutex(); StableAttachmentPart::Sync* const attSync = sAtt->getSync();
fb_assert(attMutex->locked()); fb_assert(attSync->locked());
Jrd::Attachment* attachment = sAtt->getHandle(); Jrd::Attachment* attachment = sAtt->getHandle();
@ -8177,10 +8177,10 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
attachment->att_use_count--; attachment->att_use_count--;
{ // scope { // scope
MutexUnlockGuard cout(*attMutex, FB_FUNCTION); AttSyncUnlockGuard cout(*attSync, FB_FUNCTION);
// !!!!!!!!!!!!!!!!! - event? semaphore? condvar? (when ATT_purge_started / sAtt->getHandle() changes) // !!!!!!!!!!!!!!!!! - event? semaphore? condvar? (when ATT_purge_started / sAtt->getHandle() changes)
fb_assert(!attMutex->locked()); fb_assert(!attSync->locked());
Thread::yield(); Thread::yield();
Thread::sleep(1); Thread::sleep(1);
} }
@ -8204,10 +8204,10 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
attachment->att_use_count--; attachment->att_use_count--;
{ // scope { // scope
MutexUnlockGuard cout(*attMutex, FB_FUNCTION); AttSyncUnlockGuard cout(*attSync, FB_FUNCTION);
// !!!!!!!!!!!!!!!!! - event? semaphore? condvar? (when --att_use_count) // !!!!!!!!!!!!!!!!! - event? semaphore? condvar? (when --att_use_count)
fb_assert(!attMutex->locked()); fb_assert(!attSync->locked());
Thread::yield(); Thread::yield();
Thread::sleep(1); Thread::sleep(1);
} }
@ -8218,7 +8218,7 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
attachment->att_use_count++; attachment->att_use_count++;
} }
fb_assert(attMutex->locked()); fb_assert(attSync->locked());
if (!attachment) if (!attachment)
return; return;
@ -8340,13 +8340,13 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
attachment->att_trace_manager->event_detach(&conn, false); attachment->att_trace_manager->event_detach(&conn, false);
} }
fb_assert(attMutex->locked()); fb_assert(attSync->locked());
Mutex* asyncMutex = sAtt->getMutex(true, true); StableAttachmentPart::Sync* attAsync = sAtt->getSync(true, true);
MutexEnsureUnlock asyncGuard(*asyncMutex, FB_FUNCTION); EnsureUnlock<StableAttachmentPart::Sync, NotRefCounted> asyncGuard(*attAsync, FB_FUNCTION);
{ // scope - ensure correct order of taking both async and main mutexes { // scope - ensure correct order of taking both async and main mutexes
MutexUnlockGuard cout(*attMutex, FB_FUNCTION); AttSyncUnlockGuard cout(*attSync, FB_FUNCTION);
fb_assert(!attMutex->locked()); fb_assert(!attSync->locked());
asyncGuard.enter(); asyncGuard.enter();
} }
@ -8363,7 +8363,7 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
release_attachment(tdbb, attachment); release_attachment(tdbb, attachment);
asyncGuard.leave(); asyncGuard.leave();
MutexUnlockGuard cout(*attMutex, FB_FUNCTION); AttSyncUnlockGuard cout(*attSync, FB_FUNCTION);
MutexUnlockGuard coutBlocking(*sAtt->getBlockingMutex(), FB_FUNCTION); MutexUnlockGuard coutBlocking(*sAtt->getBlockingMutex(), FB_FUNCTION);
// Try to close database if there are no attachments // Try to close database if there are no attachments
@ -8645,7 +8645,7 @@ namespace
{ {
StableAttachmentPart* const sAtt = *iter; StableAttachmentPart* const sAtt = *iter;
MutexLockGuard guard(*(sAtt->getMutex(true)), FB_FUNCTION); AttSyncLockGuard guard(*(sAtt->getSync(true)), FB_FUNCTION);
Attachment* attachment = sAtt->getHandle(); Attachment* attachment = sAtt->getHandle();
if (attachment) if (attachment)
@ -8660,7 +8660,7 @@ namespace
StableAttachmentPart* const sAtt = *iter; StableAttachmentPart* const sAtt = *iter;
MutexLockGuard guardBlocking(*(sAtt->getBlockingMutex()), FB_FUNCTION); MutexLockGuard guardBlocking(*(sAtt->getBlockingMutex()), FB_FUNCTION);
MutexLockGuard guard(*(sAtt->getMutex()), FB_FUNCTION); AttSyncLockGuard guard(*(sAtt->getSync()), FB_FUNCTION);
Attachment* attachment = sAtt->getHandle(); Attachment* attachment = sAtt->getHandle();
if (attachment) if (attachment)
@ -9079,9 +9079,18 @@ void thread_db::reschedule()
checkCancelState(); checkCancelState();
{ // checkout scope StableAttachmentPart::Sync* sync = this->getAttachment()->getStable()->getSync();
Database* dbb = this->getDatabase();
if (sync->hasContention())
{
FB_UINT64 cnt = sync->getLockCounter();
EngineCheckout cout(this, FB_FUNCTION); EngineCheckout cout(this, FB_FUNCTION);
Thread::yield(); Thread::yield();
while (sync->hasContention() && (sync->getLockCounter() == cnt))
Thread::sleep(1);
} }
checkCancelState(); checkCancelState();

View File

@ -1089,7 +1089,7 @@ namespace Jrd {
fb_assert(optional || m_ref.hasData()); fb_assert(optional || m_ref.hasData());
if (m_ref.hasData()) if (m_ref.hasData())
m_ref->getMutex()->leave(); m_ref->getSync()->leave();
} }
EngineCheckout(Attachment* att, const char* from) EngineCheckout(Attachment* att, const char* from)
@ -1100,14 +1100,14 @@ namespace Jrd {
if (att && att->att_use_count) if (att && att->att_use_count)
{ {
m_ref = att->getStable(); m_ref = att->getStable();
m_ref->getMutex()->leave(); m_ref->getSync()->leave();
} }
} }
~EngineCheckout() ~EngineCheckout()
{ {
if (m_ref.hasData()) if (m_ref.hasData())
m_ref->getMutex()->enter(m_from); m_ref->getSync()->enter(m_from);
// If we were signalled to cancel/shutdown, react as soon as possible. // If we were signalled to cancel/shutdown, react as soon as possible.
// We cannot throw immediately, but we can reschedule ourselves. // We cannot throw immediately, but we can reschedule ourselves.

View File

@ -469,7 +469,6 @@ static bool notify_shutdown(thread_db* tdbb, SSHORT flag, SSHORT delay, Sync* gu
* *
**************************************/ **************************************/
Database* const dbb = tdbb->getDatabase(); Database* const dbb = tdbb->getDatabase();
StableAttachmentPart* const sAtt = tdbb->getAttachment()->getStable();
shutdown_data data; shutdown_data data;
data.data_items.flag = flag; data.data_items.flag = flag;
@ -479,7 +478,7 @@ static bool notify_shutdown(thread_db* tdbb, SSHORT flag, SSHORT delay, Sync* gu
{ // scope { // scope
// Checkout before calling AST function // Checkout before calling AST function
MutexUnlockGuard uguard(*(sAtt->getMutex()), FB_FUNCTION); EngineCheckout uguard(tdbb, FB_FUNCTION);
// Notify local attachments // Notify local attachments
SHUT_blocking_ast(tdbb, true); SHUT_blocking_ast(tdbb, true);