On Thu, May 22, 2025 at 8:28 AM Zhijie Hou (Fujitsu) <houzj.f...@fujitsu.com> 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)