diff --git a/src/jrd/Attachment.cpp b/src/jrd/Attachment.cpp index aaf4130007..4303aabeb7 100644 --- a/src/jrd/Attachment.cpp +++ b/src/jrd/Attachment.cpp @@ -353,11 +353,25 @@ void Jrd::Attachment::storeBinaryBlob(thread_db* tdbb, jrd_tra* transaction, } -void Jrd::Attachment::cancelExternalConnection(thread_db* tdbb) +void Jrd::Attachment::signalCancel(thread_db* tdbb) { - if (att_ext_connection) { + att_flags |= ATT_cancel_raise; + + if (att_ext_connection) att_ext_connection->cancelExecution(tdbb); - } + + LCK_cancel_wait(this); +} + + +void Jrd::Attachment::signalShutdown(thread_db* tdbb) +{ + att_flags |= ATT_shutdown; + + if (att_ext_connection) + att_ext_connection->cancelExecution(tdbb); + + LCK_cancel_wait(this); } @@ -531,6 +545,9 @@ void Jrd::Attachment::releaseLocks(thread_db* tdbb) if (att_id_lock) LCK_release(tdbb, att_id_lock); + if (att_cancel_lock) + LCK_release(tdbb, att_cancel_lock); + if (att_temp_pg_lock) LCK_release(tdbb, att_temp_pg_lock); diff --git a/src/jrd/Attachment.h b/src/jrd/Attachment.h index edae0f9f56..dc9ac0c0c6 100644 --- a/src/jrd/Attachment.h +++ b/src/jrd/Attachment.h @@ -225,6 +225,7 @@ public: Firebird::SortedArray att_requests; // Requests belonging to attachment Lock* att_id_lock; // Attachment lock (if any) SLONG att_attachment_id; // Attachment ID + Lock* att_cancel_lock; // Lock to cancel the active request const ULONG att_lock_owner_id; // ID for the lock manager SLONG att_lock_owner_handle; // Handle for the lock manager ULONG att_backup_state_counter; // Counter of backup state locks for attachment @@ -326,7 +327,9 @@ public: void storeBinaryBlob(thread_db* tdbb, jrd_tra* transaction, bid* blobId, const Firebird::ByteChunk& chunk); - void cancelExternalConnection(thread_db* tdbb); + void signalCancel(thread_db* tdbb); + void signalShutdown(thread_db* tdbb); + void detachLocksFromAttachment(); bool backupStateWriteLock(thread_db* tdbb, SSHORT wait); @@ -334,8 +337,6 @@ public: bool backupStateReadLock(thread_db* tdbb, SSHORT wait); void backupStateReadUnLock(thread_db* tdbb); - bool cancelRaise(); - private: Attachment(MemoryPool* pool, Database* dbb); ~Attachment(); @@ -360,8 +361,6 @@ const ULONG ATT_gfix_attachment = 0x01000L; // Indicate a GFIX attachment const ULONG ATT_gstat_attachment = 0x02000L; // Indicate a GSTAT attachment const ULONG ATT_no_db_triggers = 0x04000L; // Don't execute database triggers const ULONG ATT_manual_lock = 0x08000L; // Was locked manually -const ULONG ATT_terminate = 0x10000L; // Terminate currently running operation -const ULONG ATT_protected = 0x20000L; // Ignore termination flag when disconnecting const ULONG ATT_NO_CLEANUP = (ATT_no_cleanup | ATT_notify_gc); @@ -381,14 +380,6 @@ inline void Attachment::setSysTransaction(jrd_tra* trans) att_sys_transaction = trans; } -inline bool Attachment::cancelRaise() -{ - return att_flags & ATT_protected ? false : - att_flags & ATT_terminate ? true : - att_flags & ATT_cancel_disable ? false : - att_flags & ATT_cancel_raise ? true : false; -} - } // namespace Jrd #endif // JRD_ATTACHMENT_H diff --git a/src/jrd/VirtualTable.cpp b/src/jrd/VirtualTable.cpp index 51ab8d7e23..6ba07cd7ef 100644 --- a/src/jrd/VirtualTable.cpp +++ b/src/jrd/VirtualTable.cpp @@ -70,8 +70,8 @@ void VirtualTable::erase(thread_db* tdbb, record_param* rpb) } else if (relation->rel_id == rel_mon_statements) { - // Get transaction id - if (!EVL_field(relation, rpb->rpb_record, f_mon_stmt_tra_id, &desc)) + // Get attachment id + if (!EVL_field(relation, rpb->rpb_record, f_mon_stmt_att_id, &desc)) return; lock_type = LCK_cancel; } diff --git a/src/jrd/exe.cpp b/src/jrd/exe.cpp index e84daacc0d..922fbca9bf 100644 --- a/src/jrd/exe.cpp +++ b/src/jrd/exe.cpp @@ -1146,7 +1146,7 @@ static void execute_looper(thread_db* tdbb, // Ensure the cancellation lock can be triggered - Lock* const lock = transaction->tra_cancel_lock; + Lock* const lock = attachment->att_cancel_lock; if (lock && lock->lck_logical == LCK_none) LCK_lock(tdbb, lock, LCK_SR, LCK_WAIT); diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index a6b74e892b..61e51ce21a 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -796,12 +796,7 @@ private: UserId m_id; }; -namespace { - const unsigned CHECK_ASYNC = 1; - const unsigned CHECK_DISCONNECT = 2; -} -static void check_database(thread_db* tdbb, unsigned flags = 0); -static void check_transaction(thread_db*, jrd_tra*); +static void check_database(thread_db* tdbb, bool async = false); static void commit(thread_db*, jrd_tra*, const bool); static bool drop_files(const jrd_file*); static void find_intl_charset(thread_db*, Jrd::Attachment*, const DatabaseOptions*); @@ -832,7 +827,6 @@ static bool unlink_database(Database*); static void shutdown_database(Database*, const bool); static void strip_quotes(string&); static void purge_attachment(thread_db*, Jrd::Attachment*, const bool); -static void terminate_attachment(thread_db* tdbb, Attachment* attachment); static void getUserInfo(UserId&, const DatabaseOptions&, const RefPtr*); static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM); @@ -2617,7 +2611,6 @@ void JAttachment::freeEngineData(IStatus* user_status) try { EngineContextHolder tdbb(user_status, this, FB_FUNCTION, AttachmentHolder::ATT_LOCK_ASYNC); - check_database(tdbb, CHECK_DISCONNECT); try { @@ -2625,7 +2618,7 @@ void JAttachment::freeEngineData(IStatus* user_status) if (attachment->att_in_use) status_exception::raise(Arg::Gds(isc_attachment_in_use)); - terminate_attachment(tdbb, attachment); + attachment->signalShutdown(tdbb); purge_attachment(tdbb, attachment, false); att = NULL; @@ -2719,7 +2712,7 @@ void JAttachment::dropDatabase(IStatus* user_status) // Forced release of all transactions purge_transactions(tdbb, attachment, true, attachment->att_flags); - attachment->att_flags |= ATT_cancel_disable; + tdbb->tdbb_flags |= TDBB_detaching; // Here we have database locked in exclusive mode. // Just mark the header page with an 0 ods version so that no other @@ -4683,7 +4676,7 @@ void JAttachment::ping(IStatus* user_status) try { EngineContextHolder tdbb(user_status, this, FB_FUNCTION); - check_database(tdbb); + check_database(tdbb, true); } catch (const Exception& ex) { @@ -4869,7 +4862,7 @@ void jrd_vtof(const char* string, char* field, SSHORT length) } -static void check_database(thread_db* tdbb, unsigned flags) +static void check_database(thread_db* tdbb, bool async) { /************************************** * @@ -4883,45 +4876,50 @@ static void check_database(thread_db* tdbb, unsigned flags) **************************************/ SET_TDBB(tdbb); - Database* dbb = tdbb->getDatabase(); - Jrd::Attachment* attachment = tdbb->getAttachment(); + Database* const dbb = tdbb->getDatabase(); + Jrd::Attachment* const attachment = tdbb->getAttachment(); - if (!(flags & CHECK_DISCONNECT)) + // Test for persistent errors + + if (dbb->dbb_flags & DBB_bugcheck) { - if (dbb->dbb_flags & DBB_bugcheck) - { - static const char string[] = "can't continue after bugcheck"; - status_exception::raise(Arg::Gds(isc_bug_check) << Arg::Str(string)); - } + static const char string[] = "can't continue after bugcheck"; + status_exception::raise(Arg::Gds(isc_bug_check) << Arg::Str(string)); + } - if ((attachment->att_flags & ATT_shutdown) || - ((dbb->dbb_ast_flags & DBB_shutdown) && - ((dbb->dbb_ast_flags & DBB_shutdown_full) || !attachment->locksmith()))) + if ((attachment->att_flags & ATT_shutdown) || + ((dbb->dbb_ast_flags & DBB_shutdown) && + ((dbb->dbb_ast_flags & DBB_shutdown_full) || !attachment->locksmith()))) + { + if (dbb->dbb_ast_flags & DBB_shutdown) { - if (dbb->dbb_ast_flags & DBB_shutdown) - { - const PathName& filename = attachment->att_filename; - status_exception::raise(Arg::Gds(isc_shutdown) << Arg::Str(filename)); - } - else - { - status_exception::raise(Arg::Gds(isc_att_shutdown)); - } + const PathName& filename = attachment->att_filename; + status_exception::raise(Arg::Gds(isc_shutdown) << Arg::Str(filename)); } + else + { + status_exception::raise(Arg::Gds(isc_att_shutdown)); + } + } - // do not use cancelRaise() here - we do not care about internal flags - if ((!(flags & CHECK_ASYNC)) && (attachment->att_flags & ATT_cancel_raise) - && !(attachment->att_flags & ATT_cancel_disable)) - { - attachment->att_flags &= ~ATT_cancel_raise; - status_exception::raise(Arg::Gds(isc_cancelled)); - } + // No further checks for the async calls + + if (async) + return; + + // Test for temporary errors + + if ((attachment->att_flags & ATT_cancel_raise) + && !(attachment->att_flags & ATT_cancel_disable)) + { + attachment->att_flags &= ~ATT_cancel_raise; + status_exception::raise(Arg::Gds(isc_cancelled)); } // Enable signal handler for the monitoring stuff. // See also comments in JRD_reshedule. - if (dbb->dbb_ast_flags & DBB_monitor_off && !(flags & CHECK_ASYNC)) + if (dbb->dbb_ast_flags & DBB_monitor_off) { SyncLockGuard monGuard(&dbb->dbb_mon_sync, SYNC_EXCLUSIVE, "check_database"); @@ -4937,29 +4935,6 @@ static void check_database(thread_db* tdbb, unsigned flags) } -static void check_transaction(thread_db* tdbb, jrd_tra* transaction) -{ -/************************************** - * - * c h e c k _ t r a n s a c t i o n - * - ************************************** - * - * Functional description - * Check transaction for not being interrupted - * in the meantime. - * - **************************************/ - SET_TDBB(tdbb); - - if (transaction && (transaction->tra_flags & TRA_cancel_request)) - { - transaction->tra_flags &= ~TRA_cancel_request; - status_exception::raise(Arg::Gds(isc_cancelled)); - } -} - - static void commit(thread_db* tdbb, jrd_tra* transaction, const bool retaining_flag) { /************************************** @@ -6291,8 +6266,6 @@ static void purge_attachment(thread_db* tdbb, Jrd::Attachment* attachment, const THD_sleep(1); } - attachment->att_flags |= ATT_protected; - Database* const dbb = attachment->att_database; tdbb->tdbb_flags |= TDBB_detaching; @@ -6679,25 +6652,6 @@ static void unwindAttach(thread_db* tdbb, const Exception& ex, Firebird::IStatus } -static void terminate_attachment(thread_db* tdbb, Attachment* attachment) -{ -/******************************************** - * - * t e r m i n a t e _ a t t a c h m e n t - * - ******************************************** - * - * Functional description - * Set terminate flag on attachment and - * call required subsytems to help wakeup it. - * - **************************************/ - attachment->att_flags |= ATT_terminate; - attachment->cancelExternalConnection(tdbb); - LCK_cancel_wait(attachment); -} - - namespace { @@ -6739,7 +6693,7 @@ namespace tdbb->setAttachment(attachment); tdbb->setDatabase(attachment->att_database); - terminate_attachment(tdbb, attachment); + attachment->signalShutdown(tdbb); } } @@ -6945,7 +6899,8 @@ bool thread_db::checkCancelState(bool punt) // when executing in the context of an internal request or // the system transaction. - if (attachment->cancelRaise()) + if ((attachment->att_flags & ATT_cancel_raise) && + !(attachment->att_flags & ATT_cancel_disable)) { if ((!request || !(request->getStatement()->flags & @@ -6959,24 +6914,9 @@ bool thread_db::checkCancelState(bool punt) attachment->att_flags &= ~ATT_cancel_raise; status_exception::raise(Arg::Gds(isc_cancelled)); } -/* fprintf(stderr, "req %p flags %x tra %p flags %x\n", request, request ? (request->getStatement()->flags & - (JrdStatement::FLAG_INTERNAL | JrdStatement::FLAG_SYS_TRIGGER)) : 0, - transaction, transaction ? (transaction->tra_flags & TRA_system) : 0); - abort(); */ } } - // Handle request cancellation - - if (transaction && (transaction->tra_flags & TRA_cancel_request)) - { - if (!punt) - return true; - - transaction->tra_flags &= ~TRA_cancel_request; - status_exception::raise(Arg::Gds(isc_cancelled)); - } - // Check the thread state for already posted system errors. If any still persists, // then someone tries to ignore our attempts to interrupt him. Let's insist. @@ -7057,8 +6997,6 @@ void JRD_receive(thread_db* tdbb, jrd_req* request, USHORT msg_type, ULONG msg_l * Get a record from the host program. * **************************************/ - check_transaction(tdbb, request->req_transaction); - EXE_receive(tdbb, request, msg_type, msg_length, msg, true); check_autocommit(request, tdbb); @@ -7083,8 +7021,6 @@ void JRD_send(thread_db* tdbb, jrd_req* request, USHORT msg_type, ULONG msg_leng * Get a record from the host program. * **************************************/ - check_transaction(tdbb, request->req_transaction); - EXE_send(tdbb, request, msg_type, msg_length, msg); check_autocommit(request, tdbb); @@ -7109,8 +7045,6 @@ void JRD_start(Jrd::thread_db* tdbb, jrd_req* request, jrd_tra* transaction) * Get a record from the host program. * **************************************/ - check_transaction(tdbb, transaction); - EXE_unwind(tdbb, request); EXE_start(tdbb, request, transaction); @@ -7201,8 +7135,6 @@ void JRD_start_and_send(thread_db* tdbb, jrd_req* request, jrd_tra* transaction, * Get a record from the host program. * **************************************/ - check_transaction(tdbb, transaction); - EXE_unwind(tdbb, request); EXE_start(tdbb, request, transaction); EXE_send(tdbb, request, msg_type, msg_length, msg); @@ -7462,11 +7394,7 @@ void JRD_cancel_operation(thread_db* tdbb, Jrd::Attachment* attachment, int opti case fb_cancel_raise: if (!(attachment->att_flags & ATT_cancel_disable)) - { - attachment->att_flags |= ATT_cancel_raise; - attachment->cancelExternalConnection(tdbb); - LCK_cancel_wait(attachment); - } + attachment->signalCancel(tdbb); break; default: diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index 2fa3fe242f..d5c47d6860 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -109,7 +109,8 @@ using namespace Firebird; static void add_clump(thread_db* tdbb, USHORT type, USHORT len, const UCHAR* entry, ClumpOper mode); static void attach_temp_pages(thread_db* tdbb, USHORT pageSpaceID); -static int blocking_ast_attachment(void*); +static int blocking_ast_shutdown_attachment(void*); +static int blocking_ast_cancel_attachment(void*); static void find_clump_space(thread_db* tdbb, WIN*, pag**, USHORT, USHORT, const UCHAR*); static bool find_type(thread_db* tdbb, WIN*, pag**, USHORT, USHORT, UCHAR**, const UCHAR**); @@ -764,12 +765,19 @@ SLONG PAG_attachment_id(thread_db* tdbb) // Take out lock on attachment id - Lock* const lock = FB_NEW_RPT(*attachment->att_pool, sizeof(SLONG)) - Lock(tdbb, sizeof(SLONG), LCK_attachment, attachment, blocking_ast_attachment); + Lock* lock = FB_NEW_RPT(*attachment->att_pool, sizeof(SLONG)) + Lock(tdbb, sizeof(SLONG), LCK_attachment, attachment, blocking_ast_shutdown_attachment); attachment->att_id_lock = lock; lock->lck_key.lck_long = attachment->att_attachment_id; LCK_lock(tdbb, lock, LCK_EX, LCK_WAIT); + // Allocate the cancellation lock + + lock = FB_NEW_RPT(*attachment->att_pool, sizeof(SLONG)) + Lock(tdbb, sizeof(SLONG), LCK_cancel, attachment, blocking_ast_cancel_attachment); + attachment->att_cancel_lock = lock; + lock->lck_key.lck_long = attachment->att_attachment_id; + return attachment->att_attachment_id; } @@ -1696,7 +1704,7 @@ void PAG_sweep_interval(thread_db* tdbb, SLONG interval) } -static int blocking_ast_attachment(void* ast_object) +static int blocking_ast_shutdown_attachment(void* ast_object) { Jrd::Attachment* const attachment = static_cast(ast_object); @@ -1706,9 +1714,7 @@ static int blocking_ast_attachment(void* ast_object) AsyncContextHolder tdbb(dbb, FB_FUNCTION, attachment->att_id_lock); - attachment->att_flags |= ATT_shutdown; - attachment->cancelExternalConnection(tdbb); - LCK_cancel_wait(attachment); + attachment->signalShutdown(tdbb); JRD_shutdown_attachments(dbb); @@ -1721,6 +1727,27 @@ static int blocking_ast_attachment(void* ast_object) } +static int blocking_ast_cancel_attachment(void* ast_object) +{ + Jrd::Attachment* const attachment = static_cast(ast_object); + + try + { + Database* const dbb = attachment->att_database; + + AsyncContextHolder tdbb(dbb, FB_FUNCTION, attachment->att_cancel_lock); + + attachment->signalCancel(tdbb); + + LCK_release(tdbb, attachment->att_cancel_lock); + } + catch (const Exception&) + {} // no-op + + return 0; +} + + static void find_clump_space(thread_db* tdbb, WIN* window, PAG* ppage, diff --git a/src/jrd/shut.cpp b/src/jrd/shut.cpp index fd509e7305..e8a3a3411b 100644 --- a/src/jrd/shut.cpp +++ b/src/jrd/shut.cpp @@ -516,11 +516,7 @@ static void shutdown(thread_db* tdbb, SSHORT flag) for (Jrd::Attachment* attachment = dbb->dbb_attachments; attachment; attachment = attachment->att_next) { if (!(attachment->att_flags & ATT_shutdown_manager)) - { - attachment->att_flags |= ATT_shutdown; - attachment->cancelExternalConnection(tdbb); - LCK_cancel_wait(attachment); - } + attachment->signalShutdown(tdbb); } JRD_shutdown_attachments(dbb); diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index dd8e1ddf58..3d00208dde 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -84,7 +84,6 @@ using namespace Firebird; typedef Firebird::GenericMap > > RelationLockTypeMap; -static int blocking_ast_transaction(void*); #ifdef SUPERSERVER_V2 static TraNumber bump_transaction_id(thread_db*, WIN*); #else @@ -1101,9 +1100,6 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction, Jrd::TraceTr // Release the locks associated with the transaction - if (transaction->tra_cancel_lock) - LCK_release(tdbb, transaction->tra_cancel_lock); - vec* vector = transaction->tra_relation_locks; if (vector) { @@ -1824,42 +1820,6 @@ int TRA_wait(thread_db* tdbb, jrd_tra* trans, TraNumber number, jrd_tra::wait_t } -static int blocking_ast_transaction(void* ast_object) -{ -/************************************** - * - * b l o c k i n g _ a s t _ t r a n s a c t i o n - * - ************************************** - * - * Functional description - * Mark the transaction to cancel its active requests. - * - **************************************/ - jrd_tra* const transaction = static_cast(ast_object); - - try - { - Database* const dbb = transaction->tra_cancel_lock->lck_dbb; - - AsyncContextHolder tdbb(dbb, FB_FUNCTION, transaction->tra_cancel_lock); - - if (transaction->tra_cancel_lock) - LCK_release(tdbb, transaction->tra_cancel_lock); - - transaction->tra_flags |= TRA_cancel_request; - - Jrd::Attachment* const att = tdbb->getAttachment(); - att->cancelExternalConnection(tdbb); - LCK_cancel_wait(att); - } - catch (const Firebird::Exception&) - {} // no-op - - return 0; -} - - #ifdef SUPERSERVER_V2 static TraNumber bump_transaction_id(thread_db* tdbb, WIN* window) { @@ -3264,13 +3224,6 @@ static jrd_tra* transaction_start(thread_db* tdbb, jrd_tra* temp) trans->tra_save_point->sav_flags |= SAV_trans_level; } - // Allocate the cancellation lock - - lock = FB_NEW_RPT(*trans->tra_pool, 0) - Lock(tdbb, sizeof(SLONG), LCK_cancel, trans, blocking_ast_transaction); - trans->tra_cancel_lock = lock; - lock->lck_key.lck_long = trans->tra_number; - // if the user asked us to restart all requests in this attachment, // do so now using the new transaction diff --git a/src/jrd/tra.h b/src/jrd/tra.h index 0d2202f796..1f1cbe75e8 100644 --- a/src/jrd/tra.h +++ b/src/jrd/tra.h @@ -245,7 +245,6 @@ public: BlobIndexTree* tra_blobs; // pointer to actual list of active blobs ArrayField* tra_arrays; // Linked list of active arrays Lock* tra_lock; // lock for transaction - Lock* tra_cancel_lock; // lock to cancel the active request vec* tra_relation_locks; // locks for relations UInt32Bitmap* tra_commit_sub_trans; // commited sub-transactions Savepoint* tra_save_point; // list of savepoints @@ -360,9 +359,8 @@ const ULONG TRA_perform_autocommit = 0x1000L; // indicates autocommit is necessa const ULONG TRA_rec_version = 0x2000L; // don't wait for uncommitted versions const ULONG TRA_restart_requests = 0x4000L; // restart all requests in attachment const ULONG TRA_no_auto_undo = 0x8000L; // don't start a savepoint in TRA_start -const ULONG TRA_cancel_request = 0x10000L; // cancel active request, if any -const ULONG TRA_precommitted = 0x20000L; // transaction committed at startup -const ULONG TRA_own_interface = 0x40000L; // tra_interface was created for internal needs +const ULONG TRA_precommitted = 0x10000L; // transaction committed at startup +const ULONG TRA_own_interface = 0x20000L; // tra_interface was created for internal needs // flags derived from TPB, see also transaction_options() at tra.cpp const ULONG TRA_OPTIONS_MASK = (TRA_degree3 | TRA_readonly | TRA_ignore_limbo | TRA_read_committed |