v4-PG17-0001-Avoid-distributing-invalidation-messages-sev.patch
application/octet-stream
Filename: v4-PG17-0001-Avoid-distributing-invalidation-messages-sev.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v4-0001
Subject: Avoid distributing invalidation messages several times
| File | + | − |
|---|---|---|
| src/backend/replication/logical/reorderbuffer.c | 298 | 69 |
| src/backend/replication/logical/snapbuild.c | 3 | 2 |
| src/include/replication/reorderbuffer.h | 6 | 0 |
From 82e688a1734cda5076ab1d6fdd5997f1e8cbe792 Mon Sep 17 00:00:00 2001
From: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Date: Wed, 21 May 2025 18:02:36 +0900
Subject: [PATCH v4-PG17] Avoid distributing invalidation messages several
times
---
.../replication/logical/reorderbuffer.c | 367 ++++++++++++++----
src/backend/replication/logical/snapbuild.c | 5 +-
src/include/replication/reorderbuffer.h | 6 +
3 files changed, 307 insertions(+), 71 deletions(-)
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 03eb005c39d..34c5dd88335 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -239,11 +239,30 @@ static void AssertTXNLsnOrder(ReorderBuffer *rb);
*/
static void ReorderBufferIterTXNInit(ReorderBuffer *rb, ReorderBufferTXN *txn,
ReorderBufferIterTXNState *volatile *iter_state);
+static void ReorderBufferIterTXNInitForInval(ReorderBuffer *rb,
+ ReorderBufferTXN *txn,
+ ReorderBufferIterTXNState *volatile *iter_state);
+static void ReorderBufferIterTXNInitInternal(ReorderBuffer *rb,
+ ReorderBufferTXN *txn,
+ ReorderBufferIterTXNState *volatile *iter_state,
+ bool iterate_inval);
+
static ReorderBufferChange *ReorderBufferIterTXNNext(ReorderBuffer *rb, ReorderBufferIterTXNState *state);
+static ReorderBufferChange *ReorderBufferIterTXNNextForInval(ReorderBuffer *rb, ReorderBufferIterTXNState *state);
+static ReorderBufferChange *ReorderBufferIterTXNNextInternal(ReorderBuffer *rb, ReorderBufferIterTXNState *state,
+ bool iterate_inval);
static void ReorderBufferIterTXNFinish(ReorderBuffer *rb,
ReorderBufferIterTXNState *state);
static void ReorderBufferExecuteInvalidations(uint32 nmsgs, SharedInvalidationMessage *msgs);
+static void ReorderBufferQueueChangeInternal(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn,
+ ReorderBufferChange *change, bool toast_insert,
+ bool for_inval);
+static void ReorderBufferExecuteInvalidationsInQueue(ReorderBuffer *rb, ReorderBufferTXN *txn);
+
+static void ReorderBufferQueueInval(ReorderBuffer *rb, TransactionId xid,
+ XLogRecPtr lsn, ReorderBufferChange *change);
+
/*
* ---------------------------------------
* Disk serialization support functions
@@ -428,6 +447,7 @@ ReorderBufferGetTXN(ReorderBuffer *rb)
dlist_init(&txn->changes);
dlist_init(&txn->tuplecids);
dlist_init(&txn->subtxns);
+ dlist_init(&txn->distributed_inval);
/* InvalidCommandId is not zero, so set it explicitly */
txn->command_id = InvalidCommandId;
@@ -787,6 +807,24 @@ ReorderBufferProcessPartialChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
void
ReorderBufferQueueChange(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn,
ReorderBufferChange *change, bool toast_insert)
+{
+ ReorderBufferQueueChangeInternal(rb, xid, lsn, change, toast_insert, false);
+}
+
+static void
+ReorderBufferQueueInval(ReorderBuffer *rb, TransactionId xid,
+ XLogRecPtr lsn, ReorderBufferChange *change)
+{
+ ReorderBufferQueueChangeInternal(rb, xid, lsn, change, false, true);
+}
+
+/*
+ * Actual workhorse for ReorderBufferQueueChange and ReorderBufferQueueInval
+ */
+static void
+ReorderBufferQueueChangeInternal(ReorderBuffer *rb, TransactionId xid,
+ XLogRecPtr lsn, ReorderBufferChange *change,
+ bool toast_insert, bool for_inval)
{
ReorderBufferTXN *txn;
@@ -797,7 +835,7 @@ ReorderBufferQueueChange(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn,
* transaction is aborted. So there is no point in collecting further
* changes for it.
*/
- if (txn->concurrent_abort)
+ if (!for_inval && txn->concurrent_abort)
{
/*
* We don't need to update memory accounting for this change as we
@@ -825,22 +863,84 @@ ReorderBufferQueueChange(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn,
}
change->lsn = lsn;
- change->txn = txn;
+
+ /*
+ * Associate the change with current transaction only if we are not
+ * distributing invalidation messages. Associated one has shorter
+ * lifetime than the target transaction, which may cause dangling
+ * link issues.
+ */
+ change->txn = for_inval ? NULL : txn;
Assert(InvalidXLogRecPtr != lsn);
- dlist_push_tail(&txn->changes, &change->node);
- txn->nentries++;
- txn->nentries_mem++;
- /* update memory accounting information */
- ReorderBufferChangeMemoryUpdate(rb, change, NULL, true,
- ReorderBufferChangeSize(change));
+ if (for_inval)
+ {
+ dlist_push_tail(&txn->distributed_inval, &change->node);
+ txn->nentries_distr++;
+ }
+ else
+ {
+ dlist_push_tail(&txn->changes, &change->node);
+ txn->nentries++;
+ txn->nentries_mem++;
+
+ /*
+ * For normal changes, we must update memory usage and process pertial
+ * changes. This is not needed for distributed ones, because they
+ * won't be added to the total amount of memory.
+ */
+
+ /* update memory accounting information */
+ ReorderBufferChangeMemoryUpdate(rb, change, NULL, true,
+ ReorderBufferChangeSize(change));
+
+ /* process partial change */
+ ReorderBufferProcessPartialChange(rb, txn, change, toast_insert);
- /* process partial change */
- ReorderBufferProcessPartialChange(rb, txn, change, toast_insert);
+ /* check the memory limits and evict something if needed */
+ ReorderBufferCheckMemoryLimit(rb);
+ }
+}
+
+static void
+ReorderBufferExecuteInvalidationsInQueue(ReorderBuffer *rb, ReorderBufferTXN *txn)
+{
+ ReorderBufferChange *change;
+ ReorderBufferIterTXNState *volatile iterstate = NULL;
+
+ ReorderBufferIterTXNInitForInval(rb, txn, &iterstate);
+ while ((change = ReorderBufferIterTXNNextForInval(rb, iterstate)) != NULL)
+ {
+ /* XXX do we have to do something here? */
+
+ switch (change->action)
+ {
+ /* Only interested in invalidation */
+ case REORDER_BUFFER_CHANGE_INVALIDATION:
+ /* Execute the invalidation messages locally */
+ ReorderBufferExecuteInvalidations(change->data.inval.ninvalidations,
+ change->data.inval.invalidations);
+ break;
+
+ /* Skip other changes because the transaction was aborted */
+ case REORDER_BUFFER_CHANGE_INSERT:
+ case REORDER_BUFFER_CHANGE_UPDATE:
+ case REORDER_BUFFER_CHANGE_DELETE:
+ case REORDER_BUFFER_CHANGE_MESSAGE:
+ case REORDER_BUFFER_CHANGE_INTERNAL_SNAPSHOT:
+ case REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID:
+ case REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID:
+ case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT:
+ case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_CONFIRM:
+ case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_ABORT:
+ case REORDER_BUFFER_CHANGE_TRUNCATE:
+ break;
+ }
+ }
- /* check the memory limits and evict something if needed */
- ReorderBufferCheckMemoryLimit(rb);
+ /* clean up the iterator */
+ ReorderBufferIterTXNFinish(rb, iterstate);
}
/*
@@ -1261,36 +1361,61 @@ ReorderBufferIterCompare(Datum a, Datum b, void *arg)
static void
ReorderBufferIterTXNInit(ReorderBuffer *rb, ReorderBufferTXN *txn,
ReorderBufferIterTXNState *volatile *iter_state)
+{
+ ReorderBufferIterTXNInitInternal(rb, txn, iter_state, false);
+}
+
+static void
+ReorderBufferIterTXNInitForInval(ReorderBuffer *rb, ReorderBufferTXN *txn,
+ ReorderBufferIterTXNState *volatile *iter_state)
+{
+ ReorderBufferIterTXNInitInternal(rb, txn, iter_state, true);
+}
+
+/*
+ * Actual workhorse for ReorderBufferIterTXNInit and ReorderBufferIterTXNInitForInval
+ */
+static void
+ReorderBufferIterTXNInitInternal(ReorderBuffer *rb, ReorderBufferTXN *txn,
+ ReorderBufferIterTXNState *volatile *iter_state,
+ bool iterate_inval)
{
Size nr_txns = 0;
ReorderBufferIterTXNState *state;
dlist_iter cur_txn_i;
int32 off;
+ uint64 nentries;
*iter_state = NULL;
/* Check ordering of changes in the toplevel transaction. */
- AssertChangeLsnOrder(txn);
+ if (!iterate_inval)
+ AssertChangeLsnOrder(txn);
+
+ nentries = iterate_inval ? txn->nentries_distr : txn->nentries;
/*
* Calculate the size of our heap: one element for every transaction that
* contains changes. (Besides the transactions already in the reorder
* buffer, we count the one we were directly passed.)
*/
- if (txn->nentries > 0)
+ if (nentries > 0)
nr_txns++;
- dlist_foreach(cur_txn_i, &txn->subtxns)
+ if (!iterate_inval)
{
- ReorderBufferTXN *cur_txn;
+ dlist_foreach(cur_txn_i, &txn->subtxns)
+ {
+ ReorderBufferTXN *cur_txn;
- cur_txn = dlist_container(ReorderBufferTXN, node, cur_txn_i.cur);
+ cur_txn = dlist_container(ReorderBufferTXN, node, cur_txn_i.cur);
- /* Check ordering of changes in this subtransaction. */
- AssertChangeLsnOrder(cur_txn);
+ /* Check ordering of changes in this subtransaction. */
+ AssertChangeLsnOrder(cur_txn);
- if (cur_txn->nentries > 0)
- nr_txns++;
+ if (cur_txn->nentries > 0)
+ nr_txns++;
+ }
}
/* allocate iteration state */
@@ -1324,11 +1449,12 @@ ReorderBufferIterTXNInit(ReorderBuffer *rb, ReorderBufferTXN *txn,
off = 0;
/* add toplevel transaction if it contains changes */
- if (txn->nentries > 0)
+ if (nentries > 0)
{
ReorderBufferChange *cur_change;
+ dlist_head *head;
- if (rbtxn_is_serialized(txn))
+ if (!iterate_inval && rbtxn_is_serialized(txn))
{
/* serialize remaining changes */
ReorderBufferSerializeTXN(rb, txn);
@@ -1336,8 +1462,10 @@ ReorderBufferIterTXNInit(ReorderBuffer *rb, ReorderBufferTXN *txn,
&state->entries[off].segno);
}
+ head = iterate_inval ? &txn->distributed_inval : &txn->changes;
+
cur_change = dlist_head_element(ReorderBufferChange, node,
- &txn->changes);
+ head);
state->entries[off].lsn = cur_change->lsn;
state->entries[off].change = cur_change;
@@ -1346,34 +1474,42 @@ ReorderBufferIterTXNInit(ReorderBuffer *rb, ReorderBufferTXN *txn,
binaryheap_add_unordered(state->heap, Int32GetDatum(off++));
}
- /* add subtransactions if they contain changes */
- dlist_foreach(cur_txn_i, &txn->subtxns)
+ if (!iterate_inval)
{
- ReorderBufferTXN *cur_txn;
-
- cur_txn = dlist_container(ReorderBufferTXN, node, cur_txn_i.cur);
-
- if (cur_txn->nentries > 0)
+ /* add subtransactions if they contain changes */
+ dlist_foreach(cur_txn_i, &txn->subtxns)
{
- ReorderBufferChange *cur_change;
+ ReorderBufferTXN *cur_txn;
+
+ cur_txn = dlist_container(ReorderBufferTXN, node, cur_txn_i.cur);
- if (rbtxn_is_serialized(cur_txn))
+ if (cur_txn->nentries > 0)
{
- /* serialize remaining changes */
- ReorderBufferSerializeTXN(rb, cur_txn);
- ReorderBufferRestoreChanges(rb, cur_txn,
- &state->entries[off].file,
- &state->entries[off].segno);
- }
- cur_change = dlist_head_element(ReorderBufferChange, node,
- &cur_txn->changes);
+ ReorderBufferChange *cur_change;
+ dlist_head *head;
+
+ if (rbtxn_is_serialized(cur_txn))
+ {
+ /* serialize remaining changes */
+ ReorderBufferSerializeTXN(rb, cur_txn);
+ ReorderBufferRestoreChanges(rb, cur_txn,
+ &state->entries[off].file,
+ &state->entries[off].segno);
+ }
+
+ head = iterate_inval ? &cur_txn->distributed_inval : &cur_txn->changes;
+
+ cur_change = dlist_head_element(ReorderBufferChange, node,
+ head);
- state->entries[off].lsn = cur_change->lsn;
- state->entries[off].change = cur_change;
- state->entries[off].txn = cur_txn;
+ state->entries[off].lsn = cur_change->lsn;
+ state->entries[off].change = cur_change;
+ state->entries[off].txn = cur_txn;
- binaryheap_add_unordered(state->heap, Int32GetDatum(off++));
+ binaryheap_add_unordered(state->heap, Int32GetDatum(off++));
+ }
}
+
}
/* assemble a valid binary heap */
@@ -1388,10 +1524,29 @@ ReorderBufferIterTXNInit(ReorderBuffer *rb, ReorderBufferTXN *txn,
*/
static ReorderBufferChange *
ReorderBufferIterTXNNext(ReorderBuffer *rb, ReorderBufferIterTXNState *state)
+{
+ return ReorderBufferIterTXNNextInternal(rb, state, false);
+}
+
+static ReorderBufferChange *
+ReorderBufferIterTXNNextForInval(ReorderBuffer *rb, ReorderBufferIterTXNState *state)
+{
+ return ReorderBufferIterTXNNextInternal(rb, state, true);
+}
+
+/*
+ * Actual workhorse for ReorderBufferIterTXNNext and ReorderBufferIterTXNNextForInval
+ */
+static ReorderBufferChange *
+ReorderBufferIterTXNNextInternal(ReorderBuffer *rb, ReorderBufferIterTXNState *state,
+ bool iterate_inval)
{
ReorderBufferChange *change;
ReorderBufferIterTXNEntry *entry;
int32 off;
+ dlist_head *head;
+ uint64 nentries;
+ uint64 nentries_mem;
/* nothing there anymore */
if (state->heap->bh_size == 0)
@@ -1411,15 +1566,33 @@ ReorderBufferIterTXNNext(ReorderBuffer *rb, ReorderBufferIterTXNState *state)
change = entry->change;
+ if (iterate_inval)
+ {
+ head = &entry->txn->distributed_inval;
+ nentries = entry->txn->nentries_distr;
+
+ /*
+ * The inval queue won't be serialized, so the number of entries on the
+ * memory is same as whole entries.
+ */
+ nentries_mem = entry->txn->nentries_distr;
+ }
+ else
+ {
+ head = &entry->txn->changes;
+ nentries = entry->txn->nentries;
+ nentries_mem = entry->txn->nentries_mem;
+ }
+
/*
* update heap with information about which transaction has the next
* relevant change in LSN order
*/
/* there are in-memory changes */
- if (dlist_has_next(&entry->txn->changes, &entry->change->node))
+ if (dlist_has_next(head, &entry->change->node))
{
- dlist_node *next = dlist_next_node(&entry->txn->changes, &change->node);
+ dlist_node *next = dlist_next_node(head, &change->node);
ReorderBufferChange *next_change =
dlist_container(ReorderBufferChange, node, next);
@@ -1432,7 +1605,7 @@ ReorderBufferIterTXNNext(ReorderBuffer *rb, ReorderBufferIterTXNState *state)
}
/* try to load changes from disk */
- if (entry->txn->nentries != entry->txn->nentries_mem)
+ if (nentries != nentries_mem)
{
/*
* Ugly: restoring changes will reuse *Change records, thus delete the
@@ -1453,11 +1626,11 @@ ReorderBufferIterTXNNext(ReorderBuffer *rb, ReorderBufferIterTXNState *state)
/* successfully restored changes from disk */
ReorderBufferChange *next_change =
dlist_head_element(ReorderBufferChange, node,
- &entry->txn->changes);
+ head);
elog(DEBUG2, "restored %u/%u changes from disk",
- (uint32) entry->txn->nentries_mem,
- (uint32) entry->txn->nentries);
+ (uint32) nentries_mem,
+ (uint32) nentries);
Assert(entry->txn->nentries_mem);
/* txn stays the same */
@@ -1477,6 +1650,8 @@ ReorderBufferIterTXNNext(ReorderBuffer *rb, ReorderBufferIterTXNState *state)
/*
* Deallocate the iterator
+ *
+ * XXX No need to prepare internal function because it does not refer txn.
*/
static void
ReorderBufferIterTXNFinish(ReorderBuffer *rb,
@@ -1558,6 +1733,16 @@ ReorderBufferCleanupTXN(ReorderBuffer *rb, ReorderBufferTXN *txn)
/* Update the memory counter */
ReorderBufferChangeMemoryUpdate(rb, NULL, txn, false, mem_freed);
+ /* cleanup inval queue */
+ dlist_foreach_modify(iter, &txn->distributed_inval)
+ {
+ ReorderBufferChange *change;
+
+ change = dlist_container(ReorderBufferChange, node, iter.cur);
+
+ ReorderBufferReturnChange(rb, change, false);
+ }
+
/*
* Cleanup the tuplecids we stored for decoding catalog snapshot access.
* They are always stored in the toplevel transaction.
@@ -2575,6 +2760,7 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
/* make sure there's no cache pollution */
ReorderBufferExecuteInvalidations(txn->ninvalidations, txn->invalidations);
+ ReorderBufferExecuteInvalidationsInQueue(rb, txn);
if (using_subtxn)
RollbackAndReleaseCurrentSubTransaction();
@@ -2623,6 +2809,9 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
ReorderBufferExecuteInvalidations(txn->ninvalidations,
txn->invalidations);
+ /* XXX Should this put in the concurrent_abort case? */
+ ReorderBufferExecuteInvalidationsInQueue(rb, txn);
+
if (using_subtxn)
RollbackAndReleaseCurrentSubTransaction();
@@ -3329,6 +3518,21 @@ void
ReorderBufferAddInvalidations(ReorderBuffer *rb, TransactionId xid,
XLogRecPtr lsn, Size nmsgs,
SharedInvalidationMessage *msgs)
+{
+ ReorderBufferAddInvalidationsExtended(rb, xid, lsn, nmsgs, msgs, true);
+}
+
+/*
+ * An extended workhorse version of ReorderBufferAddInvalidations(). This can
+ * control whether invalidation messages can be accumulated in reorderbuffer
+ * transactions, which would be distributed to all concurrent transactions at
+ * commit.
+ */
+void
+ReorderBufferAddInvalidationsExtended(ReorderBuffer *rb, TransactionId xid,
+ XLogRecPtr lsn, Size nmsgs,
+ SharedInvalidationMessage *msgs,
+ bool needs_distribute)
{
ReorderBufferTXN *txn;
MemoryContext oldcontext;
@@ -3340,31 +3544,34 @@ ReorderBufferAddInvalidations(ReorderBuffer *rb, TransactionId xid,
/*
* Collect all the invalidations under the top transaction, if available,
- * so that we can execute them all together. See comments atop this
- * function.
+ * so that we can execute them all together. See comments atop
+ * ReorderBufferAddInvalidations.
*/
txn = rbtxn_get_toptxn(txn);
Assert(nmsgs > 0);
- /* Accumulate invalidations. */
- if (txn->ninvalidations == 0)
+ if (needs_distribute)
{
- txn->ninvalidations = nmsgs;
- txn->invalidations = (SharedInvalidationMessage *)
- palloc(sizeof(SharedInvalidationMessage) * nmsgs);
- memcpy(txn->invalidations, msgs,
- sizeof(SharedInvalidationMessage) * nmsgs);
- }
- else
- {
- txn->invalidations = (SharedInvalidationMessage *)
- repalloc(txn->invalidations, sizeof(SharedInvalidationMessage) *
- (txn->ninvalidations + nmsgs));
+ /* Accumulate invalidations. */
+ if (txn->ninvalidations == 0)
+ {
+ txn->ninvalidations = nmsgs;
+ txn->invalidations = (SharedInvalidationMessage *)
+ palloc(sizeof(SharedInvalidationMessage) * nmsgs);
+ memcpy(txn->invalidations, msgs,
+ sizeof(SharedInvalidationMessage) * nmsgs);
+ }
+ else
+ {
+ txn->invalidations = (SharedInvalidationMessage *)
+ repalloc(txn->invalidations,
+ sizeof(SharedInvalidationMessage) * (txn->ninvalidations + nmsgs));
- memcpy(txn->invalidations + txn->ninvalidations, msgs,
- nmsgs * sizeof(SharedInvalidationMessage));
- txn->ninvalidations += nmsgs;
+ memcpy(txn->invalidations + txn->ninvalidations, msgs,
+ nmsgs * sizeof(SharedInvalidationMessage));
+ txn->ninvalidations += nmsgs;
+ }
}
change = ReorderBufferGetChange(rb);
@@ -3377,6 +3584,28 @@ ReorderBufferAddInvalidations(ReorderBuffer *rb, TransactionId xid,
ReorderBufferQueueChange(rb, xid, lsn, change, false);
+ /*
+ * If the message is distributed from other transactions, also add to
+ * another queue.
+ *
+ * XXX: IIUC This must be done only to the toptxns, but is it right?
+ */
+ if (!needs_distribute && !TransactionIdIsValid(txn->toplevel_xid))
+ {
+ ReorderBufferChange *inval_change;
+
+ /* Duplicate the inval change to queue it */
+ inval_change = ReorderBufferGetChange(rb);
+ inval_change->action = REORDER_BUFFER_CHANGE_INVALIDATION;
+ inval_change->data.inval.ninvalidations = nmsgs;
+ inval_change->data.inval.invalidations = (SharedInvalidationMessage *)
+ palloc(sizeof(SharedInvalidationMessage) * nmsgs);
+ memcpy(inval_change->data.inval.invalidations, msgs,
+ sizeof(SharedInvalidationMessage) * nmsgs);
+
+ ReorderBufferQueueInval(rb, xid, lsn, inval_change);
+ }
+
MemoryContextSwitchTo(oldcontext);
}
diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index 110e0b0a044..a8225c1d905 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -945,8 +945,9 @@ SnapBuildDistributeSnapshotAndInval(SnapBuild *builder, XLogRecPtr lsn, Transact
{
Assert(msgs != NULL);
- ReorderBufferAddInvalidations(builder->reorder, txn->xid, lsn,
- ninvalidations, msgs);
+ ReorderBufferAddInvalidationsExtended(builder->reorder, txn->xid, lsn,
+ ninvalidations, msgs,
+ false);
}
}
}
diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h
index 4c56f219fd8..7bfd199c4b7 100644
--- a/src/include/replication/reorderbuffer.h
+++ b/src/include/replication/reorderbuffer.h
@@ -422,6 +422,9 @@ typedef struct ReorderBufferTXN
* Private data pointer of the output plugin.
*/
void *output_plugin_private;
+
+ dlist_head distributed_inval;
+ uint64 nentries_distr;
} ReorderBufferTXN;
/* so we can define the callbacks used inside struct ReorderBuffer itself */
@@ -709,6 +712,9 @@ extern void ReorderBufferAddNewTupleCids(ReorderBuffer *rb, TransactionId xid,
CommandId cmin, CommandId cmax, CommandId combocid);
extern void ReorderBufferAddInvalidations(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn,
Size nmsgs, SharedInvalidationMessage *msgs);
+extern void ReorderBufferAddInvalidationsExtended(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn,
+ Size nmsgs, SharedInvalidationMessage *msgs,
+ bool needs_distribute);
extern void ReorderBufferImmediateInvalidation(ReorderBuffer *rb, uint32 ninvalidations,
SharedInvalidationMessage *invalidations);
extern void ReorderBufferProcessXid(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn);
--
2.47.1