Skip to content

Commit

Permalink
Fixed CORE-2064: AV when process is closing under high load
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexPeshkoff committed Sep 4, 2008
1 parent a3bfe23 commit 796a2e4
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 93 deletions.
4 changes: 4 additions & 0 deletions src/jrd/Database.cpp
Expand Up @@ -65,6 +65,10 @@ namespace Jrd
{
MemoryPool::deletePool(dbb_pools[i]);
}

dbb_flags |= DBB_destroying;
Checkout dcoHolder(this);
dbb_lock_mgr->release();
}

void Database::deletePool(MemoryPool* pool)
Expand Down
92 changes: 50 additions & 42 deletions src/jrd/Database.h
Expand Up @@ -81,6 +81,48 @@ namespace Jrd
typedef Firebird::ObjectsArray<Trigger> trig_vec;


//
// bit values for dbb_flags
//
const ULONG DBB_damaged = 0x1L;
const ULONG DBB_exclusive = 0x2L; // Database is accessed in exclusive mode
const ULONG DBB_bugcheck = 0x4L; // Bugcheck has occurred
#ifdef GARBAGE_THREAD
const ULONG DBB_garbage_collector = 0x8L; // garbage collector thread exists
const ULONG DBB_gc_active = 0x10L; // ... and is actively working.
const ULONG DBB_gc_pending = 0x20L; // garbage collection requested
#endif
const ULONG DBB_force_write = 0x40L; // Database is forced write
const ULONG DBB_no_reserve = 0x80L; // No reserve space for versions
const ULONG DBB_DB_SQL_dialect_3 = 0x100L; // database SQL dialect 3
const ULONG DBB_read_only = 0x200L; // DB is ReadOnly (RO). If not set, DB is RW
const ULONG DBB_being_opened_read_only = 0x400L; // DB is being opened RO. If unset, opened as RW
const ULONG DBB_not_in_use = 0x800L; // Database to be ignored while attaching
const ULONG DBB_lck_init_done = 0x1000L; // LCK_init() called for the database
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_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
const ULONG DBB_destroying = 0x100000L; // database destructor is called

//
// dbb_ast_flags
//
const UATOM DBB_blocking = 0x1L; // Exclusive mode is blocking
const UATOM DBB_get_shadows = 0x2L; // Signal received to check for new shadows
const UATOM DBB_assert_locks = 0x4L; // Locks are to be asserted
const UATOM DBB_shutdown = 0x8L; // Database is shutdown
const UATOM DBB_shut_attach = 0x10L; // no new attachments accepted
const UATOM DBB_shut_tran = 0x20L; // no new transactions accepted
const UATOM DBB_shut_force = 0x40L; // forced shutdown in progress
const UATOM DBB_shutdown_locks = 0x80L; // Database locks release by shutdown
const UATOM DBB_shutdown_full = 0x100L; // Database fully shut down
const UATOM DBB_shutdown_single = 0x200L; // Database is in single-user maintenance mode
const UATOM DBB_monitor_off = 0x400L; // Database has the monitoring lock released

class Database : public pool_alloc<type_dbb>, public Firebird::PublicHandle
{
class Sync : public Firebird::RefCounted
Expand Down Expand Up @@ -153,6 +195,13 @@ class Database : public pool_alloc<type_dbb>, public Firebird::PublicHandle
sync.release();
Firebird::status_exception::raise(Firebird::Arg::Gds(isc_bad_db_handle));
}

if (ast && dbb->dbb_flags & DBB_destroying)
{
sync.unlock();
sync.release();
Firebird::LongJump::raise();
}
}

~SyncGuard()
Expand Down Expand Up @@ -279,7 +328,7 @@ class Database : public pool_alloc<type_dbb>, public Firebird::PublicHandle
mutable Sync* dbb_sync; // Database sync primitive
Firebird::Reference dbb_sync_ref; // Database reference to dbb_sync

Firebird::RefPtr<LockManager> dbb_lock_mgr;
LockManager* dbb_lock_mgr;

Database* dbb_next; // Next database block in system
Attachment* dbb_attachments; // Active attachments
Expand Down Expand Up @@ -444,47 +493,6 @@ class Database : public pool_alloc<type_dbb>, public Firebird::PublicHandle
const Database& operator =(const Database&) { return *this; }
};

//
// bit values for dbb_flags
//
const ULONG DBB_damaged = 0x1L;
const ULONG DBB_exclusive = 0x2L; // Database is accessed in exclusive mode
const ULONG DBB_bugcheck = 0x4L; // Bugcheck has occurred
#ifdef GARBAGE_THREAD
const ULONG DBB_garbage_collector = 0x8L; // garbage collector thread exists
const ULONG DBB_gc_active = 0x10L; // ... and is actively working.
const ULONG DBB_gc_pending = 0x20L; // garbage collection requested
#endif
const ULONG DBB_force_write = 0x40L; // Database is forced write
const ULONG DBB_no_reserve = 0x80L; // No reserve space for versions
const ULONG DBB_DB_SQL_dialect_3 = 0x100L; // database SQL dialect 3
const ULONG DBB_read_only = 0x200L; // DB is ReadOnly (RO). If not set, DB is RW
const ULONG DBB_being_opened_read_only = 0x400L; // DB is being opened RO. If unset, opened as RW
const ULONG DBB_not_in_use = 0x800L; // Database to be ignored while attaching
const ULONG DBB_lck_init_done = 0x1000L; // LCK_init() called for the database
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_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

//
// dbb_ast_flags
//
const UATOM DBB_blocking = 0x1L; // Exclusive mode is blocking
const UATOM DBB_get_shadows = 0x2L; // Signal received to check for new shadows
const UATOM DBB_assert_locks = 0x4L; // Locks are to be asserted
const UATOM DBB_shutdown = 0x8L; // Database is shutdown
const UATOM DBB_shut_attach = 0x10L; // no new attachments accepted
const UATOM DBB_shut_tran = 0x20L; // no new transactions accepted
const UATOM DBB_shut_force = 0x40L; // forced shutdown in progress
const UATOM DBB_shutdown_locks = 0x80L; // Database locks release by shutdown
const UATOM DBB_shutdown_full = 0x100L; // Database fully shut down
const UATOM DBB_shutdown_single = 0x200L; // Database is in single-user maintenance mode
const UATOM DBB_monitor_off = 0x400L; // Database has the monitoring lock released

} // namespace Jrd

#endif // JRD_DATABASE_H
16 changes: 4 additions & 12 deletions src/jrd/gds.cpp
Expand Up @@ -1292,24 +1292,16 @@ void API_ROUTINE gds__log_status(const TEXT* database,

try
{
Firebird::string buffer;

if (database)
{
Firebird::string buffer;
buffer.printf("Database: %s", database);
iscLogStatus(buffer.c_str(), status_vector);
}

TEXT temp[BUFFER_LARGE];
while (safe_interpret(temp, sizeof(temp), &status_vector))
else
{
if (!buffer.empty())
{
buffer += "\n\t";
}
buffer += temp;
iscLogStatus(NULL, status_vector);
}

gds__log(buffer.c_str());
}
catch (const Firebird::Exception&)
{} // no-op
Expand Down
54 changes: 54 additions & 0 deletions src/jrd/isc.cpp
Expand Up @@ -582,3 +582,57 @@ LPSECURITY_ATTRIBUTES ISC_get_security_desc()
return security_attributes();
}
#endif


void iscLogStatus(const TEXT* text, const ISC_STATUS* status_vector)
{
/**************************************
*
* g d s _ $ l o g _ s t a t u s
*
**************************************
*
* Functional description
* Log error to error log.
*
**************************************/
fb_assert(status_vector[1] != FB_SUCCESS);

try
{
Firebird::string buffer(text ? text : "");

TEXT temp[BUFFER_LARGE];
while (fb_interpret(temp, sizeof(temp), &status_vector))
{
if (!buffer.empty())
{
buffer += "\n\t";
}
buffer += temp;
}

gds__log("%s", buffer.c_str());
}
catch (const Firebird::Exception&)
{} // no-op
}


void iscLogException(const char* text, const Firebird::Exception& e)
{
/**************************************
*
* l o g E x c e p t i o n
*
**************************************
*
* Functional description
* Add record about an exception to firebird.log
*
**************************************/
ISC_STATUS_ARRAY s;
e.stuff_exception(s);
iscLogStatus(text, s);
}

4 changes: 4 additions & 0 deletions src/jrd/isc_proto.h
Expand Up @@ -34,6 +34,10 @@ bool ISC_get_user(Firebird::string*, int*, int*, const TEXT*);
SLONG ISC_get_user_group_id(const TEXT*);
SLONG ISC_set_prefix(const TEXT*, const TEXT*);

// Does not add word "Database" in the beginning like gds__log_status
void iscLogStatus(const TEXT* text, const ISC_STATUS* status_vector);
void iscLogException(const TEXT* text, const Firebird::Exception& e);

#ifdef WIN_NT
struct _SECURITY_ATTRIBUTES* ISC_get_security_desc(void);
#endif
Expand Down
106 changes: 67 additions & 39 deletions src/lock/lock.cpp
Expand Up @@ -181,6 +181,8 @@ LockManager* LockManager::create(const Firebird::PathName& filename)
}

fb_assert(lockMgr);

lockMgr->addRef();
return lockMgr;
}

Expand Down Expand Up @@ -1311,65 +1313,91 @@ void LockManager::blocking_action_thread()
* Thread to handle blocking signals.
*
**************************************/
SRQ_PTR* process_offset_ptr = (SRQ_PTR*) &m_processOffset;

/*
* Main thread may be gone releasing our LockManager instance
* when AST can't lock appropriate database mutex and therefore does not return.
*
* This causes multiple errors when entering/releasing mutexes/semaphores.
* Catch this errors and log them.
*
* AP 2008
*/

bool atStartup = true;

while (true)
try
{
m_localMutex.enter();
SRQ_PTR* process_offset_ptr = (SRQ_PTR*) &m_processOffset;

// See if the main thread has requested us to go away
if (!*process_offset_ptr || m_process->prc_process_id != PID)
while (true)
{
if (atStartup)
m_localMutex.enter();

// See if the main thread has requested us to go away
if (!*process_offset_ptr || m_process->prc_process_id != PID)
{
m_startupSemaphore.release();
if (atStartup)
{
m_startupSemaphore.release();
}
break;
}
break;
}

const SLONG value = ISC_event_clear(&m_process->prc_blocking);
const SLONG value = ISC_event_clear(&m_process->prc_blocking);

DEBUG_DELAY;
DEBUG_DELAY;

Firebird::HalfStaticArray<SRQ_PTR, 4> blocking_owners;
Firebird::HalfStaticArray<SRQ_PTR, 4> blocking_owners;

acquire_shmem(DUMMY_OWNER);
const prc* const process = (prc*) SRQ_ABS_PTR(*process_offset_ptr);
acquire_shmem(DUMMY_OWNER);
const prc* const process = (prc*) SRQ_ABS_PTR(*process_offset_ptr);

srq* lock_srq;
SRQ_LOOP(process->prc_owners, lock_srq)
{
own* owner = (own*) ((UCHAR *) lock_srq - OFFSET(own*, own_prc_owners));
blocking_owners.add(SRQ_REL_PTR(owner));
}
srq* lock_srq;
SRQ_LOOP(process->prc_owners, lock_srq)
{
own* owner = (own*) ((UCHAR *) lock_srq - OFFSET(own*, own_prc_owners));
blocking_owners.add(SRQ_REL_PTR(owner));
}

release_mutex();
release_mutex();

while (blocking_owners.getCount() && *process_offset_ptr)
{
const SRQ_PTR owner_offset = blocking_owners.pop();
acquire_shmem(owner_offset);
blocking_action(NULL, owner_offset, (SRQ_PTR) NULL);
release_shmem(owner_offset);
}
while (blocking_owners.getCount() && *process_offset_ptr)
{
const SRQ_PTR owner_offset = blocking_owners.pop();
acquire_shmem(owner_offset);
blocking_action(NULL, owner_offset, (SRQ_PTR) NULL);
release_shmem(owner_offset);
}

if (atStartup)
{
atStartup = false;
m_startupSemaphore.release();
if (atStartup)
{
atStartup = false;
m_startupSemaphore.release();
}

m_localMutex.leave();

event_t* event_ptr = &m_process->prc_blocking;
ISC_event_wait(1, &event_ptr, &value, 0);
}

m_localMutex.leave();

event_t* event_ptr = &m_process->prc_blocking;
ISC_event_wait(1, &event_ptr, &value, 0);
}
catch(const Firebird::Exception& x)
{
iscLogException("Error in blocking action thread\n", x);
}

m_localMutex.leave();

// Wakeup the main thread waiting for our exit
m_cleanupSemaphore.release();
try
{
// Wakeup the main thread waiting for our exit
m_cleanupSemaphore.release();
}
catch(const Firebird::Exception& x)
{
iscLogException("Error closing blocking action thread\n", x);
}
}


Expand Down

0 comments on commit 796a2e4

Please sign in to comment.