Skip to content

Commit ca9f68f

Browse files
asfernandesdyemanov
authored andcommitted
Postfix for #7989 - Improve performance of external (UDR) functions (#8046)
* Postfix for #7989 - Improve performance of external (UDR) functions. * Extract common functions. * Fix profiler request time for external functions. * Change cancellation detection for external functions. * Move new private code to anonymous namesapce and rename functions.
1 parent e6c5cda commit ca9f68f

File tree

4 files changed

+200
-59
lines changed

4 files changed

+200
-59
lines changed

src/dsql/ExprNodes.cpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13567,20 +13567,7 @@ dsc* UdfCallNode::execute(thread_db* tdbb, Request* request) const
1356713567

1356813568
funcRequest->setGmtTimeStamp(request->getGmtTimeStamp());
1356913569

13570-
if (function->fun_external)
13571-
{
13572-
function->fun_external->execute(
13573-
tdbb, funcRequest, transaction, inMsgLength, inMsg, outMsgLength, outMsg);
13574-
}
13575-
else
13576-
{
13577-
EXE_start(tdbb, funcRequest, transaction);
13578-
13579-
if (inMsgLength != 0)
13580-
EXE_send(tdbb, funcRequest, 0, inMsgLength, inMsg);
13581-
13582-
EXE_receive(tdbb, funcRequest, 1, outMsgLength, outMsg);
13583-
}
13570+
EXE_execute_function(tdbb, funcRequest, transaction, inMsgLength, inMsg, outMsgLength, outMsg);
1358413571

1358513572
// Clean up all savepoints started during execution of the function
1358613573

src/jrd/ExtEngineManager.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -898,11 +898,6 @@ ExtEngineManager::Function::~Function()
898898
void ExtEngineManager::Function::execute(thread_db* tdbb, Request* request, jrd_tra* transaction,
899899
unsigned inMsgLength, UCHAR* inMsg, unsigned outMsgLength, UCHAR* outMsg) const
900900
{
901-
AutoSetRestore2<Request*, thread_db> autoSetRequest(
902-
tdbb, &thread_db::getRequest, &thread_db::setRequest, request);
903-
904-
EXE_activate(tdbb, request, transaction);
905-
906901
fb_assert(inMsgLength == udf->getInputFormat()->fmt_length);
907902
fb_assert(outMsgLength == udf->getOutputFormat()->fmt_length);
908903

src/jrd/exe.cpp

Lines changed: 197 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ string StatusXcp::as_text() const
253253
}
254254

255255

256+
static void activate_request(thread_db* tdbb, Request* request, jrd_tra* transaction);
256257
static void execute_looper(thread_db*, Request*, jrd_tra*, const StmtNode*, Request::req_s);
257258
static void looper_seh(thread_db*, Request*, const StmtNode*);
258259
static void release_blobs(thread_db*, Request*);
@@ -262,6 +263,56 @@ static void stuff_stack_trace(const Request*);
262263
const size_t MAX_STACK_TRACE = 2048;
263264

264265

266+
namespace
267+
{
268+
void forgetSavepoint(thread_db* tdbb, Request* request, jrd_tra* transaction, SavNumber savNumber);
269+
SavNumber startSavepoint(Request* request, jrd_tra* transaction);
270+
271+
void forgetSavepoint(thread_db* tdbb, Request* request, jrd_tra* transaction, SavNumber savNumber)
272+
{
273+
while (transaction->tra_save_point &&
274+
transaction->tra_save_point->getNumber() >= savNumber)
275+
{
276+
const auto savepoint = transaction->tra_save_point;
277+
// Forget about any undo for this verb
278+
fb_assert(!transaction->tra_save_point->isChanging());
279+
transaction->releaseSavepoint(tdbb);
280+
// Preserve savepoint for reuse
281+
fb_assert(savepoint == transaction->tra_save_free);
282+
transaction->tra_save_free = savepoint->moveToStack(request->req_savepoints);
283+
fb_assert(savepoint != transaction->tra_save_free);
284+
285+
// Ensure that the priorly existing savepoints are preserved,
286+
// e.g. 10-11-12-(5-6-7) where savNumber == 5. This may happen
287+
// due to looper savepoints being reused in subsequent invokations.
288+
if (savepoint->getNumber() == savNumber)
289+
break;
290+
}
291+
}
292+
293+
SavNumber startSavepoint(Request* request, jrd_tra* transaction)
294+
{
295+
if (!(request->req_flags & req_proc_fetch) && request->req_transaction)
296+
{
297+
if (transaction && !(transaction->tra_flags & TRA_system))
298+
{
299+
if (request->req_savepoints)
300+
{
301+
request->req_savepoints =
302+
request->req_savepoints->moveToStack(transaction->tra_save_point);
303+
}
304+
else
305+
transaction->startSavepoint();
306+
307+
return transaction->tra_save_point->getNumber();
308+
}
309+
}
310+
311+
return 0;
312+
}
313+
} // anonymous namespace
314+
315+
265316
// Perform an assignment.
266317
void EXE_assignment(thread_db* tdbb, const AssignmentNode* node)
267318
{
@@ -850,7 +901,7 @@ void EXE_send(thread_db* tdbb, Request* request, USHORT msg, ULONG length, const
850901

851902

852903
// Mark a request as active.
853-
void EXE_activate(thread_db* tdbb, Request* request, jrd_tra* transaction)
904+
static void activate_request(thread_db* tdbb, Request* request, jrd_tra* transaction)
854905
{
855906
SET_TDBB(tdbb);
856907

@@ -918,10 +969,151 @@ void EXE_activate(thread_db* tdbb, Request* request, jrd_tra* transaction)
918969
}
919970

920971

972+
// Execute function. A shortcut for node-based function but required for external functions.
973+
void EXE_execute_function(thread_db* tdbb, Request* request, jrd_tra* transaction,
974+
ULONG inMsgLength, UCHAR* inMsg, ULONG outMsgLength, UCHAR* outMsg)
975+
{
976+
if (const auto function = request->getStatement()->function; function && function->fun_external)
977+
{
978+
activate_request(tdbb, request, transaction);
979+
980+
const auto attachment = tdbb->getAttachment();
981+
982+
// Ensure the cancellation lock can be triggered
983+
const auto lock = attachment->att_cancel_lock;
984+
if (lock && lock->lck_logical == LCK_none)
985+
LCK_lock(tdbb, lock, LCK_SR, LCK_WAIT);
986+
987+
const SavNumber savNumber = startSavepoint(request, transaction);
988+
989+
if (!request->req_transaction)
990+
ERR_post(Arg::Gds(isc_req_no_trans));
991+
992+
try
993+
{
994+
// Save the old pool and request to restore on exit
995+
StmtNode::ExeState exeState(tdbb, request, request->req_transaction);
996+
Jrd::ContextPoolHolder context(tdbb, request->req_pool);
997+
998+
fb_assert(!request->req_caller);
999+
request->req_caller = exeState.oldRequest;
1000+
1001+
tdbb->tdbb_flags &= ~(TDBB_stack_trace_done | TDBB_sys_error);
1002+
1003+
// Execute stuff until we drop
1004+
1005+
const auto profilerManager = attachment->isProfilerActive() && !request->hasInternalStatement() ?
1006+
attachment->getProfilerManager(tdbb) : nullptr;
1007+
const SINT64 profilerInitialTicks = profilerManager ? profilerManager->queryTicks() : 0;
1008+
const SINT64 profilerInitialAccumulatedOverhead = profilerManager ?
1009+
profilerManager->getAccumulatedOverhead() : 0;
1010+
1011+
try
1012+
{
1013+
function->fun_external->execute(tdbb, request, transaction, inMsgLength, inMsg, outMsgLength, outMsg);
1014+
1015+
tdbb->checkCancelState();
1016+
}
1017+
catch (const Exception& ex)
1018+
{
1019+
ex.stuffException(tdbb->tdbb_status_vector);
1020+
1021+
request->adjustCallerStats();
1022+
1023+
// Ensure the transaction hasn't disappeared in the meantime
1024+
fb_assert(request->req_transaction);
1025+
1026+
// If the database is already bug-checked, then get out
1027+
if (tdbb->getDatabase()->dbb_flags & DBB_bugcheck)
1028+
status_exception::raise(tdbb->tdbb_status_vector);
1029+
1030+
exeState.errorPending = true;
1031+
1032+
if (!(tdbb->tdbb_flags & TDBB_stack_trace_done) && !(tdbb->tdbb_flags & TDBB_sys_error))
1033+
{
1034+
stuff_stack_trace(request);
1035+
tdbb->tdbb_flags |= TDBB_stack_trace_done;
1036+
}
1037+
}
1038+
1039+
if (profilerInitialTicks && attachment->isProfilerActive())
1040+
{
1041+
const SINT64 currentProfilerTicks = profilerManager->queryTicks();
1042+
const SINT64 elapsedTicks = profilerManager->getElapsedTicksAndAdjustOverhead(
1043+
currentProfilerTicks, profilerInitialTicks, profilerInitialAccumulatedOverhead);
1044+
1045+
request->req_profiler_ticks += elapsedTicks;
1046+
}
1047+
1048+
request->adjustCallerStats();
1049+
1050+
if (!exeState.errorPending)
1051+
TRA_release_request_snapshot(tdbb, request);
1052+
1053+
request->req_flags &= ~(req_active | req_reserved);
1054+
request->invalidateTimeStamp();
1055+
1056+
if (profilerInitialTicks && attachment->isProfilerActive())
1057+
{
1058+
ProfilerManager::Stats stats(request->req_profiler_ticks);
1059+
profilerManager->onRequestFinish(request, stats);
1060+
}
1061+
1062+
fb_assert(request->req_caller == exeState.oldRequest);
1063+
request->req_caller = nullptr;
1064+
1065+
// Ensure the transaction hasn't disappeared in the meantime
1066+
fb_assert(request->req_transaction);
1067+
1068+
// In the case of a pending error condition (one which did not
1069+
// result in a exception to the top of looper), we need to
1070+
// release the request snapshot
1071+
1072+
if (exeState.errorPending)
1073+
{
1074+
TRA_release_request_snapshot(tdbb, request);
1075+
ERR_punt();
1076+
}
1077+
1078+
if (request->req_flags & req_abort)
1079+
ERR_post(Arg::Gds(isc_req_sync));
1080+
}
1081+
catch (const Exception&)
1082+
{
1083+
// In the case of error, undo changes performed under our savepoint
1084+
1085+
if (savNumber)
1086+
transaction->rollbackToSavepoint(tdbb, savNumber);
1087+
1088+
throw;
1089+
}
1090+
1091+
// If any requested modify/delete/insert ops have completed, forget them
1092+
1093+
if (savNumber)
1094+
{
1095+
// There should be no other savepoint but the one started by ourselves.
1096+
fb_assert(transaction->tra_save_point && transaction->tra_save_point->getNumber() == savNumber);
1097+
1098+
forgetSavepoint(tdbb, request, transaction, savNumber);
1099+
}
1100+
}
1101+
else
1102+
{
1103+
EXE_start(tdbb, request, transaction);
1104+
1105+
if (inMsgLength != 0)
1106+
EXE_send(tdbb, request, 0, inMsgLength, inMsg);
1107+
1108+
EXE_receive(tdbb, request, 1, outMsgLength, outMsg);
1109+
}
1110+
}
1111+
1112+
9211113
// Start and execute a request.
9221114
void EXE_start(thread_db* tdbb, Request* request, jrd_tra* transaction)
9231115
{
924-
EXE_activate(tdbb, request, transaction);
1116+
activate_request(tdbb, request, transaction);
9251117

9261118
execute_looper(tdbb, request, transaction, request->getStatement()->topNode, Request::req_evaluate);
9271119
}
@@ -1043,25 +1235,7 @@ static void execute_looper(thread_db* tdbb,
10431235
if (lock && lock->lck_logical == LCK_none)
10441236
LCK_lock(tdbb, lock, LCK_SR, LCK_WAIT);
10451237

1046-
// Start a save point
1047-
1048-
SavNumber savNumber = 0;
1049-
1050-
if (!(request->req_flags & req_proc_fetch) && request->req_transaction)
1051-
{
1052-
if (transaction && !(transaction->tra_flags & TRA_system))
1053-
{
1054-
if (request->req_savepoints)
1055-
{
1056-
request->req_savepoints =
1057-
request->req_savepoints->moveToStack(transaction->tra_save_point);
1058-
}
1059-
else
1060-
transaction->startSavepoint();
1061-
1062-
savNumber = transaction->tra_save_point->getNumber();
1063-
}
1064-
}
1238+
const SavNumber savNumber = startSavepoint(request, transaction);
10651239

10661240
request->req_flags &= ~req_stall;
10671241
request->req_operation = next_state;
@@ -1090,24 +1264,7 @@ static void execute_looper(thread_db* tdbb,
10901264
(transaction->tra_save_point &&
10911265
transaction->tra_save_point->getNumber() == savNumber));
10921266

1093-
while (transaction->tra_save_point &&
1094-
transaction->tra_save_point->getNumber() >= savNumber)
1095-
{
1096-
const auto savepoint = transaction->tra_save_point;
1097-
// Forget about any undo for this verb
1098-
fb_assert(!transaction->tra_save_point->isChanging());
1099-
transaction->releaseSavepoint(tdbb);
1100-
// Preserve savepoint for reuse
1101-
fb_assert(savepoint == transaction->tra_save_free);
1102-
transaction->tra_save_free = savepoint->moveToStack(request->req_savepoints);
1103-
fb_assert(savepoint != transaction->tra_save_free);
1104-
1105-
// Ensure that the priorly existing savepoints are preserved,
1106-
// e.g. 10-11-12-(5-6-7) where savNumber == 5. This may happen
1107-
// due to looper savepoints being reused in subsequent invokations.
1108-
if (savepoint->getNumber() == savNumber)
1109-
break;
1110-
}
1267+
forgetSavepoint(tdbb, request, transaction, savNumber);
11111268
}
11121269
}
11131270

@@ -1357,6 +1514,7 @@ bool EXE_get_stack_trace(const Request* request, string& sTrace)
13571514
return sTrace.hasData();
13581515
}
13591516

1517+
13601518
static void stuff_stack_trace(const Request* request)
13611519
{
13621520
string sTrace;

src/jrd/exe_proto.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ void EXE_assignment(Jrd::thread_db* tdbb, const Jrd::ValueExprNode* to, dsc* fro
4040
void EXE_execute_db_triggers(Jrd::thread_db*, Jrd::jrd_tra*, enum TriggerAction);
4141
void EXE_execute_ddl_triggers(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction,
4242
bool preTriggers, int action);
43+
void EXE_execute_function(Jrd::thread_db* tdbb, Jrd::Request* request, Jrd::jrd_tra* transaction,
44+
ULONG inMsgLength, UCHAR* inMsg, ULONG outMsgLength, UCHAR* outMsg);
4345
bool EXE_get_stack_trace(const Jrd::Request* request, Firebird::string& sTrace);
4446

4547
const Jrd::StmtNode* EXE_looper(Jrd::thread_db* tdbb, Jrd::Request* request,
@@ -51,7 +53,6 @@ void EXE_execute_triggers(Jrd::thread_db*, Jrd::TrigVector**, Jrd::record_param*
5153
void EXE_receive(Jrd::thread_db*, Jrd::Request*, USHORT, ULONG, void*, bool = false);
5254
void EXE_release(Jrd::thread_db*, Jrd::Request*);
5355
void EXE_send(Jrd::thread_db*, Jrd::Request*, USHORT, ULONG, const void*);
54-
void EXE_activate(Jrd::thread_db*, Jrd::Request*, Jrd::jrd_tra*);
5556
void EXE_start(Jrd::thread_db*, Jrd::Request*, Jrd::jrd_tra*);
5657
void EXE_unwind(Jrd::thread_db*, Jrd::Request*);
5758

0 commit comments

Comments
 (0)