postgres.git / summary / log / commit / refs
commit 3bdea167eb01491a4898e977d308508374e97bfa
Author: Andres Freund <andres@anarazel.de>
Date: Mon Jun 19 01:48:22 2017 +0000
Fix leaking of small spilled subtransactions during logical decoding.
When, during logical decoding, a transaction gets too big, it's
contents get spilled to disk. Not just the top-transaction gets
spilled, but *also* all of its subtransactions, even if they're not
that large themselves. Unfortunately we didn't clean up
such small spilled subtransactions from disk.
Fix that, by keeping better track of whether a transaction has been
spilled to disk.
Author: Andres Freund
Reported-By: Dmitriy Sarafannikov, FabrÃzio de Royes Mello
Discussion:
https://postgr.es/m/1457621358.355011041@f382.i.mail.ru
https://postgr.es/m/CAFcNs+qNMhNYii4nxpO6gqsndiyxNDYV0S=JNq0v_sEE+9PHXg@mail.gmail.com
Backpatch: 9.4-, where logical decoding was introduced
src/backend/replication/logical/reorderbuffer.c | 7 ++++---
src/include/replication/reorderbuffer.h | 9 +++++++++
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 524946a2a27..8f4f7f842bc 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -893,7 +893,7 @@ ReorderBufferIterTXNInit(ReorderBuffer *rb, ReorderBufferTXN *txn)
{
ReorderBufferChange *cur_change;
- if (txn->nentries != txn->nentries_mem)
+ if (txn->serialized)
{
/* serialize remaining changes */
ReorderBufferSerializeTXN(rb, txn);
@@ -922,7 +922,7 @@ ReorderBufferIterTXNInit(ReorderBuffer *rb, ReorderBufferTXN *txn)
{
ReorderBufferChange *cur_change;
- if (cur_txn->nentries != cur_txn->nentries_mem)
+ if (cur_txn->serialized)
{
/* serialize remaining changes */
ReorderBufferSerializeTXN(rb, cur_txn);
@@ -1142,7 +1142,7 @@ ReorderBufferCleanupTXN(ReorderBuffer *rb, ReorderBufferTXN *txn)
Assert(found);
/* remove entries spilled to disk */
- if (txn->nentries != txn->nentries_mem)
+ if (txn->serialized)
ReorderBufferRestoreCleanup(rb, txn);
/* deallocate */
@@ -2124,6 +2124,7 @@ ReorderBufferSerializeTXN(ReorderBuffer *rb, ReorderBufferTXN *txn)
Assert(spilled == txn->nentries_mem);
Assert(dlist_is_empty(&txn->changes));
txn->nentries_mem = 0;
+ txn->serialized = true;
if (fd != -1)
CloseTransientFile(fd);
diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h
index 17e47b385b7..8d8d418e8e3 100644
--- a/src/include/replication/reorderbuffer.h
+++ b/src/include/replication/reorderbuffer.h
@@ -212,6 +212,15 @@ typedef struct ReorderBufferTXN
*/
uint64 nentries_mem;
+ /*
+ * Has this transaction been spilled to disk? It's not always possible to
+ * deduce that fact by comparing nentries with nentries_mem, because
+ * e.g. subtransactions of a large transaction might get serialized
+ * together with the parent - if they're restored to memory they'd have
+ * nentries_mem == nentries.
+ */
+ bool serialized;
+
/*
* List of ReorderBufferChange structs, including new Snapshots and new
* CommandIds
[parent: b4166a8df914]