On Thu, May 22, 2025 at 8:28 AM Zhijie Hou (Fujitsu)
<[email protected]> wrote:
>
> Attaching the V31 patch set which addressed comments in [1]~[8].
>
Few comments:
1.
<para>
+ The oldest transaction ID along that is currently in the commit
+ phase on the server, along with its epoch.
The first 'along' in the sentence looks redundant. I've removed this
in the attached.
2.
+ data.remote_oldestxid = FullTransactionIdFromU64(pq_getmsgint64(&s));
+ data.remote_nextxid = FullTransactionIdFromU64(pq_getmsgint64(&s));
Shouldn't we need to typecast the result of pq_getmsgint64(&s) with
uint64 as we do at similar other places in pg_snapshot_recv?
3.
+ pq_sendint64(&output_message,
U64FromFullTransactionId(fullOldestXidInCommit));
+ pq_sendint64(&output_message, U64FromFullTransactionId(nextFullXid));
Similarly, here also we should typecase with uint64
4.
+ * XXX In phase RCI_REQUEST_PUBLISHER_STATUS, a potential enhancement could be
+ * requesting transaction information specifically for those containing
+ * UPDATEs. However, this approach introduces additional complexities in
+ * tracking UPDATEs for transactions on the publisher, and it may not
+ * effectively address scenarios with frequent UPDATEs.
I think, as the patch needs the oldest_nonremovable_xid idea even to
detect update_origin_differs and delete_origin_differs reliably, as
mentioned in 0001's commit message, is it sufficient to track update
transactions? Don't we need to track it even for deletes? I have
removed this note for now and updated the comment to mention it is
required to detect update_origin_differs and delete_origin_differs
conflicts reliably.
Apart from the above comments, I made a few other cosmetic changes in
the attached.
--
With Regards,
Amit Kapila.
diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 7a40c62c59b..16d9171bf0d 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -2672,11 +2672,11 @@ psql "dbname=postgres replication=database" -c
"IDENTIFY_SYSTEM;"
<term>Int64</term>
<listitem>
<para>
- The oldest transaction ID along that is currently in the commit
- phase on the server, along with its epoch. The most significant 32
- bits are the epoch. The least significant 32 bits are the
- transaction ID. If no transactions are active on the server, this
- number will be the next transaction ID to be assigned.
+ The oldest transaction ID that is currently in the commit phase on
+ the server, along with its epoch. The most significant 32 bits are
+ the epoch. The least significant 32 bits are the transaction ID.
+ If no transactions are active on the server, this number will be
+ the next transaction ID to be assigned.
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/replication/logical/worker.c
b/src/backend/replication/logical/worker.c
index e9ca6c88e7e..6b9477bdf6a 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -309,17 +309,16 @@ typedef struct RetainConflictInfoData
* (RCI_WAIT_FOR_LOCAL_FLUSH) */
FullTransactionId candidate_xid; /* candidate for the
non-removable
* transaction ID */
+ TimestampTz flushpos_update_time; /* when the remote flush
position was
+
* updated in final phase
+
* (RCI_WAIT_FOR_LOCAL_FLUSH) */
/*
* The following fields are used to determine the timing for the next
round
- * of transaction ID advancement and the update of the remote flush
- * position.
+ * of transaction ID advancement.
*/
TimestampTz last_recv_time; /* when the last message was received */
TimestampTz candidate_xid_time; /* when the candidate_xid is decided */
- TimestampTz flushpos_update_time; /* when the remote flush
position was
-
* updated in final phase
-
* (RCI_WAIT_FOR_LOCAL_FLUSH) */
int xid_advance_interval; /* how much time (ms)
to wait before
* attempting to advance the
* non-removable transaction ID */
@@ -4051,7 +4050,10 @@ send_feedback(XLogRecPtr recvpos, bool force, bool
requestReply)
*
* The oldest_nonremovable_xid is maintained in shared memory to prevent dead
* rows from being removed prematurely when the apply worker still needs them
- * to detect update_deleted conflicts.
+ * to detect update_deleted conflicts. Additionally, this helps to retain
+ * the required commit_ts module information, which further helps to detect
+ * update_origin_differs and delete_origin_differs conflicts reliably, as
+ * otherwise, vacuum freeze could remove the required information.
*
* The non-removable transaction ID is advanced to the oldest running
* transaction ID once all concurrent transactions on the publisher have been
@@ -4106,12 +4108,6 @@ send_feedback(XLogRecPtr recvpos, bool force, bool
requestReply)
* subscriber. However, commit timestamps can regress since a commit with a
* later LSN is not guaranteed to have a later timestamp than those with
* earlier LSNs.
- *
- * XXX In phase RCI_REQUEST_PUBLISHER_STATUS, a potential enhancement could be
- * requesting transaction information specifically for those containing
- * UPDATEs. However, this approach introduces additional complexities in
- * tracking UPDATEs for transactions on the publisher, and it may not
- * effectively address scenarios with frequent UPDATEs.
*/
static void
maybe_advance_nonremovable_xid(RetainConflictInfoData *data,
@@ -4201,8 +4197,7 @@ get_candidate_xid(RetainConflictInfoData *data)
/*
* Immediately update the timer, even if the function returns later
without
- * setting candidate_xid due to inactivity on the subscriber. This
ensures
- * a certain interval before recalculating candidate_xid, minimizing
+ * setting candidate_xid due to inactivity on the subscriber. This
avoids
* frequent calls to GetOldestActiveTransactionId.
*/
data->candidate_xid_time = now;
@@ -4298,8 +4293,8 @@ wait_for_publisher_status(RetainConflictInfoData *data,
bool status_received)
* However, it requires maintaining two fields, last_remote_nextxid and
* last_remote_lsn, within the structure for comparison with the current
* cycle's values. Considering the minimal cost of continuing in
- * RCI_WAIT_FOR_LOCAL_FLUSH without awaiting changes, we opt not to
- * advance transaction ID in this case.
+ * RCI_WAIT_FOR_LOCAL_FLUSH without awaiting changes, we opted not to
+ * advance the transaction ID here.
*/
if (FullTransactionIdPrecedesOrEquals(data->last_phase_at,
data->remote_oldestxid))
@@ -4399,7 +4394,9 @@ wait_for_local_flush(RetainConflictInfoData *data)
/*
* Reset all data fields except those used to determine the timing for
the
- * next round of transaction ID advancement.
+ * next round of transaction ID advancement. We can even use
+ * flushpos_update_time in the next round to decide whether to get the
+ * latest flush position.
*/
data->phase = RCI_GET_CANDIDATE_XID;
data->remote_lsn = InvalidXLogRecPtr;
diff --git a/src/backend/storage/ipc/procarray.c
b/src/backend/storage/ipc/procarray.c
index c1d5ddbad4b..ce87f40e986 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -2876,8 +2876,8 @@ GetRunningTransactionData(void)
* simple as possible and leave GetSnapshotData() as the primary code for
* that bookkeeping.
*
- * If inCommitOnly is true, we target transactions currently in the commit
- * phase only.
+ * inCommitOnly indicates getting the oldestActiveXid among the transactions
+ * in the commit critical section.
*/
TransactionId
GetOldestActiveTransactionId(bool inCommitOnly)