Skip to content

Commit d0f3e19

Browse files
committed
Add logic for ExecutorFinish + add test to check this logic. Some fixes for tests.
1 parent a2c8d89 commit d0f3e19

File tree

3 files changed

+82
-11
lines changed

3 files changed

+82
-11
lines changed

src/trace_execute_nodes.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ TraceExecProcNodeHook(PlanState *node)
188188

189189
clock_gettime(CLOCK_MONOTONIC, &time);
190190
startTime = time.tv_sec * 1000000000L + time.tv_nsec;
191-
nodeData->traceData.totalCalls++;
192191

193192
/* call real node */
194193
result = nodeData->traceData.execProcNode(node);
@@ -197,6 +196,7 @@ TraceExecProcNodeHook(PlanState *node)
197196

198197
clock_gettime(CLOCK_MONOTONIC, &time);
199198
timeDiff = time.tv_sec * 1000000000L + time.tv_nsec - startTime;
199+
nodeData->traceData.totalCalls++;
200200

201201
if (timeDiff > nodeData->traceData.maxTime)
202202
nodeData->traceData.maxTime = timeDiff;
@@ -315,7 +315,6 @@ TraceExprNodeHook(struct ExprState *expression, struct ExprContext *econtext, bo
315315

316316
clock_gettime(CLOCK_MONOTONIC, &time);
317317
startTime = time.tv_sec * 1000000000L + time.tv_nsec;
318-
exprData->traceData.totalCalls++;
319318

320319
/* call real node */
321320
result = exprData->traceData.evalfunc(expression, econtext, isNull);
@@ -324,6 +323,7 @@ TraceExprNodeHook(struct ExprState *expression, struct ExprContext *econtext, bo
324323

325324
clock_gettime(CLOCK_MONOTONIC, &time);
326325
timeDiff = time.tv_sec * 1000000000L + time.tv_nsec - startTime;
326+
exprData->traceData.totalCalls++;
327327

328328
if (timeDiff > exprData->traceData.maxTime)
329329
exprData->traceData.maxTime = timeDiff;

src/trace_session.c

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@
66
#include "utils/jsonb.h"
77
#include "utils/guc.h"
88
#include "commands/explain.h"
9-
#if PG_MAJORVERSION_NUM >= 18
10-
#include "commands/explain_state.h"
11-
#include "commands/explain_format.h"
12-
#endif
139
#include "storage/ipc.h"
1410
#include "storage/proc.h"
1511

@@ -33,13 +29,12 @@ static UprobeList *uprobesList = NULL;
3329

3430
static MemoryContext traceMemoryContext = NULL;
3531

32+
/* We need it in case that ListAdd fails and we need to delete this uprobe */
3633
static volatile Uprobe *lastSetUprobe = NULL;
3734

38-
/* we need it in case that ListAdd fails and we need to delete this uprobe */
39-
4035
static ExecutorRun_hook_type prev_ExecutorRun_hook = NULL;
41-
4236
static ExecutorStart_hook_type prev_ExecutorStart_hook = NULL;
37+
static ExecutorFinish_hook_type prev_ExecutorFinish_hook = NULL;
4338

4439
bool isExecuteTime = false;
4540

@@ -68,6 +63,7 @@ static void TraceSessionExecutorRun(QueryDesc *queryDesc,
6863
bool execute_once);
6964
#endif
7065
static void TraceSessionExecutorStart(QueryDesc *queryDesc, int eflags);
66+
static void TraceSessionExecutorFinish(QueryDesc *queryDesc);
7167
static char *ProcessDescBeforeExec(QueryDesc *queryDesc);
7268

7369
static UprobeList *MakeNodesPlanStringsText(char *startPlanExplain, char *endPlanExplain);
@@ -291,6 +287,8 @@ SessionTraceStart(void)
291287
ExecutorRun_hook = TraceSessionExecutorRun;
292288
prev_ExecutorStart_hook = ExecutorStart_hook;
293289
ExecutorStart_hook = TraceSessionExecutorStart;
290+
prev_ExecutorFinish_hook = ExecutorFinish_hook;
291+
ExecutorFinish_hook = TraceSessionExecutorFinish;
294292
}
295293
PG_CATCH();
296294
{
@@ -548,6 +546,62 @@ TraceSessionExecutorStart(QueryDesc *queryDesc, int eflags)
548546
}
549547

550548

549+
static void
550+
TraceSessionExecutorFinish(QueryDesc *queryDesc)
551+
{
552+
char *planCopy;
553+
struct timespec time;
554+
uint64 executionStarted;
555+
556+
/*No Executor nodes will be called, so no need for additional set up*/
557+
if (queryDesc->estate->es_auxmodifytables == NULL)
558+
{
559+
if (prev_ExecutorFinish_hook)
560+
(*prev_ExecutorFinish_hook) (queryDesc);
561+
else
562+
standard_ExecutorFinish(queryDesc);
563+
return;
564+
}
565+
566+
if (writeMode == JSON_WRITE_MODE && !isFirstNodeCall)
567+
{
568+
TracePrintf(",\n");
569+
}
570+
571+
planCopy = BeforeExecution(queryDesc);
572+
573+
clock_gettime(CLOCKTYPE, &time);
574+
executionStarted = time.tv_sec * 1000000000L + time.tv_nsec;
575+
576+
ExecutorRunNestLevel++;
577+
578+
PG_TRY();
579+
{
580+
if (prev_ExecutorFinish_hook)
581+
(*prev_ExecutorFinish_hook) (queryDesc);
582+
else
583+
standard_ExecutorFinish(queryDesc);
584+
}
585+
PG_FINALLY();
586+
{
587+
uint64 timeDiff;
588+
589+
ExecutorRunNestLevel--;
590+
591+
clock_gettime(CLOCKTYPE, &time);
592+
timeDiff = time.tv_sec * 1000000000L + time.tv_nsec - executionStarted;
593+
if (writeMode == TEXT_WRITE_MODE)
594+
TracePrintf("TRACE. Execution finished for %lu nanosec\n", timeDiff);
595+
else
596+
TracePrintf("\n],\n\"executionTime\": \"%lu nanosec\"\n", timeDiff);
597+
598+
AfterExecution(queryDesc, planCopy);
599+
isFirstNodeCall = false;
600+
}
601+
PG_END_TRY();
602+
}
603+
604+
551605
/* find the plan field in explain jsonb */
552606
static JsonbValue *
553607
FindField(JsonbValue *json, char *field, size_t len)

tests/test_trace_session.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ def trace_session_plpgsql_functions_exceptions(node: PostgresNode):
496496
start_session_trace(conn)
497497

498498
try:
499-
node.execute("SELECT process_complete_order(1, ARRAY[5,8], ARRAY[10, 5])")
499+
conn.execute("SELECT process_complete_order(1, ARRAY[5,8], ARRAY[10, 5])")
500500
except:
501501
pass
502502

@@ -506,6 +506,22 @@ def trace_session_plpgsql_functions_exceptions(node: PostgresNode):
506506
validate_each_session_trace_result(json.loads(result), conn.pid)
507507

508508

509+
def trace_session_correct_executor_finish(node: PostgresNode):
510+
with node.connect("postgres", autocommit=True) as conn:
511+
start_session_trace(conn)
512+
513+
node.execute("create table mlparted (a int, b int)")
514+
515+
node.execute("with ins (a, b, c) as \
516+
(insert into mlparted (b, a) select s.a, 1 from generate_series(2, 39) s(a) returning tableoid::regclass, *) \
517+
select a, b, min(c), max(c) from ins group by a, b order by 1;")
518+
519+
stop_session_trace(conn)
520+
521+
result = node_read_file_one_line(node, f"/pg_uprobe/trace_file.txt_{conn.pid}")
522+
validate_each_session_trace_result(json.loads(result), conn.pid)
523+
524+
509525
def run_tests(node: PostgresNode):
510526
test_wrapper(node, trace_current_session_trace)
511527
test_wrapper(node, trace_current_session_trace_non_sleep_buffer_locks)
@@ -520,4 +536,5 @@ def run_tests(node: PostgresNode):
520536
test_wrapper(node, trace_current_session_large)
521537
test_wrapper(node, trace_session_pid)
522538
test_wrapper(node, trace_session_plpgsql_functions)
523-
test_wrapper(node, trace_session_plpgsql_functions_exceptions)
539+
test_wrapper(node, trace_session_plpgsql_functions_exceptions)
540+
test_wrapper(node, trace_session_correct_executor_finish)

0 commit comments

Comments
 (0)