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

Fix for #7147: Problems with use of big timeout (or no timeout at all) in trace service (#7148)

This commit is contained in:
Alexander Peshkov 2022-06-22 18:01:29 +03:00 committed by AlexPeshkoff
parent e9d0c3c382
commit 5d0fd12985
11 changed files with 188 additions and 25 deletions

View File

@ -717,6 +717,9 @@ interface Service : ReferenceCounted
version: // 3.0.7 => 3.0.8, 4.0.0 => 4.0.1
[notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedDetach(status) endif]
void detach(Status status);
version: // 3.0.9 => 3.0.10, 4.0.1 => 4.0.2
void cancel(Status status);
}
interface Provider : PluginBase

View File

@ -2714,6 +2714,7 @@ namespace Firebird
void (CLOOP_CARG *query)(IService* self, IStatus* status, unsigned sendLength, const unsigned char* sendItems, unsigned receiveLength, const unsigned char* receiveItems, unsigned bufferLength, unsigned char* buffer) throw();
void (CLOOP_CARG *start)(IService* self, IStatus* status, unsigned spbLength, const unsigned char* spb) throw();
void (CLOOP_CARG *detach)(IService* self, IStatus* status) throw();
void (CLOOP_CARG *cancel)(IService* self, IStatus* status) throw();
};
protected:
@ -2727,7 +2728,7 @@ namespace Firebird
}
public:
static const unsigned VERSION = 4;
static const unsigned VERSION = 5;
template <typename StatusType> void deprecatedDetach(StatusType* status)
{
@ -2767,6 +2768,19 @@ namespace Firebird
static_cast<VTable*>(this->cloopVTable)->detach(this, status);
StatusType::checkException(status);
}
template <typename StatusType> void cancel(StatusType* status)
{
if (cloopVTable->version < 5)
{
StatusType::setVersionError(status, "IService", cloopVTable->version, 5);
StatusType::checkException(status);
return;
}
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->cancel(this, status);
StatusType::checkException(status);
}
};
class IProvider : public IPluginBase
@ -11460,6 +11474,7 @@ namespace Firebird
this->query = &Name::cloopqueryDispatcher;
this->start = &Name::cloopstartDispatcher;
this->detach = &Name::cloopdetachDispatcher;
this->cancel = &Name::cloopcancelDispatcher;
}
} vTable;
@ -11522,6 +11537,20 @@ namespace Firebird
}
}
static void CLOOP_CARG cloopcancelDispatcher(IService* self, IStatus* status) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::cancel(&status2);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw()
{
try
@ -11565,6 +11594,7 @@ namespace Firebird
virtual void query(StatusType* status, unsigned sendLength, const unsigned char* sendItems, unsigned receiveLength, const unsigned char* receiveItems, unsigned bufferLength, unsigned char* buffer) = 0;
virtual void start(StatusType* status, unsigned spbLength, const unsigned char* spb) = 0;
virtual void detach(StatusType* status) = 0;
virtual void cancel(StatusType* status) = 0;
};
template <typename Name, typename StatusType, typename Base>

View File

@ -414,6 +414,7 @@ type
IService_queryPtr = procedure(this: IService; status: IStatus; sendLength: Cardinal; sendItems: BytePtr; receiveLength: Cardinal; receiveItems: BytePtr; bufferLength: Cardinal; buffer: BytePtr); cdecl;
IService_startPtr = procedure(this: IService; status: IStatus; spbLength: Cardinal; spb: BytePtr); cdecl;
IService_detachPtr = procedure(this: IService; status: IStatus); cdecl;
IService_cancelPtr = procedure(this: IService; status: IStatus); cdecl;
IProvider_attachDatabasePtr = function(this: IProvider; status: IStatus; fileName: PAnsiChar; dpbLength: Cardinal; dpb: BytePtr): IAttachment; cdecl;
IProvider_createDatabasePtr = function(this: IProvider; status: IStatus; fileName: PAnsiChar; dpbLength: Cardinal; dpb: BytePtr): IAttachment; cdecl;
IProvider_attachServiceManagerPtr = function(this: IProvider; status: IStatus; service: PAnsiChar; spbLength: Cardinal; spb: BytePtr): IService; cdecl;
@ -1817,15 +1818,17 @@ type
query: IService_queryPtr;
start: IService_startPtr;
detach: IService_detachPtr;
cancel: IService_cancelPtr;
end;
IService = class(IReferenceCounted)
const VERSION = 4;
const VERSION = 5;
procedure deprecatedDetach(status: IStatus);
procedure query(status: IStatus; sendLength: Cardinal; sendItems: BytePtr; receiveLength: Cardinal; receiveItems: BytePtr; bufferLength: Cardinal; buffer: BytePtr);
procedure start(status: IStatus; spbLength: Cardinal; spb: BytePtr);
procedure detach(status: IStatus);
procedure cancel(status: IStatus);
end;
IServiceImpl = class(IService)
@ -1837,6 +1840,7 @@ type
procedure query(status: IStatus; sendLength: Cardinal; sendItems: BytePtr; receiveLength: Cardinal; receiveItems: BytePtr; bufferLength: Cardinal; buffer: BytePtr); virtual; abstract;
procedure start(status: IStatus; spbLength: Cardinal; spb: BytePtr); virtual; abstract;
procedure detach(status: IStatus); virtual; abstract;
procedure cancel(status: IStatus); virtual; abstract;
end;
ProviderVTable = class(PluginBaseVTable)
@ -7085,6 +7089,17 @@ begin
FbException.checkException(status);
end;
procedure IService.cancel(status: IStatus);
begin
if (vTable.version < 5) then begin
FbException.setVersionError(status, 'IService', vTable.version, 5);
end
else begin
ServiceVTable(vTable).cancel(Self, status);
end;
FbException.checkException(status);
end;
function IProvider.attachDatabase(status: IStatus; fileName: PAnsiChar; dpbLength: Cardinal; dpb: BytePtr): IAttachment;
begin
Result := ProviderVTable(vTable).attachDatabase(Self, status, fileName, dpbLength, dpb);
@ -11307,6 +11322,15 @@ begin
end
end;
procedure IServiceImpl_cancelDispatcher(this: IService; status: IStatus); cdecl;
begin
try
IServiceImpl(this).cancel(status);
except
on e: Exception do FbException.catchException(status, e);
end
end;
var
IServiceImpl_vTable: ServiceVTable;
@ -15740,13 +15764,14 @@ initialization
IAttachmentImpl_vTable.dropDatabase := @IAttachmentImpl_dropDatabaseDispatcher;
IServiceImpl_vTable := ServiceVTable.create;
IServiceImpl_vTable.version := 4;
IServiceImpl_vTable.version := 5;
IServiceImpl_vTable.addRef := @IServiceImpl_addRefDispatcher;
IServiceImpl_vTable.release := @IServiceImpl_releaseDispatcher;
IServiceImpl_vTable.deprecatedDetach := @IServiceImpl_deprecatedDetachDispatcher;
IServiceImpl_vTable.query := @IServiceImpl_queryDispatcher;
IServiceImpl_vTable.start := @IServiceImpl_startDispatcher;
IServiceImpl_vTable.detach := @IServiceImpl_detachDispatcher;
IServiceImpl_vTable.cancel := @IServiceImpl_cancelDispatcher;
IProviderImpl_vTable := ProviderVTable.create;
IProviderImpl_vTable.version := 4;

View File

@ -506,6 +506,7 @@ public:
unsigned int bufferLength, unsigned char* buffer) override;
void start(Firebird::CheckStatusWrapper* status,
unsigned int spbLength, const unsigned char* spb) override;
void cancel(Firebird::CheckStatusWrapper* status) override;
public:
explicit JService(Jrd::Service* handle);

View File

@ -4407,6 +4407,26 @@ void JService::query(CheckStatusWrapper* user_status,
}
void JService::cancel(CheckStatusWrapper* user_status)
{
try
{
ThreadContextHolder tdbb(user_status);
validateHandle(svc);
svc->cancel(tdbb);
}
catch (const Exception& ex)
{
ex.stuffException(user_status);
return;
}
successful_completion(user_status);
}
void JService::start(CheckStatusWrapper* user_status, unsigned int spbLength, const unsigned char* spb)
{
/**************************************

View File

@ -688,7 +688,8 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d
svc_stdout_head(0), svc_stdout_tail(0), svc_service_run(NULL),
svc_resp_alloc(getPool()), svc_resp_buf(0), svc_resp_ptr(0), svc_resp_buf_len(0),
svc_resp_len(0), svc_flags(SVC_finished), svc_user_flag(0), svc_spb_version(0),
svc_do_shutdown(false), svc_shutdown_in_progress(false), svc_timeout(false),
svc_shutdown_server(false), svc_shutdown_request(false),
svc_shutdown_in_progress(false), svc_timeout(false),
svc_username(getPool()), svc_sql_role(getPool()), svc_auth_block(getPool()),
svc_expected_db(getPool()), svc_trusted_role(false), svc_utf8(false),
svc_switches(getPool()), svc_perm_sw(getPool()), svc_address_path(getPool()),
@ -864,7 +865,7 @@ void Service::detach()
}
// save it cause after call to finish() we can't access class members any more
const bool localDoShutdown = svc_do_shutdown;
const bool localDoShutdown = svc_shutdown_server;
if (svc_trace_manager->needs(ITraceFactory::TRACE_EVENT_SERVICE_DETACH))
{
@ -950,7 +951,7 @@ ULONG Service::totalCount()
bool Service::checkForShutdown()
{
if (svcShutdown)
if (svcShutdown || svc_shutdown_request)
{
if (svc_shutdown_in_progress)
{
@ -966,6 +967,20 @@ bool Service::checkForShutdown()
}
void Service::cancel(thread_db* /*tdbb*/)
{
svc_shutdown_request = true;
// signal once
if (!(svc_flags & SVC_finished))
svc_detach_sem.release();
if (svc_stdin_size_requested)
svc_stdin_semaphore.release();
svc_sem_full.release();
}
void Service::shutdownServices()
{
svcShutdown = true;
@ -1158,7 +1173,7 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/,
*info++ = item;
if (svc_user_flag & SVC_user_dba)
{
svc_do_shutdown = false;
svc_shutdown_server = false;
}
else
need_admin_privs(status, "isc_info_svc_svr_online");
@ -1168,7 +1183,7 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/,
*info++ = item;
if (svc_user_flag & SVC_user_dba)
{
svc_do_shutdown = true;
svc_shutdown_server = true;
}
else
need_admin_privs(status, "isc_info_svc_svr_offline");
@ -1613,7 +1628,7 @@ void Service::query(USHORT send_item_length,
*info++ = item;
if (svc_user_flag & SVC_user_dba)
{
svc_do_shutdown = false;
svc_shutdown_server = false;
*info++ = 0; // Success
}
else
@ -1624,7 +1639,7 @@ void Service::query(USHORT send_item_length,
*info++ = item;
if (svc_user_flag & SVC_user_dba)
{
svc_do_shutdown = true;
svc_shutdown_server = true;
*info++ = 0; // Success
}
else
@ -1937,6 +1952,9 @@ void Service::start(USHORT spb_length, const UCHAR* spb_data)
try
{
if (!svcShutdown)
svc_shutdown_request = svc_shutdown_in_progress = false;
ClumpletReader spb(ClumpletReader::SpbStart, spb_data, spb_length);
// The name of the service is the first element of the buffer

View File

@ -172,6 +172,8 @@ public: // external interface with service
const UCHAR* recv_items, USHORT buffer_length, UCHAR* info);
ISC_STATUS query2(thread_db* tdbb, USHORT send_item_length, const UCHAR* send_items,
USHORT recv_item_length, const UCHAR* recv_items, USHORT buffer_length, UCHAR* info);
// Cancel wait in query service
void cancel(thread_db* tdbb);
// Detach from service
void detach();
// get service version
@ -305,7 +307,8 @@ private:
USHORT svc_flags;
USHORT svc_user_flag;
USHORT svc_spb_version;
bool svc_do_shutdown;
bool svc_shutdown_server;
bool svc_shutdown_request;
bool svc_shutdown_in_progress;
bool svc_timeout;
char svc_arg_conv[MsgFormat::SAFEARG_MAX_ARG * 2];

View File

@ -151,6 +151,8 @@ namespace {
cstring* ptr;
cstring oldValue;
};
GlobalPtr<PortsCleanup> outPorts;
}
namespace Remote {
@ -936,6 +938,7 @@ public:
unsigned int receiveLength, const unsigned char* receiveItems,
unsigned int bufferLength, unsigned char* buffer) override;
void start(CheckStatusWrapper* status, unsigned int spbLength, const unsigned char* spb) override;
void cancel(CheckStatusWrapper* status) override;
public:
Service(Rdb* handle) : rdb(handle) { }
@ -998,6 +1001,15 @@ private:
void RProvider::shutdown(CheckStatusWrapper* status, unsigned int /*timeout*/, const int /*reason*/)
{
status->init();
try
{
outPorts->closePorts();
}
catch (const Exception& ex)
{
ex.stuffException(status);
}
}
void RProvider::setDbCryptCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback)
@ -1063,7 +1075,7 @@ static void batch_gds_receive(rem_port*, struct rmtque *, USHORT);
static void batch_dsql_fetch(rem_port*, struct rmtque *, USHORT);
static void clear_queue(rem_port*);
static void clear_stmt_que(rem_port*, Rsr*);
static void disconnect(rem_port*);
static void disconnect(rem_port*, bool rmRef = true);
static void enqueue_receive(rem_port*, t_rmtque_fn, Rdb*, void*, Rrq::rrq_repeat*);
static void dequeue_receive(rem_port*);
static THREAD_ENTRY_DECLARE event_thread(THREAD_ENTRY_PARAM);
@ -6435,6 +6447,28 @@ void Service::query(CheckStatusWrapper* status,
}
void Service::cancel(CheckStatusWrapper* status)
{
try
{
reset(status);
// Check and validate handles, etc.
CHECK_HANDLE(rdb, isc_bad_svc_handle);
/*
rem_port* port = rdb->rdb_port;
RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION);
*/
Arg::Gds(isc_wish_list).raise();
}
catch (const Exception& ex)
{
ex.stuffException(status);
}
}
void Service::start(CheckStatusWrapper* status,
unsigned int spbLength, const unsigned char* spb)
{
@ -7197,10 +7231,11 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned
}
catch (const Exception&)
{
disconnect(port);
disconnect(port, false);
throw;
}
outPorts->registerPort(port);
return port;
}
@ -7556,7 +7591,7 @@ static void clear_queue(rem_port* port)
}
static void disconnect( rem_port* port)
static void disconnect(rem_port* port, bool rmRef)
{
/**************************************
*
@ -7625,6 +7660,12 @@ static void disconnect( rem_port* port)
port->port_flags |= PORT_disconnect;
port->disconnect();
delete rdb;
port->port_context = nullptr;
// Remove from active ports
if (rmRef)
outPorts->unRegisterPort(port);
}

View File

@ -2681,23 +2681,28 @@ static void cancel_operation(rem_port* port, USHORT kind)
if ((port->port_flags & (PORT_async | PORT_disconnect)) || !(port->port_context))
return;
ServAttachment iface;
ServAttachment dbIface;
ServService svcIface;
{
RefMutexGuard portGuard(*port->port_cancel_sync, FB_FUNCTION);
Rdb* rdb;
if ((port->port_flags & PORT_disconnect) || !(rdb = port->port_context))
Rdb* rdb = port->port_context;
if ((port->port_flags & PORT_disconnect) || !rdb)
return;
iface = rdb->rdb_iface;
if (rdb->rdb_svc)
svcIface = rdb->rdb_svc->svc_iface;
else
dbIface = rdb->rdb_iface;
}
if (iface)
{
LocalStatus ls;
CheckStatusWrapper status_vector(&ls);
iface->cancelOperation(&status_vector, kind);
}
LocalStatus ls;
CheckStatusWrapper status_vector(&ls);
if (dbIface)
dbIface->cancelOperation(&status_vector, kind);
else if (svcIface && kind == fb_cancel_raise)
svcIface->cancel(&status_vector);
}
@ -5054,8 +5059,11 @@ static bool process_packet(rem_port* port, PACKET* sendL, PACKET* receive, rem_p
{
if (!port->port_parent)
{
if (!Worker::isShuttingDown() && !(port->port_flags & (PORT_rdb_shutdown | PORT_detached)))
if (!Worker::isShuttingDown() && !(port->port_flags & (PORT_rdb_shutdown | PORT_detached)) &&
((port->port_server_flags & (SRVR_server | SRVR_multi_client)) != SRVR_server))
{
gds__log("SERVER/process_packet: broken port, server exiting");
}
port->disconnect(sendL, receive);
return false;
}

View File

@ -613,6 +613,7 @@ public:
unsigned int bufferLength, unsigned char* buffer);
void start(Firebird::CheckStatusWrapper* status,
unsigned int spbLength, const unsigned char* spb);
void cancel(Firebird::CheckStatusWrapper* status);
public:
typedef Firebird::IService NextInterface;

View File

@ -6197,6 +6197,19 @@ void YService::query(CheckStatusWrapper* status, unsigned int sendLength, const
}
}
void YService::cancel(CheckStatusWrapper* status)
{
try
{
YEntry<YService> entry(status, this);
entry.next()->cancel(status);
}
catch (const Exception& e)
{
e.stuffException(status);
}
}
void YService::start(CheckStatusWrapper* status, unsigned int spbLength, const unsigned char* spbItems)
{
try