diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index bc2a2feb0b..fad49aba82 100644 --- a/doc/src/sgml/protocol.sgml +++ b/doc/src/sgml/protocol.sgml @@ -1315,6 +1315,17 @@ SELCT 1/0; channel name. + + When the parameter listen_transaction_id is enabled, at + the begining of a transaction (not a subtransaction) the backend sends a + NotificationResponse message containing the transaction ID on the + _my_transaction_id channel. This may be useful for the frontend to + use after a crash-recovery, to inspect the state of their transaction from + before the crash; see pg_xact_status(). Unlike other + NotificationResponse messaegs, the process ID in this message is the same as + that of the current backend. + + At present, NotificationResponse can only be sent outside a diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 441445927e..e80dfb3a7d 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -68,6 +68,8 @@ #include "utils/timeout.h" #include "utils/timestamp.h" +extern char *FullTransactionIdToStr(FullTransactionId fxid); + /* * User-tweakable parameters */ @@ -107,6 +109,7 @@ bool bsysscan = false; * XactTopFullTransactionId stores the XID of our toplevel transaction, which * will be the same as TopTransactionStateData.fullTransactionId in an * ordinary backend; but in a parallel backend, which does not have the entire + * ordinary backend; but in a parallel backend, which does not have the entire * transaction state, it will instead be copied from the backend that started * the parallel operation. * @@ -714,6 +717,21 @@ AssignTransactionId(TransactionState s) TopTransactionStateData.didLogXid = true; } } + + // NOTIFY FrontEnd, if it wants to know the top transaction's ID. + if (!isSubXact && listen_transaction_id) + { + char *xidStr; + + Assert(s->parent == NULL); + + // Should we Assert(!IsParallelWorker()) here? + + xidStr = FullTransactionIdToStr(s->fullTransactionId); + + NotifyMyFrontEnd("_my_transaction_id", xidStr, MyProcPid); + pfree(xidStr); + } } /* @@ -6005,7 +6023,7 @@ xact_redo(XLogReaderState *record) } else if (info == XLOG_XACT_COMMIT_PREPARED) { - xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record); + xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record); xl_xact_parsed_commit parsed; ParseCommitRecord(XLogRecGetInfo(record), xlrec, &parsed); diff --git a/src/backend/utils/adt/xid.c b/src/backend/utils/adt/xid.c index 24c1c93732..755cc53d36 100644 --- a/src/backend/utils/adt/xid.c +++ b/src/backend/utils/adt/xid.c @@ -161,13 +161,19 @@ xid8in(PG_FUNCTION_ARGS) PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(pg_strtouint64(str, NULL, 0))); } +char * +FullTransactionIdToStr(FullTransactionId fxid) +{ + char *result = (char *) palloc(21); + snprintf(result, 21, UINT64_FORMAT, U64FromFullTransactionId(fxid)); + return result; +} + Datum xid8out(PG_FUNCTION_ARGS) { FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0); - char *result = (char *) palloc(21); - - snprintf(result, 21, UINT64_FORMAT, U64FromFullTransactionId(fxid)); + char *result = FullTransactionIdToStr(fxid); PG_RETURN_CSTRING(result); } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 68b62d523d..1df14b9745 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -947,11 +947,21 @@ static const unit_conversion time_unit_conversion_table[] = * variable_is_guc_list_quote() in src/bin/pg_dump/dumputils.c. */ +bool listen_transaction_id = false; /******** option records follow ********/ static struct config_bool ConfigureNamesBool[] = { + { + {"listen_transaction_id", PGC_USERSET, UNGROUPED, + gettext_noop("Emit top-level transaction ID on transaction start."), + NULL + }, + &listen_transaction_id, + false, + NULL, NULL, NULL + }, { {"enable_seqscan", PGC_USERSET, QUERY_TUNING_METHOD, gettext_noop("Enables the planner's use of sequential-scan plans."), diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index a7c3a4958e..ed86a7a16d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -278,6 +278,8 @@ extern int tcp_keepalives_interval; extern int tcp_keepalives_count; extern int tcp_user_timeout; +extern bool listen_transaction_id; + #ifdef TRACE_SORT extern bool trace_sort; #endif