On Fri, Jan 28, 2022 at 7:47 PM Andres Freund <and...@anarazel.de> wrote: > > On 2022-01-28 16:36:32 -0800, Andres Freund wrote: > > On 2022-01-28 18:43:57 -0500, James Coleman wrote: > > > Alternatively I see pg_attribute_aligned, but that's not defined > > > (AFAICT) on clang, for example, so I'm not sure that'd be acceptable? > > > > clang should have it (it defines __GNUC__). The problem would be msvc, I > > think. Not sure if there's a way to get to a common way of defining it > > between > > gcc-like compilers and msvc (the rest is niche enough that we don't need to > > care about the efficiency I think). > > Seems like it's doable: > > https://godbolt.org/z/3c5573bTW
Oh, thanks. I'd seen some discussion previously on the list about clang not supporting it, but that seems to have been incorrect. Also I didn't know about that compiler site -- that's really neat. Here's an updated patch series using that approach; the first patch can (and probably should be) committed separately/regardless to update the pg_attribute_aligned to be used in MSVC. Thanks, James Coleman
From c104bec6ed93cea06f4d5ff0f9150490f159dfaa Mon Sep 17 00:00:00 2001 From: jcoleman <jtc...@gmail.com> Date: Sat, 29 Jan 2022 11:28:45 -0500 Subject: [PATCH v4 1/2] Support pg_attribute_aligned in MSVC --- configure | 2 ++ src/include/c.h | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/configure b/configure index 3f2aea0d7d..e9ab674f38 100755 --- a/configure +++ b/configure @@ -17862,6 +17862,8 @@ else /* This must match the corresponding code in c.h: */ #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__) #define pg_attribute_aligned(a) __attribute__((aligned(a))) +#elif defined(_MSC_VER) +#define pg_attribute_aligned(a) __declspec(align(a)) #endif typedef __int128 int128a #if defined(pg_attribute_aligned) diff --git a/src/include/c.h b/src/include/c.h index 4f16e589b3..0441b031b4 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -179,6 +179,10 @@ #define pg_attribute_noreturn() #endif +#if defined(_MSC_VER) +#define pg_attribute_aligned(a) __declspec(align(a)) +#endif + /* * Use "pg_attribute_always_inline" in place of "inline" for functions that * we wish to force inlining of, even when the compiler's heuristics would -- 2.17.1
From 1f456c9f3976e49cc9be31878c5ad5d7eba5c1b6 Mon Sep 17 00:00:00 2001 From: jcoleman <jtc...@gmail.com> Date: Sat, 29 Jan 2022 12:18:45 -0500 Subject: [PATCH v4 2/2] Expose LSN of last commit via pg_last_committed_xact --- src/backend/access/transam/xact.c | 6 +++- src/backend/access/transam/xlogfuncs.c | 17 ++++++++++ src/backend/storage/ipc/procarray.c | 34 +++++++++++++++++++ src/include/access/transam.h | 2 ++ src/include/catalog/pg_proc.dat | 6 ++++ src/include/storage/proc.h | 10 ++++++ src/include/storage/procarray.h | 2 ++ .../test_misc/t/002_last_commit_lsn.pl | 31 +++++++++++++++++ 8 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/test/modules/test_misc/t/002_last_commit_lsn.pl diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index c9516e03fa..f2ae4b0667 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -1355,6 +1355,7 @@ RecordTransactionCommit(void) else { bool replorigin; + XLogRecPtr commit_lsn; /* * Are we using the replication origins feature? Or, in other words, @@ -1391,7 +1392,7 @@ RecordTransactionCommit(void) SetCurrentTransactionStopTimestamp(); - XactLogCommitRecord(xactStopTimestamp, + commit_lsn = XactLogCommitRecord(xactStopTimestamp, nchildren, children, nrels, rels, nmsgs, invalMessages, RelcacheInitFileInval, @@ -1419,6 +1420,7 @@ RecordTransactionCommit(void) TransactionTreeSetCommitTsData(xid, nchildren, children, replorigin_session_origin_timestamp, replorigin_session_origin); + MyProc->lastCommitLSN = commit_lsn; } /* @@ -5883,6 +5885,8 @@ xact_redo_commit(xl_xact_parsed_commit *parsed, TransactionTreeSetCommitTsData(xid, parsed->nsubxacts, parsed->subxacts, commit_time, origin_id); + MyProc->lastCommitLSN = lsn; + if (standbyState == STANDBY_DISABLED) { /* diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c index d8af5aad58..05ee661fc2 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -29,6 +29,7 @@ #include "replication/walreceiver.h" #include "storage/fd.h" #include "storage/ipc.h" +#include "storage/procarray.h" #include "storage/smgr.h" #include "utils/builtins.h" #include "utils/guc.h" @@ -425,6 +426,22 @@ pg_last_wal_replay_lsn(PG_FUNCTION_ARGS) PG_RETURN_LSN(recptr); } +/* + * pg_last_commit_lsn + * + * SQL-callable wrapper to obtain the lsn of the last commit. + */ +Datum +pg_last_commit_lsn(PG_FUNCTION_ARGS) +{ + XLogRecPtr lsn = GetLastCommitLSN(); + + if (lsn == InvalidXLogRecPtr) + PG_RETURN_NULL(); + else + PG_RETURN_DATUM(LSNGetDatum(lsn)); +} + /* * Compute an xlog file name and decimal byte offset given a WAL location, * such as is returned by pg_stop_backup() or pg_switch_wal(). diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 3be6040289..92586d1492 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -430,6 +430,7 @@ CreateSharedProcArray(void) procArray->replication_slot_xmin = InvalidTransactionId; procArray->replication_slot_catalog_xmin = InvalidTransactionId; ShmemVariableCache->xactCompletionCount = 1; + ShmemVariableCache->finishedProcsLastCommitLSN = InvalidXLogRecPtr; } allProcs = ProcGlobal->allProcs; @@ -580,6 +581,9 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid) /* Same with xactCompletionCount */ ShmemVariableCache->xactCompletionCount++; + if (proc->lastCommitLSN > ShmemVariableCache->finishedProcsLastCommitLSN) + ShmemVariableCache->finishedProcsLastCommitLSN = proc->lastCommitLSN; + ProcGlobal->xids[myoff] = InvalidTransactionId; ProcGlobal->subxidStates[myoff].overflowed = false; ProcGlobal->subxidStates[myoff].count = 0; @@ -3914,6 +3918,36 @@ ProcArrayGetReplicationSlotXmin(TransactionId *xmin, LWLockRelease(ProcArrayLock); } +/* + * GetLastCommitLSN + * + * Return LSN of the most recent COMMIT record written to WAL. + * + * For performance reasons we do not guarantee the result to be perfectly in + * line with current visibility. + */ +XLogRecPtr +GetLastCommitLSN(void) +{ + ProcArrayStruct *arrayP = procArray; + XLogRecPtr lsn; + int i; + + LWLockAcquire(ProcArrayLock, LW_SHARED); + lsn = ShmemVariableCache->finishedProcsLastCommitLSN; + for (i = 0; i < arrayP->numProcs; i++) + { + int pgprocno = arrayP->pgprocnos[i]; + PGPROC *proc = &allProcs[pgprocno]; + + if (proc->lastCommitLSN > lsn) + lsn = proc->lastCommitLSN; + } + LWLockRelease(ProcArrayLock); + + return lsn; +} + /* * XidCacheRemoveRunningXids * diff --git a/src/include/access/transam.h b/src/include/access/transam.h index 338dfca5a0..c53f2d3810 100644 --- a/src/include/access/transam.h +++ b/src/include/access/transam.h @@ -237,6 +237,8 @@ typedef struct VariableCacheData */ FullTransactionId latestCompletedXid; /* newest full XID that has * committed or aborted */ + /* */ + XLogRecPtr finishedProcsLastCommitLSN; /* * Number of top-level transactions with xids (i.e. which may have diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index d6bf1f3274..cdf73f3bd5 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -6164,6 +6164,12 @@ proargnames => '{xid,timestamp,roident}', prosrc => 'pg_last_committed_xact' }, +{ oid => '9861', + descr => 'get commit lsn of latest transaction commit', + proname => 'pg_last_commit_lsn', provolatile => 'v', + prorettype => 'pg_lsn', proargtypes => '', + prosrc => 'pg_last_commit_lsn' }, + { oid => '3537', descr => 'get identification of SQL object', proname => 'pg_describe_object', provolatile => 's', prorettype => 'text', proargtypes => 'oid oid int4', prosrc => 'pg_describe_object' }, diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index a58888f9e9..efaf6442f5 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -258,6 +258,16 @@ struct PGPROC PGPROC *lockGroupLeader; /* lock group leader, if I'm a member */ dlist_head lockGroupMembers; /* list of members, if I'm a leader */ dlist_node lockGroupLink; /* my member link, if I'm a member */ + + /* + * Last transaction metadata. + */ +#ifndef pg_attribute_aligned + char *pad[PG_CACHE_LINE_SIZE]; +#else + pg_attribute_aligned(PG_CACHE_LINE_SIZE) +#endif + XLogRecPtr lastCommitLSN; /* cache of last committed LSN */ }; /* NOTE: "typedef struct PGPROC PGPROC" appears in storage/lock.h. */ diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h index e03692053e..ec3baa29e8 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -94,4 +94,6 @@ extern void ProcArraySetReplicationSlotXmin(TransactionId xmin, extern void ProcArrayGetReplicationSlotXmin(TransactionId *xmin, TransactionId *catalog_xmin); +extern XLogRecPtr GetLastCommitLSN(void); + #endif /* PROCARRAY_H */ diff --git a/src/test/modules/test_misc/t/002_last_commit_lsn.pl b/src/test/modules/test_misc/t/002_last_commit_lsn.pl new file mode 100644 index 0000000000..f249326c6b --- /dev/null +++ b/src/test/modules/test_misc/t/002_last_commit_lsn.pl @@ -0,0 +1,31 @@ + +# Copyright (c) 2021-2022, PostgreSQL Global Development Group + +use strict; +use warnings; +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More tests => 2; + +# Initialize a test cluster +my $node = PostgreSQL::Test::Cluster->new('primary'); +$node->init(); +$node->start; + +my ($ret, $before_lsn, $after_lsn); + +$ret = $node->safe_psql('postgres', 'SELECT pg_last_commit_lsn()'); +is($ret, '', 'null at startup'); + +$node->safe_psql('postgres', qq[CREATE TABLE t(i integer);]); + +$before_lsn = $node->safe_psql('postgres', 'SELECT pg_current_wal_lsn()'); +$node->safe_psql('postgres', 'INSERT INTO t(i) VALUES (1)'); +$after_lsn = $node->safe_psql('postgres', 'SELECT pg_current_wal_lsn()'); + +$ret = $node->safe_psql('postgres', qq[ + SELECT pg_last_commit_lsn() BETWEEN '$before_lsn'::pg_lsn AND '$after_lsn'::pg_lsn +]); +is($ret, 't', 'last commit lsn is set'); + +$node->stop('fast'); -- 2.17.1