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

Backported CORE-5197: Segfault when process exits with active sweep thread

This commit is contained in:
AlexPeshkoff 2020-12-09 17:18:53 +03:00
parent dacef52463
commit b5ade14767
10 changed files with 395 additions and 188 deletions

View File

@ -0,0 +1,96 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Alexander Peshkoff
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2020 Alexander Peshkoff <peshkoff@mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
#ifndef COMMON_X_THREAD_MUTEX_H
#define COMMON_X_THREAD_MUTEX_H
#include "../common/classes/Reasons.h"
#include "../common/classes/RefMutex.h"
#include "../common/classes/semaphore.h"
namespace Firebird
{
// Non-recursive mutex that may be unlocked by any thread
// Based on semaphore
class XThreadMutex : private Semaphore, private Reasons
{
public:
XThreadMutex()
{
Semaphore::release();
#ifdef DEV_BUILD
locked = false;
#endif
}
~XThreadMutex()
{
fb_assert(!locked);
}
void enter(const char* aReason)
{
Semaphore::enter();
fb_assert(!locked);
#ifdef DEV_BUILD
locked = true;
#endif
reason(aReason);
}
bool tryEnter(const char* aReason)
{
const bool ret = Semaphore::tryEnter();
if (ret)
{
fb_assert(!locked);
#ifdef DEV_BUILD
locked = true;
#endif
reason(aReason);
}
return ret;
}
void leave()
{
fb_assert(locked);
#ifdef DEV_BUILD
locked = false;
#endif
Semaphore::release();
}
private:
#ifdef DEV_BUILD
bool locked;
#endif
};
typedef RaiiLockGuard<XThreadMutex> XThreadLockGuard;
typedef EnsureUnlock<XThreadMutex, NotRefCounted<XThreadMutex> > XThreadEnsureUnlock;
}
#endif // COMMON_X_THREAD_MUTEX_H

View File

@ -337,16 +337,17 @@ typedef Mutex Spinlock;
// RAII holder
class MutexLockGuard
template <typename M>
class RaiiLockGuard
{
public:
MutexLockGuard(Mutex& aLock, const char* aReason)
RaiiLockGuard(M& aLock, const char* aReason)
: lock(&aLock)
{
lock->enter(aReason);
}
~MutexLockGuard()
~RaiiLockGuard()
{
try
{
@ -360,12 +361,14 @@ public:
private:
// Forbid copying
MutexLockGuard(const MutexLockGuard&);
MutexLockGuard& operator=(const MutexLockGuard&);
RaiiLockGuard(const RaiiLockGuard&);
RaiiLockGuard& operator=(const RaiiLockGuard&);
Mutex* lock;
M* lock;
};
typedef RaiiLockGuard<Mutex> MutexLockGuard;
class MutexUnlockGuard
{
public:

View File

@ -419,7 +419,7 @@ const ULONG ATT_creator = 0x08000L; // This attachment created the DB
const ULONG ATT_monitor_done = 0x10000L; // Monitoring data is refreshed
const ULONG ATT_security_db = 0x20000L; // Attachment used for security purposes
const ULONG ATT_mapping = 0x40000L; // Attachment used for mapping auth block
const ULONG ATT_crypt_thread = 0x80000L; // Attachment from crypt thread
const ULONG ATT_from_thread = 0x80000L; // Attachment from internal special thread (sweep, crypt)
const ULONG ATT_monitor_init = 0x100000L; // Attachment is registered in monitoring
const ULONG ATT_NO_CLEANUP = (ATT_no_cleanup | ATT_notify_gc);

View File

@ -286,7 +286,7 @@ namespace Jrd {
slowIO(0),
crypt(false),
process(false),
down(false),
flDown(false),
run(false)
{
stateLock = FB_NEW_RPT(getPool(), 0)
@ -825,7 +825,7 @@ namespace Jrd {
void CryptoManager::terminateCryptThread(thread_db*, bool wait)
{
down = true;
flDown = true;
if (wait && cryptThreadId)
{
Thread::waitForCompletion(cryptThreadId);
@ -962,114 +962,114 @@ namespace Jrd {
writer.insertByte(isc_dpb_no_db_triggers, TRUE);
// Avoid races with release_attachment() in jrd.cpp
MutexEnsureUnlock releaseGuard(cryptAttMutex, FB_FUNCTION);
XThreadEnsureUnlock releaseGuard(dbb.dbb_thread_mutex, FB_FUNCTION);
releaseGuard.enter();
if (!down)
if (!down())
{
AutoPlugin<JProvider> jInstance(JProvider::getInstance());
jInstance->setDbCryptCallback(&status_vector, dbb.dbb_callback);
check(&status_vector);
AutoPlugin<JProvider> jInstance(JProvider::getInstance());
jInstance->setDbCryptCallback(&status_vector, dbb.dbb_callback);
check(&status_vector);
RefPtr<JAttachment> jAtt(REF_NO_INCR, jInstance->attachDatabase(&status_vector,
dbb.dbb_database_name.c_str(), writer.getBufferLength(), writer.getBuffer()));
check(&status_vector);
RefPtr<JAttachment> jAtt(REF_NO_INCR, jInstance->attachDatabase(&status_vector,
dbb.dbb_database_name.c_str(), writer.getBufferLength(), writer.getBuffer()));
check(&status_vector);
MutexLockGuard attGuard(*(jAtt->getStable()->getMutex()), FB_FUNCTION);
Attachment* att = jAtt->getHandle();
if (!att)
Arg::Gds(isc_att_shutdown).raise();
att->att_flags |= ATT_crypt_thread;
releaseGuard.leave();
MutexLockGuard attGuard(*(jAtt->getStable()->getMutex()), FB_FUNCTION);
Attachment* att = jAtt->getHandle();
if (!att)
Arg::Gds(isc_att_shutdown).raise();
att->att_flags |= ATT_from_thread;
releaseGuard.leave();
ThreadContextHolder tdbb(att->att_database, att, &status_vector);
tdbb->markAsSweeper();
ThreadContextHolder tdbb(att->att_database, att, &status_vector);
tdbb->markAsSweeper();
DatabaseContextHolder dbHolder(tdbb);
DatabaseContextHolder dbHolder(tdbb);
class UseCountHolder
{
public:
explicit UseCountHolder(Attachment* a)
: att(a)
class UseCountHolder
{
att->att_use_count++;
}
~UseCountHolder()
{
att->att_use_count--;
}
private:
Attachment* att;
};
UseCountHolder use_count(att);
public:
explicit UseCountHolder(Attachment* a)
: att(a)
{
att->att_use_count++;
}
~UseCountHolder()
{
att->att_use_count--;
}
private:
Attachment* att;
};
UseCountHolder use_count(att);
// get ready...
AutoSetRestore<Attachment*> attSet(&cryptAtt, att);
ULONG lastPage = getLastPage(tdbb);
// get ready...
AutoSetRestore<Attachment*> attSet(&cryptAtt, att);
ULONG lastPage = getLastPage(tdbb);
do
{
// Check is there some job to do
while (currentPage < lastPage)
do
{
// Check is there some job to do
while (currentPage < lastPage)
{
// forced terminate
if (down())
{
break;
}
// scheduling
if (--tdbb->tdbb_quantum < 0)
JRD_reschedule(tdbb, true);
// nbackup state check
BackupManager::StateReadGuard::lock(tdbb, 1);
int bak_state = tdbb->getDatabase()->dbb_backup_manager->getState();
BackupManager::StateReadGuard::unlock(tdbb);
if (bak_state != Ods::hdr_nbak_normal)
{
EngineCheckout checkout(tdbb, FB_FUNCTION);
Thread::sleep(10);
continue;
}
// writing page to disk will change it's crypt status in usual way
WIN window(DB_PAGE_SPACE, currentPage);
Ods::pag* page = CCH_FETCH(tdbb, &window, LCK_write, pag_undefined);
if (page && page->pag_type <= pag_max &&
(bool(page->pag_flags & Ods::crypted_page) != crypt) &&
Ods::pag_crypt_page[page->pag_type])
{
CCH_MARK_MUST_WRITE(tdbb, &window);
}
CCH_RELEASE_TAIL(tdbb, &window);
// sometimes save currentPage into DB header
++currentPage;
if ((currentPage & 0x3FF) == 0)
{
writeDbHeader(tdbb, currentPage);
}
}
// forced terminate
if (down)
if (down())
{
break;
}
// scheduling
if (--tdbb->tdbb_quantum < 0)
JRD_reschedule(tdbb, true);
// At this moment of time all pages with number < lastpage
// are guaranteed to change crypt state. Check for added pages.
lastPage = getLastPage(tdbb);
// nbackup state check
BackupManager::StateReadGuard::lock(tdbb, 1);
int bak_state = tdbb->getDatabase()->dbb_backup_manager->getState();
BackupManager::StateReadGuard::unlock(tdbb);
} while (currentPage < lastPage);
if (bak_state != Ods::hdr_nbak_normal)
{
EngineCheckout checkout(tdbb, FB_FUNCTION);
Thread::sleep(10);
continue;
}
// writing page to disk will change it's crypt status in usual way
WIN window(DB_PAGE_SPACE, currentPage);
Ods::pag* page = CCH_FETCH(tdbb, &window, LCK_write, pag_undefined);
if (page && page->pag_type <= pag_max &&
(bool(page->pag_flags & Ods::crypted_page) != crypt) &&
Ods::pag_crypt_page[page->pag_type])
{
CCH_MARK_MUST_WRITE(tdbb, &window);
}
CCH_RELEASE_TAIL(tdbb, &window);
// sometimes save currentPage into DB header
++currentPage;
if ((currentPage & 0x3FF) == 0)
{
writeDbHeader(tdbb, currentPage);
}
}
// forced terminate
if (down)
// Finalize crypt
if (!down())
{
break;
writeDbHeader(tdbb, 0);
}
// At this moment of time all pages with number < lastpage
// are guaranteed to change crypt state. Check for added pages.
lastPage = getLastPage(tdbb);
} while (currentPage < lastPage);
// Finalize crypt
if (!down)
{
writeDbHeader(tdbb, 0);
}
}
// Release exclusive lock on StartCryptThread
@ -1344,6 +1344,11 @@ namespace Jrd {
return keyName.c_str();
}
bool CryptoManager::down() const
{
return flDown || (dbb.dbb_flags & DBB_closing);
}
void CryptoManager::addClumplet(string& signature, ClumpletReader& block, UCHAR tag)
{
if (block.find(tag))

View File

@ -42,8 +42,6 @@
#include "../jrd/status.h"
#include "firebird/Interface.h"
#define CRYPT_DEBUG(A)
// forward
class Config;
@ -419,10 +417,9 @@ private:
// normal operation.
SINT64 slowIO;
bool crypt, process, down, run;
bool crypt, process, flDown, run;
public:
Firebird::Mutex cryptAttMutex;
bool down() const;
};
} // namespace Jrd

View File

@ -128,10 +128,21 @@ namespace Jrd
Database* dbb = static_cast<Database*>(ast_object);
AsyncContextHolder tdbb(dbb, FB_FUNCTION);
if ((dbb->dbb_flags & DBB_sweep_starting) && !(dbb->dbb_flags & DBB_sweep_in_progress))
while (true)
{
dbb->dbb_flags &= ~DBB_sweep_starting;
LCK_release(tdbb, dbb->dbb_sweep_lock);
AtomicCounter::counter_type old = dbb->dbb_flags;
if ((old & DBB_sweep_in_progress) || !(old & DBB_sweep_starting))
{
SPTHR_DEBUG(fprintf(stderr, "blocking_ast_sweep %p false wrong flags %lx\n", dbb, old));
break;
}
if (dbb->dbb_flags.compareExchange(old, old & ~DBB_sweep_starting))
{
SPTHR_DEBUG(fprintf(stderr, "blocking_ast_sweep true %p\n", dbb));
dbb->dbb_thread_mutex.leave();
break;
}
}
}
catch (const Exception&)
@ -153,6 +164,7 @@ namespace Jrd
bool Database::allowSweepThread(thread_db* tdbb)
{
SPTHR_DEBUG(fprintf(stderr, "allowSweepThread %p\n", this));
if (readOnly())
return false;
@ -160,32 +172,74 @@ namespace Jrd
if (attachment->att_flags & ATT_no_cleanup)
return false;
if (!dbb_thread_mutex.tryEnter(FB_FUNCTION))
{
SPTHR_DEBUG(fprintf(stderr, "allowSweepThread %p false, dbb_thread_mutex busy\n", this));
return false;
}
if (dbb_flags & DBB_closing)
{
SPTHR_DEBUG(fprintf(stderr, "allowSweepThread false, dbb closing\n"));
dbb_thread_mutex.leave();
return false;
}
while (true)
{
AtomicCounter::counter_type old = dbb_flags;
if ((old & (DBB_sweep_in_progress | DBB_sweep_starting)) || (dbb_ast_flags & DBB_shutdown))
{
dbb_thread_mutex.leave();
return false;
}
if (dbb_flags.compareExchange(old, old | DBB_sweep_starting))
break;
}
SPTHR_DEBUG(fprintf(stderr, "allowSweepThread - set DBB_sweep_starting\n"));
createSweepLock(tdbb);
if (!LCK_lock(tdbb, dbb_sweep_lock, LCK_EX, LCK_NO_WAIT))
{
// clear lock error from status vector
fb_utils::init_status(tdbb->tdbb_status_vector);
dbb_flags &= ~DBB_sweep_starting;
clearSweepStarting();
SPTHR_DEBUG(fprintf(stderr, "allowSweepThread - !LCK_lock\n"));
return false;
}
SPTHR_DEBUG(fprintf(stderr, "allowSweepThread - TRUE\n"));
return true;
}
bool Database::clearSweepStarting()
{
while (true)
{
AtomicCounter::counter_type old = dbb_flags;
if (!(old & DBB_sweep_starting))
{
SPTHR_DEBUG(fprintf(stderr, "clearSweepStarting false %p\n", this));
return false;
}
if (dbb_flags.compareExchange(old, old & ~DBB_sweep_starting))
{
SPTHR_DEBUG(fprintf(stderr, "clearSweepStarting true %p\n", this));
dbb_thread_mutex.leave();
return true;
}
}
}
bool Database::allowSweepRun(thread_db* tdbb)
{
if (readOnly())
SPTHR_DEBUG(fprintf(stderr, "allowSweepRun %p\n", this));
if (readOnly() || (dbb_flags & DBB_closing))
return false;
Jrd::Attachment* const attachment = tdbb->getAttachment();
@ -196,14 +250,21 @@ namespace Jrd
{
AtomicCounter::counter_type old = dbb_flags;
if (old & DBB_sweep_in_progress)
{
clearSweepStarting();
return false;
}
if (dbb_flags.compareExchange(old, old | DBB_sweep_in_progress))
break;
}
SPTHR_DEBUG(fprintf(stderr, "allowSweepRun - set DBB_sweep_in_progress\n"));
if (!(dbb_flags & DBB_sweep_starting))
{
SPTHR_DEBUG(fprintf(stderr, "allowSweepRun - createSweepLock\n"));
createSweepLock(tdbb);
if (!LCK_lock(tdbb, dbb_sweep_lock, LCK_EX, -1))
{
@ -215,20 +276,24 @@ namespace Jrd
}
}
else
dbb_flags &= ~DBB_sweep_starting;
{
SPTHR_DEBUG(fprintf(stderr, "allowSweepRun - clearSweepStarting\n"));
attachment->att_flags |= ATT_from_thread;
clearSweepStarting();
}
return true;
}
void Database::clearSweepFlags(thread_db* tdbb)
{
if (!(dbb_flags & (DBB_sweep_starting | DBB_sweep_in_progress)))
if (!(dbb_flags & DBB_sweep_in_progress))
return;
if (dbb_sweep_lock)
LCK_release(tdbb, dbb_sweep_lock);
dbb_flags &= ~(DBB_sweep_in_progress | DBB_sweep_starting);
dbb_flags &= ~DBB_sweep_in_progress;
}
void Database::registerModule(Module& module)

View File

@ -52,6 +52,7 @@
#include "../common/classes/GenericMap.h"
#include "../common/classes/RefCounted.h"
#include "../common/classes/semaphore.h"
#include "../common/classes/XThreadMutex.h"
#include "../common/classes/DbImplementation.h"
#include "../common/utils_proto.h"
#include "../jrd/RandomGenerator.h"
@ -68,6 +69,10 @@
#include "../common/classes/Synchronize.h"
#include "fb_types.h"
#define SPTHR_DEBUG(A)
namespace Jrd
{
template <typename T> class vec;
@ -219,6 +224,7 @@ const ULONG DBB_no_fs_cache = 0x40000L; // Not using file system cache
const ULONG DBB_sweep_starting = 0x80000L; // Auto-sweep is starting
const ULONG DBB_creating = 0x100000L; // Database creation is in progress
const ULONG DBB_shared = 0x200000L; // Database object is shared among connections
const ULONG DBB_closing = 0x400000L; // Database closing, special backgroud threads should exit
//
// dbb_ast_flags
@ -467,6 +473,8 @@ public:
SharedCounter dbb_shared_counter;
CryptoManager* dbb_crypto_manager;
Firebird::RefPtr<ExistenceRefMutex> dbb_init_fini;
Firebird::XThreadMutex dbb_thread_mutex; // special threads start/stop mutex
Thread::Handle dbb_sweep_thread;
Firebird::RefPtr<Linger> dbb_linger_timer;
unsigned dbb_linger_seconds;
time_t dbb_linger_end;
@ -522,6 +530,7 @@ private:
dbb_external_file_directory_list(NULL),
dbb_shared_counter(shared),
dbb_init_fini(FB_NEW_POOL(*getDefaultMemoryPool()) ExistenceRefMutex()),
dbb_sweep_thread(0),
dbb_linger_seconds(0),
dbb_linger_end(0),
dbb_plugin_config(pConf)
@ -561,8 +570,10 @@ public:
bool allowSweepThread(thread_db* tdbb);
// returns true if sweep could run
bool allowSweepRun(thread_db* tdbb);
// reset sweep flags and release sweep lock
// reset sweep flag and release sweep lock
void clearSweepFlags(thread_db* tdbb);
// reset sweep starting flag, release thread starting mutex
bool clearSweepStarting();
static void garbage_collector(Database* dbb);
void exceptionHandler(const Firebird::Exception& ex, ThreadFinishSync<Database*>::ThreadRoutine* routine);

View File

@ -6451,54 +6451,67 @@ static void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
attachment->mergeStats();
// avoid races with crypt thread
Mutex dummyMutex;
MutexEnsureUnlock cryptGuard(dbb->dbb_crypto_manager ? dbb->dbb_crypto_manager->cryptAttMutex :
dummyMutex, FB_FUNCTION);
cryptGuard.enter();
Sync sync(&dbb->dbb_sync, "jrd.cpp: release_attachment");
// avoid races with special threads
XThreadEnsureUnlock threadGuard(dbb->dbb_thread_mutex, FB_FUNCTION);
threadGuard.enter();
sync.lock(SYNC_EXCLUSIVE);
// stop the crypt thread if we release last regular attachment
Jrd::Attachment* crypt_att = NULL;
// stop special threads if and only if we release last regular attachment
bool other = false;
CRYPT_DEBUG(fprintf(stderr, "\nrelease attachment=%p\n", attachment));
for (Jrd::Attachment* att = dbb->dbb_attachments; att; att = att->att_next)
{
CRYPT_DEBUG(fprintf(stderr, "att=%p crypt_att=%p F=%c ", att, crypt_att, att->att_flags & ATT_crypt_thread ? '1' : '0'));
if (att == attachment)
{ // checkout scope
EngineCheckout checkout(tdbb, FB_FUNCTION);
SPTHR_DEBUG(fprintf(stderr, "\nrelease attachment=%p\n", attachment));
for (Jrd::Attachment* att = dbb->dbb_attachments; att; att = att->att_next)
{
CRYPT_DEBUG(fprintf(stderr, "self\n"));
continue;
SPTHR_DEBUG(fprintf(stderr, "att=%p FromThr=%c ", att, att->att_flags & ATT_from_thread ? '1' : '0'));
if (att == attachment)
{
SPTHR_DEBUG(fprintf(stderr, "self\n"));
continue;
}
if (att->att_flags & ATT_from_thread)
{
SPTHR_DEBUG(fprintf(stderr, "found special att=%p\n", att));
continue;
}
// Found attachment that is not current (to be released) and is not special
other = true;
SPTHR_DEBUG(fprintf(stderr, "other\n"));
break;
}
if (att->att_flags & ATT_crypt_thread)
// Notify special threads
if (!other)
dbb->dbb_flags |= DBB_closing;
threadGuard.leave();
// Sync with special threads
if (!other)
{
crypt_att = att;
CRYPT_DEBUG(fprintf(stderr, "found crypt_att=%p\n", crypt_att));
continue;
sync.unlock();
// crypt thread
if (dbb->dbb_crypto_manager)
dbb->dbb_crypto_manager->terminateCryptThread(tdbb, true);
// sweep thread
if (dbb->dbb_sweep_thread)
{
Thread::waitForCompletion(dbb->dbb_sweep_thread);
dbb->dbb_sweep_thread = 0;
}
}
crypt_att = NULL;
other = true;
CRYPT_DEBUG(fprintf(stderr, "other\n"));
break;
}
if (dbb->dbb_crypto_manager && !(other || crypt_att))
dbb->dbb_crypto_manager->terminateCryptThread(tdbb, false);
cryptGuard.leave();
if (crypt_att)
{
sync.unlock();
CRYPT_DEBUG(fprintf(stderr, "crypt_att=%p terminateCryptThread\n", crypt_att));
fb_assert(dbb->dbb_crypto_manager);
dbb->dbb_crypto_manager->terminateCryptThread(tdbb, true);
} // EngineCheckout scope
// restore database lock if needed
if (!other)
sync.lock(SYNC_EXCLUSIVE);
}
// remove the attachment block from the dbb linked list
for (Jrd::Attachment** ptr = &dbb->dbb_attachments; *ptr; ptr = &(*ptr)->att_next)

View File

@ -1789,6 +1789,13 @@ void TRA_sweep(thread_db* tdbb)
try {
// Avoid races with release_attachment()
XThreadEnsureUnlock releaseAttGuard(dbb->dbb_thread_mutex, FB_FUNCTION);
releaseAttGuard.enter();
if (dbb->dbb_flags & DBB_closing)
return;
// Identify ourselves as a sweeper thread. This accomplishes two goals:
// 1) Sweep transaction is started "precommitted" and
// 2) Execution is throttled in JRD_reschedule() by
@ -1817,6 +1824,11 @@ void TRA_sweep(thread_db* tdbb)
attachment->att_flags &= ~ATT_notify_gc;
// Mark our attachment as special one
attachment->att_flags |= ATT_from_thread;
releaseAttGuard.leave();
if (VIO_sweep(tdbb, transaction, &traceSweep))
{
// At this point, we know that no record versions belonging to dead
@ -2677,35 +2689,21 @@ static void start_sweeper(thread_db* tdbb)
TRA_update_counters(tdbb, dbb);
// allocate space for the string and a null at the end
const char* pszFilename = tdbb->getAttachment()->att_filename.c_str();
char* database = (char*) gds__alloc(static_cast<SLONG>(strlen(pszFilename)) + 1);
if (database)
// pass dbb to sweep thread - if allowSweepThread() returned TRUE that is safe
try
{
strcpy(database, pszFilename);
try
{
Thread::start(sweep_database, database, THREAD_medium);
return;
}
catch (const Firebird::Exception& ex)
{
gds__free(database);
iscLogException("cannot start sweep thread", ex);
}
Thread::start(sweep_database, dbb, THREAD_medium, &dbb->dbb_sweep_thread);
return;
}
else
catch (const Firebird::Exception& ex)
{
ERR_log(0, 0, "cannot start sweep thread, Out of Memory");
iscLogException("cannot start sweep thread", ex);
dbb->clearSweepFlags(tdbb);
}
dbb->clearSweepFlags(tdbb);
}
static THREAD_ENTRY_DECLARE sweep_database(THREAD_ENTRY_PARAM database)
static THREAD_ENTRY_DECLARE sweep_database(THREAD_ENTRY_PARAM d)
{
/**************************************
*
@ -2717,26 +2715,32 @@ static THREAD_ENTRY_DECLARE sweep_database(THREAD_ENTRY_PARAM database)
* Sweep database.
*
**************************************/
Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::dpbList, MAX_DPB_SIZE);
dpb.insertByte(isc_dpb_sweep, isc_dpb_records);
// use embedded authentication to attach database
const char* szAuthenticator = "sweeper";
dpb.insertString(isc_dpb_user_name, szAuthenticator, fb_strlen(szAuthenticator));
ISC_STATUS_ARRAY status_vector = {0};
isc_db_handle db_handle = 0;
isc_attach_database(status_vector, 0, (const char*) database,
&db_handle, dpb.getBufferLength(),
reinterpret_cast<const char*>(dpb.getBuffer()));
if (db_handle)
// determine database name
// taking into an account that thread is started successfully
// we should take care about parameters reference counter and DBB flags
Database* dbb = (Database*) d;
try
{
isc_detach_database(status_vector, &db_handle);
}
ISC_STATUS_ARRAY status_vector = {0};
isc_db_handle db_handle = 0;
gds__free(database);
Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::dpbList, MAX_DPB_SIZE);
dpb.insertByte(isc_dpb_sweep, isc_dpb_records);
// use embedded authentication to attach database
const char* szAuthenticator = "sweeper";
dpb.insertString(isc_dpb_user_name, szAuthenticator, fb_strlen(szAuthenticator));
isc_attach_database(status_vector, 0, dbb->dbb_database_name.c_str(),
&db_handle, dpb.getBufferLength(),
reinterpret_cast<const char*>(dpb.getBuffer()));
if (db_handle)
isc_detach_database(status_vector, &db_handle);
}
catch (const Exception&)
{ }
dbb->clearSweepStarting(); // actually needed here only for classic,
// but do danger calling for super
return 0;
}

View File

@ -3705,6 +3705,13 @@ bool VIO_sweep(thread_db* tdbb, jrd_tra* transaction, TraceSweepEvent* traceSwee
for (FB_SIZE_T i = 1; (vector = attachment->att_relations) && i < vector->count(); i++)
{
if (dbb->dbb_flags & DBB_closing)
{
SPTHR_DEBUG(fprintf(stderr, "VIO_sweep exits\n"));
ret = false;
break;
}
relation = (*vector)[i];
if (relation)
relation = MET_lookup_relation_id(tdbb, i, false);
@ -3735,6 +3742,12 @@ bool VIO_sweep(thread_db* tdbb, jrd_tra* transaction, TraceSweepEvent* traceSwee
{
CCH_RELEASE(tdbb, &rpb.getWindow(tdbb));
if (dbb->dbb_flags & DBB_closing)
{
SPTHR_DEBUG(fprintf(stderr, "VIO_sweep exits after VIO_next_record\n"));
break;
}
if (relation->rel_flags & REL_deleting)
break;