From 0c02c039e47352c3f30b94d379012462cbe2e5a3 Mon Sep 17 00:00:00 2001 From: hvlad Date: Fri, 14 May 2021 20:43:50 +0300 Subject: [PATCH] Fixed bug #6802 : When the statement timeout is set, it causes the lock manager to delay reporting deadlocks until timeout is expired --- src/jrd/jrd.cpp | 20 +++++++++++++++++++- src/jrd/jrd.h | 4 ++++ src/jrd/lck.cpp | 37 ------------------------------------- src/lock/lock.cpp | 4 ++-- 4 files changed, 25 insertions(+), 40 deletions(-) diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 15bea43d9c..d696160ae2 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -8657,7 +8657,7 @@ bool TimeoutTimer::expired() const return false; const SINT64 t = currTime(); - return t > m_start + m_value; + return t >= m_start + m_value; } unsigned int TimeoutTimer::timeToExpire() const @@ -8838,6 +8838,24 @@ void thread_db::reschedule() tdbb_quantum = (tdbb_flags & TDBB_sweeper) ? SWEEP_QUANTUM : QUANTUM; } +SLONG thread_db::adjustWait(SLONG wait) const +{ + if ((wait == 0) || (tdbb_flags & TDBB_wait_cancel_disable) || !tdbb_reqTimer) + return wait; + + const unsigned int tout = tdbb_reqTimer->timeToExpire(); + SLONG t; + if (tout < MAX_SSHORT * 1000) + t = (tout + 999) / 1000; + else + t = MAX_SSHORT; + + if (wait > t) + return t; + + return wait; +} + // end thread_db methods diff --git a/src/jrd/jrd.h b/src/jrd/jrd.h index ff8ad7c268..dd1361ad4d 100644 --- a/src/jrd/jrd.h +++ b/src/jrd/jrd.h @@ -655,6 +655,10 @@ public: return tdbb_reqTimer; } + // Returns minimum of passed wait timeout and time to expiration of reqTimer. + // Timer value is rounded to the upper whole second. + SLONG adjustWait(SLONG wait) const; + void registerBdb(BufferDesc* bdb) { if (tdbb_bdbs.isEmpty()) { diff --git a/src/jrd/lck.cpp b/src/jrd/lck.cpp index 380d40fd45..0647bc4139 100644 --- a/src/jrd/lck.cpp +++ b/src/jrd/lck.cpp @@ -56,7 +56,6 @@ using namespace Jrd; using namespace Firebird; -static SSHORT adjust_wait(thread_db* tdbb, SSHORT wait); static void bug_lck(const TEXT*); static bool compatible(const Lock*, const Lock*, USHORT); static void enqueue(thread_db*, CheckStatusWrapper*, Lock*, USHORT, SSHORT); @@ -344,7 +343,6 @@ bool LCK_convert(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait) WaitCancelGuard guard(tdbb, lock, wait); FbLocalStatus statusVector; - wait = adjust_wait(tdbb, wait); const bool result = CONVERT(tdbb, &statusVector, lock, level, wait); if (!result) @@ -672,7 +670,6 @@ bool LCK_lock(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait) WaitCancelGuard guard(tdbb, lock, wait); FbLocalStatus statusVector; - wait = adjust_wait(tdbb, wait); ENQUEUE(tdbb, &statusVector, lock, level, wait); fb_assert(LCK_CHECK_LOCK(lock)); @@ -872,40 +869,6 @@ void LCK_write_data(thread_db* tdbb, Lock* lock, LOCK_DATA_T data) } -static SSHORT adjust_wait(thread_db* tdbb, SSHORT wait) -{ -/************************************** - * - * a d j u s t _ w a i t - * - ************************************** - * - * Functional description - * If wait is cancellable and if statement timer was started - calc new wait - * time to ensure it will not take longer than rest of timeout. - * - **************************************/ - if ((wait == LCK_NO_WAIT) || (tdbb->tdbb_flags & TDBB_wait_cancel_disable) || !tdbb->getTimeoutTimer()) - return wait; - - unsigned int tout = tdbb->getTimeoutTimer()->timeToExpire(); - if (tout > 0) - { - SSHORT t; - if (tout < 1000) - t = 1; - else if (tout < MAX_SSHORT * 1000) - t = (tout + 999) / 1000; - else - t = MAX_SSHORT; - - if ((wait == LCK_WAIT) || (-wait > t)) - return -t; - } - return wait; -} - - static void bug_lck(const TEXT* string) { /************************************** diff --git a/src/lock/lock.cpp b/src/lock/lock.cpp index dd0a56016b..cd4d1def60 100644 --- a/src/lock/lock.cpp +++ b/src/lock/lock.cpp @@ -3765,7 +3765,7 @@ void LockManager::wait_for_request(thread_db* tdbb, lrq* request, SSHORT lck_wai // out the time when the lock request will timeout const time_t lock_timeout = (lck_wait < 0) ? current_time + (-lck_wait) : 0; - time_t deadlock_timeout = current_time + scan_interval; + time_t deadlock_timeout = current_time + tdbb->adjustWait(scan_interval); // Wait in a loop until the lock becomes available @@ -3890,7 +3890,7 @@ void LockManager::wait_for_request(thread_db* tdbb, lrq* request, SSHORT lck_wai // We're going to do some real work - reset when we next want to // do a deadlock scan - deadlock_timeout = current_time + scan_interval; + deadlock_timeout = current_time + tdbb->adjustWait(scan_interval); // Handle lock event first if (ret == FB_SUCCESS)