diff options
author | Andres Freund <andres@anarazel.de> | 2016-04-23 19:18:00 -0700 |
---|---|---|
committer | Andres Freund <andres@anarazel.de> | 2016-04-26 20:21:54 -0700 |
commit | c6ff84b06a68b71719aa1aaa5f6704d8db1b51f8 (patch) | |
tree | bca1d7f785aa03f73b137f3182d028e16abdf519 /src/backend/replication | |
parent | 2ac3be2e763d9b971352819f285dd51519e0aeb9 (diff) | |
download | postgresql-c6ff84b06a68b71719aa1aaa5f6704d8db1b51f8.tar.gz postgresql-c6ff84b06a68b71719aa1aaa5f6704d8db1b51f8.zip |
Emit invalidations to standby for transactions without xid.
So far, when a transaction with pending invalidations, but without an
assigned xid, committed, we simply ignored those invalidation
messages. That's problematic, because those are actually sent for a
reason.
Known symptoms of this include that existing sessions on a hot-standby
replica sometimes fail to notice new concurrently built indexes and
visibility map updates.
The solution is to WAL log such invalidations in transactions without an
xid. We considered to alternatively force-assign an xid, but that'd be
problematic for vacuum, which might be run in systems with few xids.
Important: This adds a new WAL record, but as the patch has to be
back-patched, we can't bump the WAL page magic. This means that standbys
have to be updated before primaries; otherwise
"PANIC: standby_redo: unknown op code 32" errors can be encountered.
XXX:
Reported-By: Васильев Дмитрий, Masahiko Sawada
Discussion:
CAB-SwXY6oH=9twBkXJtgR4UC1NqT-vpYAtxCseME62ADwyK5OA@mail.gmail.com
CAD21AoDpZ6Xjg=gFrGPnSn4oTRRcwK1EBrWCq9OqOHuAcMMC=w@mail.gmail.com
Diffstat (limited to 'src/backend/replication')
-rw-r--r-- | src/backend/replication/logical/decode.c | 9 | ||||
-rw-r--r-- | src/backend/replication/logical/reorderbuffer.c | 53 |
2 files changed, 42 insertions, 20 deletions
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c index 0cdb0b8a92b..0c248f07e8f 100644 --- a/src/backend/replication/logical/decode.c +++ b/src/backend/replication/logical/decode.c @@ -327,6 +327,15 @@ DecodeStandbyOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) break; case XLOG_STANDBY_LOCK: break; + case XLOG_INVALIDATIONS: + { + xl_invalidations *invalidations = + (xl_invalidations *) XLogRecGetData(r); + + ReorderBufferImmediateInvalidation( + ctx->reorder, invalidations->nmsgs, invalidations->msgs); + } + break; default: elog(ERROR, "unexpected RM_STANDBY_ID record type: %u", info); } diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c index 45207086ac0..57821c34027 100644 --- a/src/backend/replication/logical/reorderbuffer.c +++ b/src/backend/replication/logical/reorderbuffer.c @@ -1810,26 +1810,8 @@ ReorderBufferForget(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn) * catalog and we need to update the caches according to that. */ if (txn->base_snapshot != NULL && txn->ninvalidations > 0) - { - bool use_subtxn = IsTransactionOrTransactionBlock(); - - if (use_subtxn) - BeginInternalSubTransaction("replay"); - - /* - * Force invalidations to happen outside of a valid transaction - that - * way entries will just be marked as invalid without accessing the - * catalog. That's advantageous because we don't need to setup the - * full state necessary for catalog access. - */ - if (use_subtxn) - AbortCurrentTransaction(); - - ReorderBufferExecuteInvalidations(rb, txn); - - if (use_subtxn) - RollbackAndReleaseCurrentSubTransaction(); - } + ReorderBufferImmediateInvalidation(rb, txn->ninvalidations, + txn->invalidations); else Assert(txn->ninvalidations == 0); @@ -1837,6 +1819,37 @@ ReorderBufferForget(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn) ReorderBufferCleanupTXN(rb, txn); } +/* + * Execute invalidations happening outside the context of a decoded + * transaction. That currently happens either for xid-less commits + * (c.f. RecordTransactionCommit()) or for invalidations in uninteresting + * transactions (via ReorderBufferForget()). + */ +void +ReorderBufferImmediateInvalidation(ReorderBuffer *rb, uint32 ninvalidations, + SharedInvalidationMessage *invalidations) +{ + bool use_subtxn = IsTransactionOrTransactionBlock(); + int i; + + if (use_subtxn) + BeginInternalSubTransaction("replay"); + + /* + * Force invalidations to happen outside of a valid transaction - that + * way entries will just be marked as invalid without accessing the + * catalog. That's advantageous because we don't need to setup the + * full state necessary for catalog access. + */ + if (use_subtxn) + AbortCurrentTransaction(); + + for (i = 0; i < ninvalidations; i++) + LocalExecuteInvalidationMessage(&invalidations[i]); + + if (use_subtxn) + RollbackAndReleaseCurrentSubTransaction(); +} /* * Tell reorderbuffer about an xid seen in the WAL stream. Has to be called at |