mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 12:43:03 +01:00
Backported fix for CORE-1439: DB corruption when killing posix CS
This commit is contained in:
parent
974df75779
commit
63e2610d3a
@ -844,66 +844,64 @@ ISC_STATUS callback_execute_immediate( ISC_STATUS* status,
|
||||
requests = 0;
|
||||
}
|
||||
|
||||
// 1. Locate why_db_handle, corresponding to jrd_database_handle
|
||||
YValve::Attachment* why_db_handle = 0;
|
||||
YValve::Transaction* why_trans_handle = 0;
|
||||
dsql_dbb* database = 0;
|
||||
|
||||
THREAD_EXIT();
|
||||
THD_MUTEX_LOCK (&databases_mutex);
|
||||
dsql_dbb* database;
|
||||
for (database = databases; database; database = database->dbb_next)
|
||||
try
|
||||
{
|
||||
if (WHY_translate_handle(database->dbb_database_handle)->handle.h_dbb == jrd_attachment_handle)
|
||||
// 1. Locate why_db_handle, corresponding to jrd_database_handle
|
||||
for (database = databases; database; database = database->dbb_next)
|
||||
{
|
||||
break;
|
||||
if (YValve::translate<YValve::Attachment>(&database->dbb_database_handle)->handle == jrd_attachment_handle)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (! database) {
|
||||
status[0] = isc_arg_gds;
|
||||
status[1] = isc_bad_db_handle;
|
||||
status[2] = isc_arg_end;
|
||||
THD_MUTEX_UNLOCK(&databases_mutex);
|
||||
THREAD_ENTER();
|
||||
return status[1];
|
||||
}
|
||||
WHY_DBB why_db_handle = WHY_translate_handle(database->dbb_database_handle);
|
||||
if (! database)
|
||||
{
|
||||
Firebird::status_exception::raise(isc_bad_db_handle, isc_arg_end);
|
||||
}
|
||||
why_db_handle = YValve::translate<YValve::Attachment>(&database->dbb_database_handle);
|
||||
|
||||
/* 2. Create why_trans_handle - it's new, but points to the same jrd
|
||||
transaction as original before callback. */
|
||||
WHY_TRA why_trans_handle = WHY_alloc_handle(why_db_handle->implementation, HANDLE_transaction);
|
||||
if (!why_trans_handle) {
|
||||
status[0] = isc_arg_gds;
|
||||
status[1] = isc_virmemexh;
|
||||
status[2] = isc_arg_end;
|
||||
// 2. Create why_trans_handle - it's new, but points to the same jrd
|
||||
// transaction as original before callback.
|
||||
why_trans_handle = new YValve::Transaction(jrd_transaction_handle, 0, why_db_handle);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
THD_MUTEX_UNLOCK(&databases_mutex);
|
||||
THREAD_ENTER();
|
||||
return status[1];
|
||||
return Firebird::stuff_exception(status, e);
|
||||
}
|
||||
why_trans_handle->handle.h_tra = jrd_transaction_handle;
|
||||
why_trans_handle->parent = why_db_handle;
|
||||
THD_MUTEX_UNLOCK (&databases_mutex);
|
||||
THREAD_ENTER();
|
||||
|
||||
|
||||
// 3. Call execute... function
|
||||
THD_MUTEX_UNLOCK (&databases_mutex);
|
||||
THREAD_ENTER();
|
||||
const ISC_STATUS rc = dsql8_execute_immediate_common(status,
|
||||
&database->dbb_database_handle, &why_trans_handle->public_handle,
|
||||
sql_operator.length(), sql_operator.c_str(),
|
||||
database->dbb_db_SQL_dialect,
|
||||
0, NULL, 0, 0, NULL, 0, NULL, 0, 0, NULL, requests);
|
||||
WHY_cleanup_transaction(why_trans_handle);
|
||||
WHY_free_handle(why_trans_handle->public_handle);
|
||||
delete why_trans_handle;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
WHY_DBB GetWhyAttachment (ISC_STATUS* status,
|
||||
Jrd::Attachment* jrd_attachment_handle)
|
||||
YValve::Attachment* GetWhyAttachment(ISC_STATUS* status,
|
||||
Jrd::Attachment* jrd_attachment_handle)
|
||||
{
|
||||
THREAD_EXIT();
|
||||
THD_MUTEX_LOCK (&databases_mutex);
|
||||
dsql_dbb* database;
|
||||
WHY_DBB db_handle = 0;
|
||||
YValve::Attachment* db_handle = 0;
|
||||
for (database = databases; database; database = database->dbb_next)
|
||||
{
|
||||
db_handle = WHY_translate_handle(database->dbb_database_handle);
|
||||
if (db_handle->handle.h_dbb == jrd_attachment_handle)
|
||||
db_handle = YValve::translate<YValve::Attachment>(&database->dbb_database_handle);
|
||||
if (db_handle->handle == jrd_attachment_handle)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -382,7 +382,7 @@ ISC_STATUS API_ROUTINE gds__create_database(ISC_STATUS* status_vector,
|
||||
|
||||
ISC_STATUS API_ROUTINE gds__database_cleanup(ISC_STATUS * status_vector,
|
||||
FB_API_HANDLE* db_handle,
|
||||
DatabaseCleanupRoutine *routine, void* arg)
|
||||
AttachmentCleanupRoutine* routine, void* arg)
|
||||
{
|
||||
|
||||
return isc_database_cleanup(status_vector, db_handle, routine, arg);
|
||||
|
@ -66,7 +66,7 @@ ISC_STATUS API_ROUTINE gds__create_database( ISC_STATUS*, SSHORT, const SCHAR*,
|
||||
FB_API_HANDLE*, SSHORT, const SCHAR*, SSHORT);
|
||||
|
||||
ISC_STATUS API_ROUTINE gds__database_cleanup(ISC_STATUS*, FB_API_HANDLE*,
|
||||
DatabaseCleanupRoutine*, void * );
|
||||
AttachmentCleanupRoutine*, void * );
|
||||
|
||||
ISC_STATUS API_ROUTINE gds__database_info(ISC_STATUS*, FB_API_HANDLE*, SSHORT,
|
||||
const SCHAR*, SSHORT, SCHAR*);
|
||||
|
@ -496,13 +496,9 @@ USHORT BLB_get_segment(thread_db* tdbb,
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->tdbb_database;
|
||||
|
||||
#ifdef SUPERSERVER
|
||||
|
||||
if (--tdbb->tdbb_quantum < 0)
|
||||
JRD_reschedule(tdbb, 0, true);
|
||||
|
||||
#endif
|
||||
|
||||
/* If we reached end of file, we're still there */
|
||||
|
||||
if (blob->blb_flags & BLB_eof)
|
||||
|
@ -3859,11 +3859,9 @@ static SLONG fast_load(thread_db* tdbb,
|
||||
pointers[level] = levelPointer;
|
||||
}
|
||||
|
||||
#ifdef SUPERSERVER
|
||||
if (--tdbb->tdbb_quantum < 0) {
|
||||
error = JRD_reschedule(tdbb, 0, false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// To finish up, put an end of level marker on the last bucket
|
||||
@ -6414,7 +6412,6 @@ static CONTENTS remove_leaf_node(thread_db* tdbb, index_insertion* insertion, WI
|
||||
} while (--l);
|
||||
}
|
||||
|
||||
#ifdef SUPERSERVER
|
||||
// Until deletion of duplicate nodes becomes efficient, limit
|
||||
// leaf level traversal by rescheduling.
|
||||
if (--tdbb->tdbb_quantum < 0) {
|
||||
@ -6423,7 +6420,6 @@ static CONTENTS remove_leaf_node(thread_db* tdbb, index_insertion* insertion, WI
|
||||
ERR_punt();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// If we've needed to search thru a significant number of pages, warn the
|
||||
|
@ -84,9 +84,10 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define CANCEL_OPERATION
|
||||
|
||||
#ifdef SUPERSERVER
|
||||
#define GOVERNOR
|
||||
#define CANCEL_OPERATION
|
||||
#define FB_ARCHITECTURE isc_info_db_class_server_access
|
||||
#else
|
||||
#define FB_ARCHITECTURE isc_info_db_class_classic_access
|
||||
|
@ -578,10 +578,8 @@ void EXE_receive(thread_db* tdbb,
|
||||
|
||||
DEV_BLKCHK(request, type_req);
|
||||
|
||||
#ifdef SUPERSERVER
|
||||
if (--tdbb->tdbb_quantum < 0)
|
||||
JRD_reschedule(tdbb, 0, true);
|
||||
#endif
|
||||
|
||||
jrd_tra* transaction = request->req_transaction;
|
||||
|
||||
@ -722,10 +720,8 @@ void EXE_send(thread_db* tdbb,
|
||||
SET_TDBB(tdbb);
|
||||
DEV_BLKCHK(request, type_req);
|
||||
|
||||
#ifdef SUPERSERVER
|
||||
if (--tdbb->tdbb_quantum < 0)
|
||||
JRD_reschedule(tdbb, 0, true);
|
||||
#endif
|
||||
|
||||
if (!(request->req_flags & req_active))
|
||||
ERR_post(isc_req_sync, isc_arg_end);
|
||||
@ -1630,16 +1626,12 @@ static jrd_nod* looper(thread_db* tdbb, jrd_req* request, jrd_nod* in_node)
|
||||
{
|
||||
try {
|
||||
|
||||
#ifdef SUPERSERVER
|
||||
|
||||
if (request->req_operation == jrd_req::req_evaluate &&
|
||||
(--tdbb->tdbb_quantum < 0))
|
||||
{
|
||||
JRD_reschedule(tdbb, 0, true);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_GDS_ALLOC) && FALSE
|
||||
int node_type = node->nod_type;
|
||||
#endif
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include "../jrd/jrd.h"
|
||||
#include "../jrd/tra.h"
|
||||
#include "../jrd/dsc.h"
|
||||
#include "../jrd/y_handle.h"
|
||||
#include "../jrd/thd.h"
|
||||
#include "../jrd/err_proto.h"
|
||||
#include "../jrd/mov_proto.h"
|
||||
@ -44,6 +43,7 @@
|
||||
#include "../jrd/thread_proto.h"
|
||||
#define WHY_NO_API
|
||||
#include "../jrd/why_proto.h"
|
||||
#include "../jrd/y_handle.h"
|
||||
|
||||
#include "../jrd/align.h"
|
||||
#include "../jrd/execute_statement.h"
|
||||
@ -53,8 +53,7 @@
|
||||
using namespace Jrd;
|
||||
using namespace Firebird;
|
||||
|
||||
WHY_DBB GetWhyAttachment(ISC_STATUS* status,
|
||||
Attachment* jrd_attachment_handle);
|
||||
YValve::Attachment* GetWhyAttachment(ISC_STATUS*, Attachment*);
|
||||
|
||||
static const SSHORT sqlType[] =
|
||||
{
|
||||
@ -112,19 +111,14 @@ void ExecuteStatement::Open(thread_db* tdbb, jrd_nod* sql, SSHORT nVars, bool Si
|
||||
memcpy(StartOfSqlOperator, SqlText.c_str(), sizeof(StartOfSqlOperator) - 1);
|
||||
StartOfSqlOperator[sizeof(StartOfSqlOperator) - 1] = 0;
|
||||
|
||||
WHY_DBB temp_dbb = GetWhyAttachment(tdbb->tdbb_status_vector,
|
||||
YValve::Attachment* temp_dbb = GetWhyAttachment(tdbb->tdbb_status_vector,
|
||||
tdbb->tdbb_attachment);
|
||||
if (!temp_dbb)
|
||||
ERR_punt();
|
||||
|
||||
Attachment = temp_dbb->public_handle;
|
||||
|
||||
WHY_TRA temp_tra = WHY_alloc_handle(temp_dbb->implementation, HANDLE_transaction);
|
||||
if (!temp_tra)
|
||||
ERR_post(isc_virmemexh, isc_arg_end);
|
||||
Transaction = temp_tra->public_handle;
|
||||
temp_tra->handle.h_tra = tdbb->tdbb_transaction;
|
||||
temp_tra->parent = temp_dbb;
|
||||
YValve::Transaction* temp_tra = new YValve::Transaction(tdbb->tdbb_transaction, &Transaction, temp_dbb);
|
||||
|
||||
Statement = 0;
|
||||
Sqlda = MakeSqlda(tdbb, nVars ? nVars : 1);
|
||||
@ -290,12 +284,9 @@ void ExecuteStatement::Close(thread_db* tdbb)
|
||||
delete[] p;
|
||||
Sqlda = 0;
|
||||
if (Transaction) {
|
||||
THREAD_EXIT();
|
||||
WHY_cleanup_transaction(WHY_translate_handle(Transaction));
|
||||
THREAD_ENTER();
|
||||
delete YValve::translate<YValve::Transaction>(&Transaction);
|
||||
Transaction = 0;
|
||||
}
|
||||
WHY_free_handle(Transaction);
|
||||
Transaction = 0;
|
||||
delete[] Buffer;
|
||||
Buffer = 0;
|
||||
}
|
||||
|
@ -488,10 +488,8 @@ void IDX_create_index(
|
||||
delete record;
|
||||
}
|
||||
|
||||
#ifdef SUPERSERVER
|
||||
if (--tdbb->tdbb_quantum < 0)
|
||||
cancel = JRD_reschedule(tdbb, 0, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
gc_record->rec_flags &= ~REC_gc_active;
|
||||
|
269
src/jrd/jrd.cpp
269
src/jrd/jrd.cpp
@ -4424,7 +4424,6 @@ void JRD_print_procedure_info(thread_db* tdbb, const char* mesg)
|
||||
#endif /* DEBUG_PROCS */
|
||||
|
||||
|
||||
#ifdef MULTI_THREAD
|
||||
bool JRD_reschedule(thread_db* tdbb, SLONG quantum, bool punt)
|
||||
{
|
||||
/**************************************
|
||||
@ -4439,9 +4438,10 @@ bool JRD_reschedule(thread_db* tdbb, SLONG quantum, bool punt)
|
||||
*
|
||||
**************************************/
|
||||
|
||||
/* Force garbage colletion activity to yield the
|
||||
processor in case client threads haven't had
|
||||
an opportunity to enter the scheduling queue. */
|
||||
#ifdef MULTI_THREAD
|
||||
// Force garbage collection activity to yield the
|
||||
// processor in case client threads haven't had
|
||||
// an opportunity to enter the scheduling queue.
|
||||
|
||||
if (!(tdbb->tdbb_flags & TDBB_sweeper))
|
||||
SCH_schedule();
|
||||
@ -4450,6 +4450,7 @@ bool JRD_reschedule(thread_db* tdbb, SLONG quantum, bool punt)
|
||||
THREAD_YIELD();
|
||||
THREAD_ENTER();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Test various flags and unwind/throw if required.
|
||||
// But do that only if we're not in the verb cleanup state,
|
||||
@ -4533,13 +4534,16 @@ bool JRD_reschedule(thread_db* tdbb, SLONG quantum, bool punt)
|
||||
}
|
||||
|
||||
tdbb->tdbb_quantum = (tdbb->tdbb_quantum <= 0) ?
|
||||
#ifdef MULTI_THREAD
|
||||
(quantum ? quantum : (ThreadPriorityScheduler::boosted() ?
|
||||
Config::getPriorityBoost() : 1) * QUANTUM) :
|
||||
#else
|
||||
(quantum ? quantum : QUANTUM) :
|
||||
#endif
|
||||
tdbb->tdbb_quantum;
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void JRD_restore_context(void)
|
||||
@ -5014,7 +5018,8 @@ static ISC_STATUS error(ISC_STATUS* user_status)
|
||||
use count is erroneously left set. */
|
||||
|
||||
#if (defined DEV_BUILD && !defined MULTI_THREAD)
|
||||
if (dbb && dbb->dbb_use_count && !(dbb->dbb_flags & DBB_security_db)) {
|
||||
if (dbb && dbb->dbb_use_count && !(dbb->dbb_flags & DBB_security_db))
|
||||
{
|
||||
dbb->dbb_use_count = 0;
|
||||
ISC_STATUS* p = user_status;
|
||||
*p++ = isc_arg_gds;
|
||||
@ -6123,6 +6128,129 @@ void JRD_set_cache_default(ULONG* num_ptr)
|
||||
}
|
||||
|
||||
|
||||
static ISC_STATUS shutdown_dbb(thread_db* tdbb, Database* dbb, Attachment** released)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* s h u t d o w n _ d b b
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* rollback every transaction,
|
||||
* release every attachment,
|
||||
* and shutdown database.
|
||||
*
|
||||
**************************************/
|
||||
if (!(dbb->dbb_flags & (DBB_bugcheck | DBB_not_in_use | DBB_security_db)) &&
|
||||
!(dbb->dbb_ast_flags & DBB_shutdown &&
|
||||
dbb->dbb_ast_flags & DBB_shutdown_locks))
|
||||
{
|
||||
Attachment* att_next;
|
||||
for (Attachment* attach = dbb->dbb_attachments; attach; attach = att_next)
|
||||
{
|
||||
att_next = attach->att_next;
|
||||
tdbb->tdbb_database = dbb;
|
||||
tdbb->tdbb_attachment = attach;
|
||||
tdbb->tdbb_request = NULL;
|
||||
tdbb->tdbb_transaction = NULL;
|
||||
tdbb->tdbb_flags |= TDBB_shutdown_manager;
|
||||
Jrd::ContextPoolHolder context(tdbb, 0);
|
||||
++dbb->dbb_use_count;
|
||||
|
||||
// purge_attachment() below can do an ERR_post
|
||||
ISC_STATUS_ARRAY user_status;
|
||||
tdbb->tdbb_status_vector = user_status;
|
||||
|
||||
try
|
||||
{
|
||||
// purge attachment, rollback any open transactions
|
||||
#if defined(V4_THREADING) && !defined(SUPERSERVER)
|
||||
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
|
||||
#endif
|
||||
purge_attachment(tdbb, user_status, attach, true);
|
||||
#if defined(V4_THREADING) && !defined(SUPERSERVER)
|
||||
V4_JRD_MUTEX_UNLOCK(databases_mutex);
|
||||
#endif
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
if (released)
|
||||
{
|
||||
*released = 0;
|
||||
}
|
||||
return error(user_status, ex);
|
||||
}
|
||||
|
||||
// attach became invalid pointer
|
||||
// if we have someone, intereted in that fact, inform him
|
||||
if (released)
|
||||
{
|
||||
*released++ = attach;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (released)
|
||||
{
|
||||
*released = 0;
|
||||
}
|
||||
return FB_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static ISC_STATUS shutdown_all()
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* s h u t d o w n _ a l l
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* rollback every transaction,
|
||||
* release every attachment,
|
||||
* and shutdown every database.
|
||||
*
|
||||
**************************************/
|
||||
THREAD_ENTER();
|
||||
// NOTE!!!
|
||||
// This routine doesn't contain THREAD_EXIT to help ensure
|
||||
// that no threads will get in and try to access the data
|
||||
// structures we released here
|
||||
|
||||
thread_db thd_context;
|
||||
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
|
||||
|
||||
if (initialized) {
|
||||
JRD_SS_MUTEX_LOCK;
|
||||
}
|
||||
|
||||
Database* dbb_next;
|
||||
for (Database* dbb = databases; dbb; dbb = dbb_next)
|
||||
{
|
||||
dbb_next = dbb->dbb_next;
|
||||
|
||||
ISC_STATUS rc = shutdown_dbb(tdbb, dbb, 0);
|
||||
if (rc != FB_SUCCESS)
|
||||
{
|
||||
if (initialized)
|
||||
{
|
||||
JRD_SS_MUTEX_UNLOCK;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
JRD_SS_MUTEX_UNLOCK;
|
||||
}
|
||||
|
||||
JRD_restore_context();
|
||||
|
||||
return FB_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#ifdef SERVER_SHUTDOWN
|
||||
TEXT* JRD_num_attachments(TEXT* const buf, USHORT buf_len, USHORT flag,
|
||||
USHORT* atts, USHORT* dbs)
|
||||
@ -6356,92 +6484,9 @@ static void ExtractDriveLetter(const TEXT* file_name, ULONG* drive_mask)
|
||||
#endif
|
||||
|
||||
|
||||
ISC_STATUS shutdown_all()
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* s h u t d o w n _ a l l
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* rollback every transaction,
|
||||
* release every attachment,
|
||||
* and shutdown every database.
|
||||
*
|
||||
**************************************/
|
||||
THREAD_ENTER();
|
||||
// NOTE!!!
|
||||
// This routine doesn't contain THREAD_EXIT to help ensure
|
||||
// that no threads will get in and try to access the data
|
||||
// structures we released here
|
||||
|
||||
thread_db thd_context;
|
||||
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
|
||||
|
||||
if (initialized) {
|
||||
JRD_SS_MUTEX_LOCK;
|
||||
}
|
||||
ISC_STATUS_ARRAY user_status;
|
||||
|
||||
Database* dbb_next;
|
||||
for (Database* dbb = databases; dbb; dbb = dbb_next)
|
||||
{
|
||||
dbb_next = dbb->dbb_next;
|
||||
if (!(dbb->dbb_flags & (DBB_bugcheck | DBB_not_in_use | DBB_security_db)) &&
|
||||
!(dbb->dbb_ast_flags & DBB_shutdown &&
|
||||
dbb->dbb_ast_flags & DBB_shutdown_locks))
|
||||
{
|
||||
Attachment* att_next;
|
||||
for (Attachment* attach = dbb->dbb_attachments; attach; attach = att_next)
|
||||
{
|
||||
att_next = attach->att_next;
|
||||
tdbb->tdbb_database = dbb;
|
||||
tdbb->tdbb_attachment = attach;
|
||||
tdbb->tdbb_request = NULL;
|
||||
tdbb->tdbb_transaction = NULL;
|
||||
tdbb->tdbb_flags |= TDBB_shutdown_manager;
|
||||
Jrd::ContextPoolHolder context(tdbb, 0);
|
||||
|
||||
++dbb->dbb_use_count;
|
||||
|
||||
/* purge_attachment below can do an ERR_post */
|
||||
|
||||
tdbb->tdbb_status_vector = user_status;
|
||||
|
||||
try {
|
||||
/* purge attachment, rollback any open transactions */
|
||||
|
||||
#if defined(V4_THREADING) && !defined(SUPERSERVER)
|
||||
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini);
|
||||
#endif
|
||||
purge_attachment(tdbb, user_status, attach, true);
|
||||
#if defined(V4_THREADING) && !defined(SUPERSERVER)
|
||||
V4_JRD_MUTEX_UNLOCK(databases_mutex);
|
||||
#endif
|
||||
} // try
|
||||
catch (const std::exception& ex) {
|
||||
if (initialized) {
|
||||
JRD_SS_MUTEX_UNLOCK;
|
||||
}
|
||||
return error(user_status, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
JRD_SS_MUTEX_UNLOCK;
|
||||
}
|
||||
|
||||
JRD_restore_context();
|
||||
|
||||
return FB_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#ifdef SUPERSERVER
|
||||
static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM arg) {
|
||||
static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM arg)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* s h u t d o w n _ t h r e a d
|
||||
@ -6476,9 +6521,9 @@ void JRD_shutdown_all(bool asyncMode)
|
||||
* asynchronous shutdown.
|
||||
*
|
||||
**************************************/
|
||||
#ifdef SUPERSERVER
|
||||
int flShutdownComplete = 0;
|
||||
|
||||
#ifdef SUPERSERVER
|
||||
if (asyncMode)
|
||||
{
|
||||
gds__thread_start(shutdown_thread, &flShutdownComplete,
|
||||
@ -6492,6 +6537,7 @@ void JRD_shutdown_all(bool asyncMode)
|
||||
}
|
||||
}
|
||||
else // sync mode
|
||||
#endif // SUPERSERVER
|
||||
{
|
||||
flShutdownComplete = (shutdown_all() == FB_SUCCESS);
|
||||
}
|
||||
@ -6500,8 +6546,45 @@ void JRD_shutdown_all(bool asyncMode)
|
||||
{
|
||||
gds__log("Forced server shutdown - not all databases closed");
|
||||
}
|
||||
#endif // SUPERSERVER
|
||||
}
|
||||
|
||||
#else // SERVER_SHUTDOWN
|
||||
|
||||
// This conditional compilation, though sitting under not
|
||||
// defined SERVER_SHUTDOWN, performs full or partial shutdown
|
||||
// of database. SERVER_SHUTDOWN defined controls some other
|
||||
// aspects of operation, therefore was left "as is".
|
||||
// Who wants to invent better naem for it, please do it.
|
||||
|
||||
void JRD_process_close()
|
||||
{
|
||||
shutdown_all();
|
||||
}
|
||||
|
||||
void JRD_database_close(Attachment** handle, Attachment** released)
|
||||
{
|
||||
THREAD_ENTER();
|
||||
thread_db thd_context;
|
||||
thread_db* tdbb = JRD_MAIN_set_thread_data(thd_context);
|
||||
|
||||
Database* dbb = databases;
|
||||
for (; dbb; dbb = dbb->dbb_next)
|
||||
{
|
||||
for (Attachment* attach = dbb->dbb_attachments; attach; attach = attach->att_next)
|
||||
{
|
||||
if (attach == *handle)
|
||||
{
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
found:
|
||||
// got dbb to be closed
|
||||
shutdown_dbb(tdbb, dbb, released);
|
||||
}
|
||||
|
||||
#endif /* SERVER_SHUTDOWN */
|
||||
|
||||
|
||||
|
@ -148,6 +148,9 @@ const USHORT JRD_info_dbnames = 2;
|
||||
|
||||
TEXT* JRD_num_attachments(TEXT* const, USHORT, USHORT, USHORT*, USHORT*);
|
||||
void JRD_shutdown_all(bool);
|
||||
#else /* SERVER_SHUTDOWN */
|
||||
void JRD_process_close();
|
||||
void JRD_database_close(Jrd::Attachment**, Jrd::Attachment**);
|
||||
#endif /* SERVER_SHUTDOWN */
|
||||
|
||||
void JRD_set_cache_default(ULONG *);
|
||||
|
@ -34,8 +34,8 @@ int ISC_kill(SLONG, SLONG, void *);
|
||||
#else
|
||||
// And that are functions to manage UNIX signals
|
||||
int ISC_kill(SLONG, SLONG);
|
||||
void ISC_signal(int, FPTR_VOID_PTR, void *);
|
||||
void ISC_signal_cancel(int, FPTR_VOID_PTR, void *);
|
||||
bool ISC_signal(int, FPTR_VOID_PTR, void *);
|
||||
void ISC_signal_cancel(int, FPTR_VOID_PTR, void *);
|
||||
#endif
|
||||
|
||||
void ISC_signal_init(void);
|
||||
|
@ -36,7 +36,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: isc_ipc.cpp,v 1.17.4.5 2008-08-28 06:37:33 alexpeshkoff Exp $ */
|
||||
/* $Id: isc_ipc.cpp,v 1.17.4.6 2008-09-15 11:25:41 alexpeshkoff Exp $ */
|
||||
|
||||
#include "firebird.h"
|
||||
#include <stdio.h>
|
||||
@ -128,7 +128,7 @@ static int volatile relay_pipe = 0;
|
||||
|
||||
|
||||
static void cleanup(void* arg);
|
||||
static void isc_signal2(int signal, FPTR_VOID handler, void* arg, ULONG);
|
||||
static bool isc_signal2(int signal, FPTR_VOID handler, void* arg, ULONG);
|
||||
static SLONG overflow_handler(void* arg);
|
||||
static SIG que_signal(int signal, FPTR_VOID handler, void* arg, int flags);
|
||||
|
||||
@ -242,6 +242,9 @@ int ISC_kill(SLONG pid, SLONG signal_number)
|
||||
* Notify somebody else.
|
||||
*
|
||||
**************************************/
|
||||
if (! pid)
|
||||
pid = getpid();
|
||||
|
||||
for (;;) {
|
||||
const int status = kill(pid, signal_number);
|
||||
|
||||
@ -302,7 +305,7 @@ int ISC_kill(SLONG pid, SLONG signal_number)
|
||||
}
|
||||
|
||||
|
||||
void ISC_signal(int signal_number, FPTR_VOID_PTR handler, void* arg)
|
||||
bool ISC_signal(int signal_number, FPTR_VOID_PTR handler, void* arg)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -314,11 +317,11 @@ void ISC_signal(int signal_number, FPTR_VOID_PTR handler, void* arg)
|
||||
* Multiplex multiple handers into single signal.
|
||||
*
|
||||
**************************************/
|
||||
isc_signal2(signal_number, reinterpret_cast<FPTR_VOID>(handler), arg, SIG_user);
|
||||
return isc_signal2(signal_number, reinterpret_cast<FPTR_VOID>(handler), arg, SIG_user);
|
||||
}
|
||||
|
||||
|
||||
static void isc_signal2(
|
||||
static bool isc_signal2(
|
||||
int signal_number,
|
||||
FPTR_VOID handler, void* arg, ULONG flags)
|
||||
{
|
||||
@ -334,6 +337,7 @@ static void isc_signal2(
|
||||
**************************************/
|
||||
|
||||
SIG sig;
|
||||
bool rc = false;
|
||||
|
||||
/* The signal handler needs the process id */
|
||||
if (!process_id)
|
||||
@ -377,6 +381,7 @@ static void isc_signal2(
|
||||
{
|
||||
que_signal(signal_number, reinterpret_cast<FPTR_VOID>(oact.sa_handler),
|
||||
NULL, SIG_client);
|
||||
rc = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -385,6 +390,8 @@ static void isc_signal2(
|
||||
que_signal(signal_number, handler, arg, flags);
|
||||
|
||||
THD_MUTEX_UNLOCK(&sig_mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1794,15 +1794,11 @@ static bool get_record(thread_db* tdbb,
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
#ifdef SUPERSERVER
|
||||
|
||||
if (--tdbb->tdbb_quantum < 0)
|
||||
{
|
||||
JRD_reschedule(tdbb, 0, true);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* check request flags for special processing */
|
||||
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
|
@ -821,10 +821,8 @@ static FETCH_CODE fetch_page(thread_db* tdbb,
|
||||
Database* dbb = tdbb->tdbb_database;
|
||||
CHECK_DBB(dbb);
|
||||
|
||||
#ifdef SUPERSERVER
|
||||
if (--tdbb->tdbb_quantum < 0)
|
||||
JRD_reschedule(tdbb, 0, true);
|
||||
#endif
|
||||
|
||||
window->win_page = page_number;
|
||||
window->win_flags = 0;
|
||||
|
@ -3607,14 +3607,12 @@ static void garbage_collect(thread_db* tdbb,
|
||||
if (rpb->rpb_record) {
|
||||
going.push(rpb->rpb_record);
|
||||
}
|
||||
#ifdef SUPERSERVER
|
||||
|
||||
/* Don't monopolize the server while chasing long
|
||||
back version chains. */
|
||||
|
||||
if (--tdbb->tdbb_quantum < 0) {
|
||||
JRD_reschedule(tdbb, 0, true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
BLB_garbage_collect(tdbb, going, staying, prior_page, rpb->rpb_relation);
|
||||
@ -4069,14 +4067,12 @@ static void list_staying(thread_db* tdbb, record_param* rpb, RecordStack& stayin
|
||||
break;
|
||||
}
|
||||
depth++;
|
||||
#ifdef SUPERSERVER
|
||||
|
||||
/* Don't monopolize the server while chasing long
|
||||
back version chains. */
|
||||
|
||||
if (--tdbb->tdbb_quantum < 0) {
|
||||
JRD_reschedule(tdbb, 0, true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (timed_out) {
|
||||
continue;
|
||||
|
4725
src/jrd/why.cpp
4725
src/jrd/why.cpp
File diff suppressed because it is too large
Load Diff
@ -255,8 +255,6 @@ SLONG API_ROUTINE isc_reset_fpe(USHORT);
|
||||
#endif /* JRD_IBASE_H */
|
||||
#endif /* WHY_NO_API */
|
||||
|
||||
typedef void DatabaseCleanupRoutine(FB_API_HANDLE*, void*);
|
||||
|
||||
#ifdef CANCEL_OPERATION
|
||||
#define CANCEL_disable 1
|
||||
#define CANCEL_enable 2
|
||||
@ -264,8 +262,11 @@ typedef void DatabaseCleanupRoutine(FB_API_HANDLE*, void*);
|
||||
ISC_STATUS API_ROUTINE gds__cancel_operation(ISC_STATUS*, FB_API_HANDLE*, USHORT);
|
||||
#endif
|
||||
|
||||
typedef void AttachmentCleanupRoutine(FB_API_HANDLE*, void*);
|
||||
typedef void TransactionCleanupRoutine(FB_API_HANDLE, void*);
|
||||
|
||||
ISC_STATUS API_ROUTINE isc_database_cleanup(ISC_STATUS*, FB_API_HANDLE*,
|
||||
DatabaseCleanupRoutine*, void*);
|
||||
AttachmentCleanupRoutine*, void*);
|
||||
int API_ROUTINE gds__disable_subsystem(TEXT*);
|
||||
int API_ROUTINE gds__enable_subsystem(TEXT*);
|
||||
|
||||
@ -275,7 +276,6 @@ ISC_STATUS gds__handle_cleanup(ISC_STATUS*, FB_API_HANDLE*);
|
||||
#define INTL_FUNCTION_OCTET_LENGTH 2
|
||||
ISC_STATUS API_ROUTINE gds__intl_function(ISC_STATUS*, FB_API_HANDLE*, USHORT, UCHAR, USHORT, const UCHAR*, USHORT*);
|
||||
|
||||
typedef void TransactionCleanupRoutine(FB_API_HANDLE, void*);
|
||||
ISC_STATUS API_ROUTINE gds__transaction_cleanup(ISC_STATUS*, FB_API_HANDLE*,
|
||||
TransactionCleanupRoutine*, void*);
|
||||
void WHY_cleanup_transaction(struct why_hndl* transaction);
|
||||
@ -290,9 +290,5 @@ BOOLEAN WHY_get_shutdown();
|
||||
} /* extern "C"*/
|
||||
#endif
|
||||
|
||||
struct why_hndl* WHY_alloc_handle(int implementation, int handle_type);
|
||||
struct why_hndl* WHY_translate_handle(FB_API_HANDLE handle);
|
||||
void WHY_free_handle(FB_API_HANDLE handle);
|
||||
|
||||
#endif // JRD_WHY_PROTO_H
|
||||
|
||||
|
@ -25,12 +25,15 @@
|
||||
#ifndef JRD_Y_HANDLE_H
|
||||
#define JRD_Y_HANDLE_H
|
||||
|
||||
/*
|
||||
* These definitions placed into separate file
|
||||
* to avoid multiple definition of struct why_hndl in why.cpp
|
||||
* and dsql.cpp
|
||||
*
|
||||
*/
|
||||
#include "../common/classes/alloc.h"
|
||||
#include "../common/classes/array.h"
|
||||
#include "../common/classes/fb_string.h"
|
||||
#include "../dsql/sqlda_pub.h"
|
||||
#include "../dsql/sqlda.h"
|
||||
#include "../jrd/thread_proto.h"
|
||||
|
||||
#include "gen/iberror.h"
|
||||
|
||||
|
||||
namespace Jrd {
|
||||
class Attachment;
|
||||
@ -38,52 +41,352 @@ namespace Jrd {
|
||||
class jrd_req;
|
||||
}
|
||||
|
||||
union any_handle {
|
||||
struct why_hndl* h_why;
|
||||
class dsql_req* h_dsql;
|
||||
Jrd::Attachment* h_dbb;
|
||||
Jrd::jrd_tra* h_tra;
|
||||
};
|
||||
class dsql_req;
|
||||
|
||||
struct why_hndl
|
||||
namespace YValve
|
||||
{
|
||||
UCHAR type;
|
||||
UCHAR flags;
|
||||
USHORT implementation;
|
||||
FB_API_HANDLE public_handle;
|
||||
union any_handle handle;
|
||||
struct why_hndl* parent;
|
||||
struct why_hndl* next;
|
||||
union {
|
||||
struct why_hndl* requests;
|
||||
struct sqlda_sup* das;
|
||||
// flags
|
||||
const UCHAR HANDLE_TRANSACTION_limbo = 1;
|
||||
const UCHAR HANDLE_BLOB_filter = 2; /* Blob is locally filtered */
|
||||
const UCHAR HANDLE_STATEMENT_local = 4; /* Process DSQL statement locally */
|
||||
const UCHAR HANDLE_STATEMENT_prepared = 8;
|
||||
const UCHAR HANDLE_shutdown = 0x10; // Database shutdown
|
||||
|
||||
// forwards
|
||||
class Attachment;
|
||||
class Transaction;
|
||||
class Request;
|
||||
class Blob;
|
||||
class Statement;
|
||||
class Service;
|
||||
|
||||
// force use of default memory pool for Y-Valve objects
|
||||
class DefaultMemory
|
||||
{
|
||||
public:
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return getDefaultMemoryPool()->allocate(size);
|
||||
}
|
||||
|
||||
void operator delete(void* mem)
|
||||
{
|
||||
getDefaultMemoryPool()->deallocate(mem);
|
||||
}
|
||||
};
|
||||
struct why_hndl* statements;
|
||||
struct why_hndl* blobs;
|
||||
FB_API_HANDLE* user_handle;
|
||||
struct clean* cleanup;
|
||||
TEXT* db_path;
|
||||
};
|
||||
|
||||
typedef why_hndl *WHY_HNDL;
|
||||
typedef why_hndl *WHY_REQ;
|
||||
typedef why_hndl *WHY_DBB;
|
||||
typedef why_hndl *WHY_TRA;
|
||||
typedef why_hndl *WHY_BLB;
|
||||
typedef why_hndl *WHY_ATT;
|
||||
typedef why_hndl *WHY_STMT;
|
||||
typedef why_hndl *WHY_SVC;
|
||||
// stored handle types
|
||||
typedef Jrd::jrd_tra StTra;
|
||||
typedef void StReq;
|
||||
typedef void StBlb;
|
||||
typedef Jrd::Attachment StAtt;
|
||||
typedef dsql_req StStm;
|
||||
typedef void StSvc;
|
||||
|
||||
const int HANDLE_invalid = 0;
|
||||
const int HANDLE_database = 1;
|
||||
const int HANDLE_transaction = 2;
|
||||
const int HANDLE_request = 3;
|
||||
const int HANDLE_blob = 4;
|
||||
const int HANDLE_statement = 5;
|
||||
const int HANDLE_service = 6;
|
||||
template <typename CleanupRoutine, typename CleanupArg>
|
||||
class Clean : public DefaultMemory
|
||||
{
|
||||
private:
|
||||
struct st_clean
|
||||
{
|
||||
CleanupRoutine *Routine;
|
||||
void* clean_arg;
|
||||
st_clean(CleanupRoutine *r, void* a)
|
||||
: Routine(r), clean_arg(a) { }
|
||||
st_clean()
|
||||
: Routine(0), clean_arg(0) { }
|
||||
};
|
||||
Firebird::HalfStaticArray<st_clean, 1> calls;
|
||||
|
||||
const int HANDLE_TRANSACTION_limbo = 1;
|
||||
const int HANDLE_BLOB_filter = 2; /* Blob is locally filtered */
|
||||
const int HANDLE_STATEMENT_local = 4; /* Process DSQL statement locally */
|
||||
public:
|
||||
Clean() : calls(*getDefaultMemoryPool()) { }
|
||||
|
||||
void add(CleanupRoutine *r, void* a)
|
||||
{
|
||||
for (size_t i = 0; i < calls.getCount(); ++i)
|
||||
{
|
||||
if (calls[i].Routine == r &&
|
||||
calls[i].clean_arg == a)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
calls.add(st_clean(r, a));
|
||||
}
|
||||
|
||||
void call(CleanupArg public_handle)
|
||||
{
|
||||
for (size_t i = 0; i < calls.getCount(); ++i)
|
||||
{
|
||||
if (calls[i].Routine)
|
||||
{
|
||||
THREAD_EXIT();
|
||||
calls[i].Routine(public_handle, calls[i].clean_arg);
|
||||
THREAD_ENTER();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Handle : public DefaultMemory
|
||||
{
|
||||
public:
|
||||
UCHAR type;
|
||||
UCHAR flags;
|
||||
USHORT implementation;
|
||||
FB_API_HANDLE public_handle;
|
||||
Attachment* parent;
|
||||
FB_API_HANDLE* user_handle;
|
||||
|
||||
protected:
|
||||
Handle(UCHAR t, FB_API_HANDLE* pub, Attachment* par, USHORT imp = ~0);
|
||||
|
||||
public:
|
||||
static Handle* translate(FB_API_HANDLE);
|
||||
Jrd::Attachment* getAttachmentHandle();
|
||||
void cancel();
|
||||
~Handle();
|
||||
|
||||
// required to put pointers to it into the tree
|
||||
static const FB_API_HANDLE& generate(const void* sender, Handle* value) {
|
||||
return value->public_handle;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename HType>
|
||||
void toParent(Firebird::SortedArray<HType*>& members, HType* newMember)
|
||||
{
|
||||
members.add(newMember);
|
||||
}
|
||||
|
||||
template <typename HType>
|
||||
void fromParent(Firebird::SortedArray<HType*>& members, HType* newMember)
|
||||
{
|
||||
size_t pos;
|
||||
if (members.find(newMember, pos))
|
||||
{
|
||||
members.remove(pos);
|
||||
}
|
||||
#ifdef DEV_BUILD
|
||||
else
|
||||
{
|
||||
//Attempt to deregister not registered member
|
||||
fb_assert(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename ToHandle>
|
||||
ToHandle* translate(FB_API_HANDLE* handle)
|
||||
{
|
||||
if (handle && *handle)
|
||||
{
|
||||
Handle* rc = Handle::translate(*handle);
|
||||
if (rc && rc->type == ToHandle::hType())
|
||||
{
|
||||
return reinterpret_cast<ToHandle*>(rc);
|
||||
}
|
||||
}
|
||||
|
||||
Firebird::status_exception::raise(ToHandle::hError(),
|
||||
isc_arg_end);
|
||||
// compiler warning silencer
|
||||
return 0;
|
||||
}
|
||||
|
||||
class Attachment : public Handle
|
||||
{
|
||||
public:
|
||||
Firebird::SortedArray<Transaction*> transactions;
|
||||
Firebird::SortedArray<Request*> requests;
|
||||
Firebird::SortedArray<Blob*> blobs;
|
||||
Firebird::SortedArray<Statement*> statements;
|
||||
|
||||
Clean<AttachmentCleanupRoutine, FB_API_HANDLE*> cleanup;
|
||||
StAtt* handle;
|
||||
Firebird::PathName db_path;
|
||||
|
||||
static ISC_STATUS hError()
|
||||
{
|
||||
return isc_bad_db_handle;
|
||||
}
|
||||
|
||||
static UCHAR hType()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public:
|
||||
Attachment(StAtt*, FB_API_HANDLE*, USHORT);
|
||||
void cancel2();
|
||||
~Attachment();
|
||||
};
|
||||
|
||||
class Transaction : public Handle
|
||||
{
|
||||
public:
|
||||
Clean<TransactionCleanupRoutine, FB_API_HANDLE> cleanup;
|
||||
Transaction* next;
|
||||
StTra* handle;
|
||||
|
||||
static ISC_STATUS hError()
|
||||
{
|
||||
return isc_bad_trans_handle;
|
||||
}
|
||||
|
||||
static UCHAR hType()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
public:
|
||||
Transaction(StTra* h, FB_API_HANDLE* pub, Attachment* par)
|
||||
: Handle(hType(), pub, par),
|
||||
next(0), handle(h)
|
||||
{
|
||||
toParent(parent->transactions, this);
|
||||
}
|
||||
|
||||
Transaction(FB_API_HANDLE* pub, USHORT implementation)
|
||||
: Handle(hType(), pub, 0, implementation),
|
||||
next(0), handle(0)
|
||||
{
|
||||
// toParent(parent->transactions, this);
|
||||
}
|
||||
|
||||
~Transaction()
|
||||
{
|
||||
cleanup.call(public_handle);
|
||||
if (parent)
|
||||
{
|
||||
fromParent(parent->transactions, this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Request : public Handle
|
||||
{
|
||||
public:
|
||||
StReq* handle;
|
||||
|
||||
static ISC_STATUS hError()
|
||||
{
|
||||
return isc_bad_req_handle;
|
||||
}
|
||||
|
||||
static UCHAR hType()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
public:
|
||||
Request(StReq* h, FB_API_HANDLE* pub, Attachment* par)
|
||||
: Handle(hType(), pub, par), handle(h)
|
||||
{
|
||||
toParent(parent->requests, this);
|
||||
}
|
||||
|
||||
~Request()
|
||||
{
|
||||
fromParent(parent->requests, this);
|
||||
}
|
||||
};
|
||||
|
||||
class Blob : public Handle
|
||||
{
|
||||
public:
|
||||
StBlb* handle;
|
||||
|
||||
static ISC_STATUS hError()
|
||||
{
|
||||
return isc_bad_segstr_handle;
|
||||
}
|
||||
|
||||
static UCHAR hType()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
public:
|
||||
Blob(StBlb* h, FB_API_HANDLE* pub, Attachment* par)
|
||||
: Handle(hType(), pub, par), handle(h)
|
||||
{
|
||||
toParent(parent->blobs, this);
|
||||
}
|
||||
|
||||
~Blob()
|
||||
{
|
||||
fromParent(parent->blobs, this);
|
||||
}
|
||||
};
|
||||
|
||||
class Statement : public Handle
|
||||
{
|
||||
public:
|
||||
StStm* handle;
|
||||
struct sqlda_sup das;
|
||||
|
||||
static ISC_STATUS hError()
|
||||
{
|
||||
return isc_bad_stmt_handle;
|
||||
}
|
||||
|
||||
static UCHAR hType()
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
public:
|
||||
Statement(StStm* h, FB_API_HANDLE* pub, Attachment* par)
|
||||
: Handle(hType(), pub, par), handle(h)
|
||||
{
|
||||
toParent(parent->statements, this);
|
||||
memset(&das, 0, sizeof das);
|
||||
}
|
||||
|
||||
void checkPrepared()
|
||||
{
|
||||
if (!(flags & HANDLE_STATEMENT_prepared))
|
||||
{
|
||||
Firebird::status_exception::raise(isc_unprepared_stmt, isc_arg_end);
|
||||
}
|
||||
}
|
||||
|
||||
~Statement()
|
||||
{
|
||||
fromParent(parent->statements, this);
|
||||
}
|
||||
};
|
||||
|
||||
class Service : public Handle
|
||||
{
|
||||
public:
|
||||
Clean<AttachmentCleanupRoutine, FB_API_HANDLE*> cleanup;
|
||||
StSvc* handle;
|
||||
|
||||
static ISC_STATUS hError()
|
||||
{
|
||||
return isc_bad_svc_handle;
|
||||
}
|
||||
|
||||
static UCHAR hType()
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
|
||||
public:
|
||||
Service(StSvc* h, FB_API_HANDLE* pub, USHORT impl)
|
||||
: Handle(hType(), pub, 0, impl), handle(h)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
~Service()
|
||||
{
|
||||
cleanup.call(&public_handle);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // JRD_Y_HANDLE_H
|
||||
|
@ -4429,6 +4429,15 @@ ISC_STATUS rem_port::send_response( PACKET* sendL,
|
||||
|
||||
this->send(sendL);
|
||||
|
||||
#ifndef SUPERSERVER
|
||||
// In case of CS remote listener we have a single connection system.
|
||||
// If database is shut down, it's no use running fb_inet_server any more.
|
||||
if (exit_code == isc_shutdown)
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user