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

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

This commit is contained in:
AlexPeshkoff 2021-10-11 20:06:18 +03:00
parent 12be4beed7
commit 9ed56eff6c
11 changed files with 181 additions and 62 deletions

View File

@ -210,7 +210,10 @@ void Thread::kill(Handle& thread)
ThreadId Thread::getId()
{
#ifdef USE_LWP_AS_THREAD_ID
return syscall(SYS_gettid);
static __thread int tid = 0;
if (!tid)
tid = syscall(SYS_gettid);
return tid;
#else
return pthread_self();
#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
{
public:
@ -114,14 +114,14 @@ namespace Firebird
#define FB_LOCKED_FROM NULL
#endif
{
RefCounted::addRef(m_mutex);
RefCounted<Mtx>::addRef(m_mutex);
}
~EnsureUnlock()
{
while (m_locked)
leave();
RefCounted::release(m_mutex);
RefCounted<Mtx>::release(m_mutex);
}
void enter()
@ -155,7 +155,7 @@ namespace Firebird
};
#undef FB_LOCKED_FROM
typedef EnsureUnlock<Mutex, NotRefCounted<Mutex> > MutexEnsureUnlock;
typedef EnsureUnlock<Mutex, NotRefCounted> MutexEnsureUnlock;
typedef EnsureUnlock<RefMutex> RefMutexEnsureUnlock;
} // namespace

View File

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

View File

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

View File

@ -203,6 +203,107 @@ private:
class StableAttachmentPart : public Firebird::RefCounted, public Firebird::GlobalStorage
{
public:
class Sync
{
public:
Sync()
: waiters(0), threadId(0), totalLocksCounter(0), currentLocksCounter(0)
{ }
void enter(const char* aReason)
{
int 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)
{
int 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)
: att(handle), jAtt(NULL), shutError(0)
{ }
@ -226,13 +327,13 @@ public:
shutError = 0;
}
Firebird::Mutex* getMutex(bool useAsync = false, bool forceAsync = false)
Sync* getSync(bool useAsync = false, bool forceAsync = false)
{
if (useAsync && !forceAsync)
{
fb_assert(!mainMutex.locked());
fb_assert(!mainSync.locked());
}
return useAsync ? &asyncMutex : &mainMutex;
return useAsync ? &async : &mainSync;
}
Firebird::Mutex* getBlockingMutex()
@ -242,8 +343,8 @@ public:
void cancel()
{
fb_assert(asyncMutex.locked());
fb_assert(mainMutex.locked());
fb_assert(async.locked());
fb_assert(mainSync.locked());
att = NULL;
}
@ -279,13 +380,16 @@ private:
JAttachment* jAtt;
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().
Firebird::Mutex mainMutex, asyncMutex;
Sync mainSync, async;
// This mutex guarantees attachment is not accessed by more than single external thread.
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
//
@ -310,7 +414,7 @@ public:
~SyncGuard()
{
if (jStable)
jStable->getMutex()->leave();
jStable->getSync()->leave();
}
private:

View File

@ -970,7 +970,7 @@ namespace Jrd {
dbb.dbb_database_name.c_str(), writer.getBufferLength(), writer.getBuffer()));
check(&status_vector);
MutexLockGuard attGuard(*(jAtt->getStable()->getMutex()), FB_FUNCTION);
AttSyncLockGuard attGuard(*(jAtt->getStable()->getSync()), FB_FUNCTION);
Attachment* att = jAtt->getHandle();
if (!att)
Arg::Gds(isc_att_shutdown).raise();

View File

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

View File

@ -733,7 +733,7 @@ namespace
try
{
if (!nolock)
sAtt->getMutex(async)->enter(from);
sAtt->getSync(async)->enter(from);
Jrd::Attachment* attachment = sAtt->getHandle(); // Must be done after entering mutex
@ -764,7 +764,7 @@ namespace
catch (const Firebird::Exception&)
{
if (!nolock)
sAtt->getMutex(async)->leave();
sAtt->getSync(async)->leave();
throw;
}
}
@ -788,7 +788,7 @@ namespace
}
if (!nolock)
sAtt->getMutex(async)->leave();
sAtt->getSync(async)->leave();
if (blocking)
sAtt->getBlockingMutex()->leave();
@ -3373,12 +3373,12 @@ void JAttachment::deprecatedDropDatabase(CheckStatusWrapper* user_status)
try
{
EngineContextHolder tdbb(user_status, this, FB_FUNCTION, AttachmentHolder::ATT_LOCK_ASYNC);
Jrd::Attachment* attachment = getHandle();
Attachment* attachment = getHandle();
Database* const dbb = tdbb->getDatabase();
try
{
MutexEnsureUnlock guard(*(getStable()->getMutex()), FB_FUNCTION);
EnsureUnlock<StableAttachmentPart::Sync, NotRefCounted> guard(*(getStable()->getSync()), FB_FUNCTION);
if (!guard.tryEnter())
{
status_exception::raise(Arg::Gds(isc_attachment_in_use));
@ -4975,8 +4975,8 @@ void SysStableAttachment::destroy(Attachment* attachment)
}
// Make Attachment::destroy() happy
MutexLockGuard async(*getMutex(true), FB_FUNCTION);
MutexLockGuard sync(*getMutex(), FB_FUNCTION);
AttSyncLockGuard async(*getSync(true), FB_FUNCTION);
AttSyncLockGuard sync(*getSync(), FB_FUNCTION);
setInterface(NULL);
Jrd::Attachment::destroy(attachment);
@ -8095,8 +8095,8 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
**************************************/
SET_TDBB(tdbb);
Mutex* const attMutex = sAtt->getMutex();
fb_assert(attMutex->locked());
StableAttachmentPart::Sync* const attSync = sAtt->getSync();
fb_assert(attSync->locked());
Jrd::Attachment* attachment = sAtt->getHandle();
@ -8111,10 +8111,10 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
attachment->att_use_count--;
{ // scope
MutexUnlockGuard cout(*attMutex, FB_FUNCTION);
AttSyncUnlockGuard cout(*attSync, FB_FUNCTION);
// !!!!!!!!!!!!!!!!! - event? semaphore? condvar? (when ATT_purge_started / sAtt->getHandle() changes)
fb_assert(!attMutex->locked());
fb_assert(!attSync->locked());
Thread::yield();
Thread::sleep(1);
}
@ -8138,10 +8138,10 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
attachment->att_use_count--;
{ // scope
MutexUnlockGuard cout(*attMutex, FB_FUNCTION);
AttSyncUnlockGuard cout(*attSync, FB_FUNCTION);
// !!!!!!!!!!!!!!!!! - event? semaphore? condvar? (when --att_use_count)
fb_assert(!attMutex->locked());
fb_assert(!attSync->locked());
Thread::yield();
Thread::sleep(1);
}
@ -8152,7 +8152,7 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
attachment->att_use_count++;
}
fb_assert(attMutex->locked());
fb_assert(attSync->locked());
if (!attachment)
return;
@ -8257,13 +8257,13 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
attachment->att_trace_manager->event_detach(&conn, false);
}
fb_assert(attMutex->locked());
Mutex* asyncMutex = sAtt->getMutex(true, true);
MutexEnsureUnlock asyncGuard(*asyncMutex, FB_FUNCTION);
fb_assert(attSync->locked());
StableAttachmentPart::Sync* attAsync = sAtt->getSync(true, true);
EnsureUnlock<StableAttachmentPart::Sync, NotRefCounted> asyncGuard(*attAsync, FB_FUNCTION);
{ // scope - ensure correct order of taking both async and main mutexes
MutexUnlockGuard cout(*attMutex, FB_FUNCTION);
fb_assert(!attMutex->locked());
AttSyncUnlockGuard cout(*attSync, FB_FUNCTION);
fb_assert(!attSync->locked());
asyncGuard.enter();
}
@ -8280,7 +8280,7 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
release_attachment(tdbb, attachment);
asyncGuard.leave();
MutexUnlockGuard cout(*attMutex, FB_FUNCTION);
AttSyncUnlockGuard cout(*attSync, FB_FUNCTION);
MutexUnlockGuard coutBlocking(*sAtt->getBlockingMutex(), FB_FUNCTION);
// Try to close database if there are no attachments
@ -8560,7 +8560,7 @@ namespace
{
StableAttachmentPart* const sAtt = *iter;
MutexLockGuard guard(*(sAtt->getMutex(true)), FB_FUNCTION);
AttSyncLockGuard guard(*(sAtt->getSync(true)), FB_FUNCTION);
Attachment* attachment = sAtt->getHandle();
if (attachment)
@ -8575,7 +8575,7 @@ namespace
StableAttachmentPart* const sAtt = *iter;
MutexLockGuard guardBlocking(*(sAtt->getBlockingMutex()), FB_FUNCTION);
MutexLockGuard guard(*(sAtt->getMutex()), FB_FUNCTION);
AttSyncLockGuard guard(*(sAtt->getSync()), FB_FUNCTION);
Attachment* attachment = sAtt->getHandle();
if (attachment)
@ -8993,9 +8993,18 @@ void thread_db::reschedule()
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);
Thread::yield();
while (sync->hasContention() && (sync->getLockCounter() == cnt))
Thread::sleep(1);
}
checkCancelState();

View File

@ -1089,13 +1089,13 @@ namespace Jrd {
fb_assert(optional || m_ref.hasData());
if (m_ref.hasData())
m_ref->getMutex()->leave();
m_ref->getSync()->leave();
}
~EngineCheckout()
{
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.
// We cannot throw immediately, but we can reschedule ourselves.

View File

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