Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 40ad7eb

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 b7c5823 commit 40ad7eb

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
@@ -803,19 +803,17 @@ DecodeDelete(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
803803
if (target_node.dbNode != ctx->slot->data.database)
804804
return;
805805

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

817810
change = ReorderBufferGetChange(ctx->reorder);
818-
change->action = REORDER_BUFFER_CHANGE_DELETE;
811+
812+
if (xlrec->flags & XLH_DELETE_IS_SUPER)
813+
change->action = REORDER_BUFFER_CHANGE_INTERNAL_SPEC_ABORT;
814+
else
815+
change->action = REORDER_BUFFER_CHANGE_DELETE;
816+
819817
change->origin_id = XLogRecGetOrigin(r);
820818

821819
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
@@ -359,6 +359,9 @@ ReorderBufferReturnTXN(ReorderBuffer *rb, ReorderBufferTXN *txn)
359359
txn->invalidations = NULL;
360360
}
361361

362+
/* Reset the toast hash */
363+
ReorderBufferToastReset(rb, txn);
364+
362365
pfree(txn);
363366
}
364367

@@ -426,6 +429,7 @@ ReorderBufferReturnChange(ReorderBuffer *rb, ReorderBufferChange *change)
426429
}
427430
break;
428431
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_CONFIRM:
432+
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_ABORT:
429433
case REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID:
430434
case REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID:
431435
break;
@@ -1628,8 +1632,8 @@ ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid,
16281632
change_done:
16291633

16301634
/*
1631-
* Either speculative insertion was confirmed, or it was
1632-
* unsuccessful and the record isn't needed anymore.
1635+
* If speculative insertion was confirmed, the record isn't
1636+
* needed anymore.
16331637
*/
16341638
if (specinsert != NULL)
16351639
{
@@ -1703,6 +1707,32 @@ ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid,
17031707
break;
17041708
}
17051709

1710+
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_ABORT:
1711+
1712+
/*
1713+
* Abort for speculative insertion arrived. So cleanup the
1714+
* specinsert tuple and toast hash.
1715+
*
1716+
* Note that we get the spec abort change for each toast
1717+
* entry but we need to perform the cleanup only the first
1718+
* time we get it for the main table.
1719+
*/
1720+
if (specinsert != NULL)
1721+
{
1722+
/*
1723+
* We must clean the toast hash before processing a
1724+
* completely new tuple to avoid confusion about the
1725+
* previous tuple's toast chunks.
1726+
*/
1727+
Assert(change->data.tp.clear_toast_afterwards);
1728+
ReorderBufferToastReset(rb, txn);
1729+
1730+
/* We don't need this record anymore. */
1731+
ReorderBufferReturnChange(rb, specinsert);
1732+
specinsert = NULL;
1733+
}
1734+
break;
1735+
17061736
case REORDER_BUFFER_CHANGE_MESSAGE:
17071737
rb->message(rb, txn, change->lsn, true,
17081738
change->data.msg.prefix,
@@ -1778,16 +1808,8 @@ ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid,
17781808
}
17791809
}
17801810

1781-
/*
1782-
* There's a speculative insertion remaining, just clean in up, it
1783-
* can't have been successful, otherwise we'd gotten a confirmation
1784-
* record.
1785-
*/
1786-
if (specinsert)
1787-
{
1788-
ReorderBufferReturnChange(rb, specinsert);
1789-
specinsert = NULL;
1790-
}
1811+
/* speculative insertion record must be freed by now */
1812+
Assert(!specinsert);
17911813

17921814
/* clean up the iterator */
17931815
ReorderBufferIterTXNFinish(rb, iterstate);
@@ -2483,6 +2505,7 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
24832505
break;
24842506
}
24852507
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_CONFIRM:
2508+
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_ABORT:
24862509
case REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID:
24872510
case REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID:
24882511
/* ReorderBufferChange contains everything important */
@@ -2797,6 +2820,7 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
27972820
break;
27982821
}
27992822
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_CONFIRM:
2823+
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_ABORT:
28002824
case REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID:
28012825
case REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID:
28022826
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)