aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2018-01-05 12:17:10 -0300
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2018-01-05 12:17:10 -0300
commita19c262f3a013065429462c7a322eebf3f7e3771 (patch)
tree6897008983e8e844a23910662d30791aa5d4794b
parent0dc5dfcd7a7190739247a88c1c6249c75591effd (diff)
downloadpostgresql-a19c262f3a013065429462c7a322eebf3f7e3771.tar.gz
postgresql-a19c262f3a013065429462c7a322eebf3f7e3771.zip
Fix failure to delete spill files of aborted transactions
Logical decoding's reorderbuffer.c may spill transaction files to disk when transactions are large. These are supposed to be removed when they become "too old" by xid; but file removal requires the boundary LSNs of the transaction to be known. The final_lsn is only set when we see the commit or abort record for the transaction, but nothing sets the value for transactions that crash, so the removal code misbehaves -- in assertion-enabled builds, it crashes by a failed assertion. To fix, modify the final_lsn of transactions that don't have a value set, to the LSN of the very latest change in the transaction. This causes the spilled files to be removed appropriately. Author: Atsushi Torikoshi Reviewed-by: Kyotaro HORIGUCHI, Craig Ringer, Masahiko Sawada Discussion: https://postgr.es/m/54e4e488-186b-a056-6628-50628e4e4ebc@lab.ntt.co.jp
-rw-r--r--src/backend/replication/logical/reorderbuffer.c19
-rw-r--r--src/include/replication/reorderbuffer.h2
2 files changed, 19 insertions, 2 deletions
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 5567bee061d..ad651e3dfb7 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -1713,8 +1713,8 @@ ReorderBufferAbortOld(ReorderBuffer *rb, TransactionId oldestRunningXid)
* Iterate through all (potential) toplevel TXNs and abort all that are
* older than what possibly can be running. Once we've found the first
* that is alive we stop, there might be some that acquired an xid earlier
- * but started writing later, but it's unlikely and they will cleaned up
- * in a later call to ReorderBufferAbortOld().
+ * but started writing later, but it's unlikely and they will be cleaned
+ * up in a later call to this function.
*/
dlist_foreach_modify(it, &rb->toplevel_by_lsn)
{
@@ -1724,6 +1724,21 @@ 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 (txn->serialized && 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 */
diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h
index 86effe106bd..0fcd722b767 100644
--- a/src/include/replication/reorderbuffer.h
+++ b/src/include/replication/reorderbuffer.h
@@ -168,6 +168,8 @@ typedef struct ReorderBufferTXN
* * plain abort record
* * prepared transaction abort
* * error during decoding
+ * * for a crashed transaction, the LSN of the last change, regardless of
+ * what it was.
* ----
*/
XLogRecPtr final_lsn;