Skip to content

Commit 1f8a934

Browse files
author
Amit Kapila
committed
Fix decoding of speculative aborts.
During decoding for speculative inserts, we were relying for cleaning toast hash on confirmation records or next change records. But that could lead to multiple problems (a) memory leak if there is neither a confirmation record nor any other record after toast insertion for a speculative insert in the transaction, (b) error and assertion failures if the next operation is not an insert/update on the same table. The fix is to start queuing spec abort change and clean up toast hash and change record during its processing. Currently, we are queuing the spec aborts for both toast and main table even though we perform cleanup while processing the main table's spec abort record. Later, if we have a way to distinguish between the spec abort record of toast and the main table, we can avoid queuing the change for spec aborts of toast tables. Reported-by: Ashutosh Bapat Author: Dilip Kumar Reviewed-by: Amit Kapila Backpatch-through: 9.6, where it was introduced Discussion: https://postgr.es/m/CAExHW5sPKF-Oovx_qZe4p5oM6Dvof7_P+XgsNAViug15Fm99jA@mail.gmail.com
1 parent 73fa762 commit 1f8a934

File tree

3 files changed

+47
-24
lines changed

3 files changed

+47
-24
lines changed

src/backend/replication/logical/decode.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -804,19 +804,17 @@ DecodeDelete(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
804804
if (target_node.dbNode != ctx->slot->data.database)
805805
return;
806806

807-
/*
808-
* Super deletions are irrelevant for logical decoding, it's driven by the
809-
* confirmation records.
810-
*/
811-
if (xlrec->flags & XLH_DELETE_IS_SUPER)
812-
return;
813-
814807
/* output plugin doesn't look for this origin, no need to queue */
815808
if (FilterByOrigin(ctx, XLogRecGetOrigin(r)))
816809
return;
817810

818811
change = ReorderBufferGetChange(ctx->reorder);
819-
change->action = REORDER_BUFFER_CHANGE_DELETE;
812+
813+
if (xlrec->flags & XLH_DELETE_IS_SUPER)
814+
change->action = REORDER_BUFFER_CHANGE_INTERNAL_SPEC_ABORT;
815+
else
816+
change->action = REORDER_BUFFER_CHANGE_DELETE;
817+
820818
change->origin_id = XLogRecGetOrigin(r);
821819

822820
memcpy(&change->data.tp.relnode, &target_node, sizeof(RelFileNode));

src/backend/replication/logical/reorderbuffer.c

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,9 @@ ReorderBufferReturnTXN(ReorderBuffer *rb, ReorderBufferTXN *txn)
351351
txn->invalidations = NULL;
352352
}
353353

354+
/* Reset the toast hash */
355+
ReorderBufferToastReset(rb, txn);
356+
354357
pfree(txn);
355358
}
356359

@@ -418,6 +421,7 @@ ReorderBufferReturnChange(ReorderBuffer *rb, ReorderBufferChange *change)
418421
}
419422
break;
420423
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_CONFIRM:
424+
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_ABORT:
421425
case REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID:
422426
case REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID:
423427
break;
@@ -1620,8 +1624,8 @@ ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid,
16201624
change_done:
16211625

16221626
/*
1623-
* Either speculative insertion was confirmed, or it was
1624-
* unsuccessful and the record isn't needed anymore.
1627+
* If speculative insertion was confirmed, the record isn't
1628+
* needed anymore.
16251629
*/
16261630
if (specinsert != NULL)
16271631
{
@@ -1695,6 +1699,32 @@ ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid,
16951699
break;
16961700
}
16971701

1702+
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_ABORT:
1703+
1704+
/*
1705+
* Abort for speculative insertion arrived. So cleanup the
1706+
* specinsert tuple and toast hash.
1707+
*
1708+
* Note that we get the spec abort change for each toast
1709+
* entry but we need to perform the cleanup only the first
1710+
* time we get it for the main table.
1711+
*/
1712+
if (specinsert != NULL)
1713+
{
1714+
/*
1715+
* We must clean the toast hash before processing a
1716+
* completely new tuple to avoid confusion about the
1717+
* previous tuple's toast chunks.
1718+
*/
1719+
Assert(change->data.tp.clear_toast_afterwards);
1720+
ReorderBufferToastReset(rb, txn);
1721+
1722+
/* We don't need this record anymore. */
1723+
ReorderBufferReturnChange(rb, specinsert);
1724+
specinsert = NULL;
1725+
}
1726+
break;
1727+
16981728
case REORDER_BUFFER_CHANGE_MESSAGE:
16991729
rb->message(rb, txn, change->lsn, true,
17001730
change->data.msg.prefix,
@@ -1770,16 +1800,8 @@ ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid,
17701800
}
17711801
}
17721802

1773-
/*
1774-
* There's a speculative insertion remaining, just clean in up, it
1775-
* can't have been successful, otherwise we'd gotten a confirmation
1776-
* record.
1777-
*/
1778-
if (specinsert)
1779-
{
1780-
ReorderBufferReturnChange(rb, specinsert);
1781-
specinsert = NULL;
1782-
}
1803+
/* speculative insertion record must be freed by now */
1804+
Assert(!specinsert);
17831805

17841806
/* clean up the iterator */
17851807
ReorderBufferIterTXNFinish(rb, iterstate);
@@ -2475,6 +2497,7 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
24752497
break;
24762498
}
24772499
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_CONFIRM:
2500+
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_ABORT:
24782501
case REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID:
24792502
case REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID:
24802503
/* ReorderBufferChange contains everything important */
@@ -2778,6 +2801,7 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
27782801
break;
27792802
}
27802803
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_CONFIRM:
2804+
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_ABORT:
27812805
case REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID:
27822806
case REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID:
27832807
break;

src/include/replication/reorderbuffer.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ typedef struct ReorderBufferTupleBuf
4444
* changes. Users of the decoding facilities will never see changes with
4545
* *_INTERNAL_* actions.
4646
*
47-
* The INTERNAL_SPEC_INSERT and INTERNAL_SPEC_CONFIRM changes concern
48-
* "speculative insertions", and their confirmation respectively. They're
49-
* used by INSERT .. ON CONFLICT .. UPDATE. Users of logical decoding don't
50-
* have to care about these.
47+
* The INTERNAL_SPEC_INSERT and INTERNAL_SPEC_CONFIRM, and INTERNAL_SPEC_ABORT
48+
* changes concern "speculative insertions", their confirmation, and abort
49+
* respectively. They're used by INSERT .. ON CONFLICT .. UPDATE. Users of
50+
* logical decoding don't have to care about these.
5151
*/
5252
enum ReorderBufferChangeType
5353
{
@@ -60,6 +60,7 @@ enum ReorderBufferChangeType
6060
REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID,
6161
REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT,
6262
REORDER_BUFFER_CHANGE_INTERNAL_SPEC_CONFIRM,
63+
REORDER_BUFFER_CHANGE_INTERNAL_SPEC_ABORT,
6364
REORDER_BUFFER_CHANGE_TRUNCATE
6465
};
6566

0 commit comments

Comments
 (0)