]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Set ReorderBufferTXN->final_lsn more eagerly
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Fri, 17 Jan 2020 21:00:39 +0000 (18:00 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Fri, 17 Jan 2020 21:00:39 +0000 (18:00 -0300)
... specifically, set it incrementally as each individual change is
spilled down to disk.  This way, it is set correctly when the
transaction disappears without trace, ie. without leaving an XACT_ABORT
wal record.  (This happens when the server crashes midway through a
transaction.)

Failing to have final_lsn prevents ReorderBufferRestoreCleanup() from
working, since it needs the final_lsn in order to know the endpoint of
its iteration through spilled files.

Commit df9f682c7bf8 already tried to fix the problem, but it didn't set
the final_lsn in all cases.  Revert that, since it's no longer needed.

Author: Vignesh C
Reviewed-by: Amit Kapila, Dilip Kumar
Discussion: https://postgr.es/m/CALDaNm2CLk+K9JDwjYST0sPbGg5AQdvhUt0jbKyX_HdAE0jk3A@mail.gmail.com

src/backend/replication/logical/reorderbuffer.c
src/include/replication/reorderbuffer.h

index bbd908af058d4e50fbe3358143def8bdb2173c28..73ca4f7884a0c36fb3ac79cc76a0252663d01a9c 100644 (file)
@@ -1974,21 +1974,6 @@ ReorderBufferAbortOld(ReorderBuffer *rb, TransactionId oldestRunningXid)
 
                if (TransactionIdPrecedes(txn->xid, oldestRunningXid))
                {
-                       /*
-                        * We set final_lsn on a transaction when we decode its commit or
-                        * abort record, but we never see those records for crashed
-                        * transactions.  To ensure cleanup of these transactions, set
-                        * final_lsn to that of their last change; this causes
-                        * ReorderBufferRestoreCleanup to do the right thing.
-                        */
-                       if (rbtxn_is_serialized(txn) && txn->final_lsn == 0)
-                       {
-                               ReorderBufferChange *last =
-                               dlist_tail_element(ReorderBufferChange, node, &txn->changes);
-
-                               txn->final_lsn = last->lsn;
-                       }
-
                        elog(DEBUG2, "aborting old transaction %u", txn->xid);
 
                        /* remove potential on-disk data, and deallocate this tx */
@@ -2623,8 +2608,7 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 
                                sz += sizeof(SnapshotData) +
                                        sizeof(TransactionId) * snap->xcnt +
-                                       sizeof(TransactionId) * snap->subxcnt
-                                       ;
+                                       sizeof(TransactionId) * snap->subxcnt;
 
                                /* make sure we have enough space */
                                ReorderBufferSerializeReserve(rb, sz);
@@ -2697,6 +2681,17 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
        }
        pgstat_report_wait_end();
 
+       /*
+        * Keep the transaction's final_lsn up to date with each change we send to
+        * disk, so that ReorderBufferRestoreCleanup works correctly.  (We used to
+        * only do this on commit and abort records, but that doesn't work if a
+        * system crash leaves a transaction without its abort record).
+        *
+        * Make sure not to move it backwards.
+        */
+       if (txn->final_lsn < change->lsn)
+               txn->final_lsn = change->lsn;
+
        Assert(ondisk->change.action == change->action);
 }
 
index 4f6c65d6f40618abe7f8624a90a98f3bfb3a17a9..626ecf4dc96aabc6ef3891e3bebcf3980192770d 100644 (file)
@@ -207,9 +207,10 @@ typedef struct ReorderBufferTXN
         * * prepared transaction commit
         * * plain abort record
         * * prepared transaction abort
-        * * error during decoding
-        * * for a crashed transaction, the LSN of the last change, regardless of
-        *   what it was.
+        *
+        * This can also become set to earlier values than transaction end when
+        * a transaction is spilled to disk; specifically it's set to the LSN of
+        * the latest change written to disk so far.
         * ----
         */
        XLogRecPtr      final_lsn;