From 62ca23fa58281cd36ef4a276ed72e872ddcb2cd1 Mon Sep 17 00:00:00 2001 From: hvlad Date: Mon, 17 Nov 2008 12:30:28 +0000 Subject: [PATCH] Fixed bug CORE-2183 : Error in ExtDS when server shutdown started with opened Execute Statement --- src/jrd/extds/ExtDS.cpp | 71 ++++++++++++++++++++++++++++++------ src/jrd/extds/ExtDS.h | 8 +++- src/jrd/extds/InternalDS.cpp | 8 ++-- src/jrd/extds/InternalDS.h | 3 +- src/jrd/extds/IscDS.cpp | 4 +- src/jrd/extds/IscDS.h | 2 +- src/jrd/jrd.cpp | 5 +++ 7 files changed, 78 insertions(+), 23 deletions(-) diff --git a/src/jrd/extds/ExtDS.cpp b/src/jrd/extds/ExtDS.cpp index 7d80d95738..34ff4de9ef 100644 --- a/src/jrd/extds/ExtDS.cpp +++ b/src/jrd/extds/ExtDS.cpp @@ -369,6 +369,18 @@ void Connection::releaseStatement(Jrd::thread_db *tdbb, Statement *stmt) m_provider.releaseConnection(JRD_get_thread_data(), *this); } +void Connection::clearTransactions(Jrd::thread_db *tdbb) +{ + Transaction **tran_ptr = m_transactions.begin(); + Transaction **end = m_transactions.end(); + + while (m_transactions.getCount()) + { + Transaction *tran = m_transactions[0]; + tran->rollback(tdbb, false); + } +} + void Connection::clearStatements(thread_db *tdbb) { Statement **stmt_ptr = m_statements.begin(); @@ -389,6 +401,19 @@ void Connection::clearStatements(thread_db *tdbb) m_free_stmts = m_used_stmts = 0; } +void Connection::detach(thread_db *tdbb) +{ + const bool was_deleting = m_deleting; + m_deleting = true; + + clearStatements(tdbb); + clearTransactions(tdbb); + + m_deleting = was_deleting; + + doDetach(tdbb); +} + Transaction* Connection::findTransaction(thread_db *tdbb, TraScope traScope) const { jrd_tra *tran = tdbb->getTransaction(); @@ -494,11 +519,13 @@ void Transaction::start(thread_db *tdbb, TraScope traScope, TraModes traMode, { case traCommon : this->m_nextTran = tran->tra_ext_common; + this->m_jrdTran = tran; tran->tra_ext_common = this; break; case traTwoPhase : // join transaction + // this->m_jrdTran = tran; // tran->tra_ext_two_phase = ext_tran; break; } @@ -523,7 +550,9 @@ void Transaction::commit(thread_db *tdbb, bool retain) m_connection.raise(status, tdbb, "transaction commit"); } - if (!retain) { + if (!retain) + { + detachFromJrdTran(); m_connection.deleteTransaction(this); } } @@ -533,7 +562,9 @@ void Transaction::rollback(thread_db *tdbb, bool retain) ISC_STATUS_ARRAY status = {0}; doRollback(status, tdbb, retain); - if (!retain) { + if (!retain) + { + detachFromJrdTran(); m_connection.deleteTransaction(this); } @@ -581,15 +612,35 @@ Transaction* Transaction::getTransaction(thread_db *tdbb, Connection *conn, TraS return ext_tran; } +void Transaction::detachFromJrdTran() +{ + if (m_scope != traCommon) + return; + + fb_assert(m_jrdTran); + if (!m_jrdTran) + return; + + Transaction **tran_ptr = &m_jrdTran->tra_ext_common; + for (; *tran_ptr; tran_ptr = &(*tran_ptr)->m_nextTran) + { + if (*tran_ptr == this) + { + *tran_ptr = this->m_nextTran; + this->m_nextTran = NULL; + return; + } + } + + fb_assert(false); +} + void Transaction::jrdTransactionEnd(thread_db *tdbb, jrd_tra* transaction, bool commit, bool retain, bool force) { - Transaction** ext_tran = &transaction->tra_ext_common; - Transaction* tran = *ext_tran; - - while (tran) + while (transaction->tra_ext_common) { - Transaction* next = tran->m_nextTran; + Transaction* tran = transaction->tra_ext_common; try { if (commit) @@ -604,11 +655,7 @@ void Transaction::jrdTransactionEnd(thread_db *tdbb, jrd_tra* transaction, // ignore rollback error fb_utils::init_status(tdbb->tdbb_status_vector); - } - - tran = next; - if (!retain) { - *ext_tran = tran; + tran->detachFromJrdTran(); } } } diff --git a/src/jrd/extds/ExtDS.h b/src/jrd/extds/ExtDS.h index b10abbcb8c..e95818a756 100644 --- a/src/jrd/extds/ExtDS.h +++ b/src/jrd/extds/ExtDS.h @@ -149,7 +149,7 @@ public: virtual void attach(Jrd::thread_db *tdbb, const Firebird::string &dbName, const Firebird::string &user, const Firebird::string &pwd) = 0; - virtual void detach(Jrd::thread_db *tdbb) = 0; + virtual void detach(Jrd::thread_db *tdbb); int getSqlDialect() const { return m_sqlDialect; } @@ -198,8 +198,12 @@ protected: virtual Transaction* doCreateTransaction() = 0; virtual Statement* doCreateStatement() = 0; + + void clearTransactions(Jrd::thread_db *tdbb); void clearStatements(Jrd::thread_db *tdbb); + virtual void doDetach(Jrd::thread_db *tdbb) = 0; + // Protection against simultaneous ISC API calls for the same connection Firebird::Mutex m_mutex; @@ -253,6 +257,7 @@ public: protected: virtual void generateTPB(Jrd::thread_db *tdbb, Firebird::ClumpletWriter &tpb, TraModes traMode, bool readOnly, bool wait, int lockTimeout) const; + void detachFromJrdTran(); virtual void doStart(ISC_STATUS* status, Jrd::thread_db *tdbb, Firebird::ClumpletWriter &tpb) = 0; virtual void doPrepare(ISC_STATUS* status, Jrd::thread_db *tdbb, int info_len, const char* info) = 0; @@ -263,6 +268,7 @@ protected: Connection &m_connection; TraScope m_scope; Transaction *m_nextTran; // next common transaction + Jrd::jrd_tra *m_jrdTran; // parent JRD transaction }; diff --git a/src/jrd/extds/InternalDS.cpp b/src/jrd/extds/InternalDS.cpp index da6e1f0c76..72fd7bf10c 100644 --- a/src/jrd/extds/InternalDS.cpp +++ b/src/jrd/extds/InternalDS.cpp @@ -146,11 +146,10 @@ void InternalConnection::attach(thread_db *tdbb, const Firebird::string &dbName, SQL_DIALECT_V6 : SQL_DIALECT_V5; } -void InternalConnection::detach(thread_db *tdbb) +void InternalConnection::doDetach(thread_db *tdbb) { - clearStatements(tdbb); - fb_assert(m_attachment); + if (m_isCurrent) { m_attachment = 0; @@ -170,9 +169,10 @@ void InternalConnection::detach(thread_db *tdbb) } if (status[1]) { - raise(status, tdbb, "dettach"); + raise(status, tdbb, "detach"); } } + fb_assert(!m_attachment) } diff --git a/src/jrd/extds/InternalDS.h b/src/jrd/extds/InternalDS.h index 2995225537..0009e9aff7 100644 --- a/src/jrd/extds/InternalDS.h +++ b/src/jrd/extds/InternalDS.h @@ -66,8 +66,6 @@ public: virtual void attach(Jrd::thread_db *tdbb, const Firebird::string &dbName, const Firebird::string &user, const Firebird::string &pwd); - virtual void detach(Jrd::thread_db *tdbb); - virtual bool isAvailable(Jrd::thread_db *tdbb, TraScope traScope) const; virtual bool isConnected() const { return (m_attachment != 0); } @@ -84,6 +82,7 @@ public: protected: virtual Transaction* doCreateTransaction(); virtual Statement* doCreateStatement(); + virtual void doDetach(Jrd::thread_db *tdbb); Jrd::Attachment* m_attachment; bool m_isCurrent; diff --git a/src/jrd/extds/IscDS.cpp b/src/jrd/extds/IscDS.cpp index 4e7a9bd4a3..140ffc0706 100644 --- a/src/jrd/extds/IscDS.cpp +++ b/src/jrd/extds/IscDS.cpp @@ -154,10 +154,8 @@ void IscConnection::attach(thread_db *tdbb, const string &dbName, const string & } } -void IscConnection::detach(thread_db *tdbb) +void IscConnection::doDetach(thread_db *tdbb) { - clearStatements(tdbb); - ISC_STATUS_ARRAY status = {0}; if (m_handle) { diff --git a/src/jrd/extds/IscDS.h b/src/jrd/extds/IscDS.h index 9b4a43adb5..24fab0826c 100644 --- a/src/jrd/extds/IscDS.h +++ b/src/jrd/extds/IscDS.h @@ -508,7 +508,6 @@ public: virtual void attach(Jrd::thread_db *tdbb, const Firebird::string &dbName, const Firebird::string &user, const Firebird::string &pwd); - virtual void detach(Jrd::thread_db *tdbb); virtual bool isAvailable(Jrd::thread_db *tdbb, TraScope traScope) const; @@ -519,6 +518,7 @@ public: protected: virtual Transaction* doCreateTransaction(); virtual Statement* doCreateStatement(); + virtual void doDetach(Jrd::thread_db *tdbb); IscProvider& m_iscProvider; FB_API_HANDLE m_handle; diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 8a613315f6..88802dad7e 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -5580,9 +5580,13 @@ static void purge_attachment(thread_db* tdbb, } } + const bool wasShuttingDown = engineShuttingDown; try { + // allow to free resources used by dynamic statements + engineShuttingDown = false; EDS::Manager::jrdAttachmentEnd(tdbb, attachment); + engineShuttingDown = wasShuttingDown; const ULONG att_flags = attachment->att_flags; attachment->att_flags |= ATT_shutdown; @@ -5601,6 +5605,7 @@ static void purge_attachment(thread_db* tdbb, } catch (const Exception&) { + engineShuttingDown = wasShuttingDown; attachment->att_flags |= (ATT_shutdown | ATT_purge_error); throw; }