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

Commit f786e91

Browse files
committed
Improve underdocumented btree_xlog_delete_get_latestRemovedXid() code.
As noted by Noah Misch, btree_xlog_delete_get_latestRemovedXid is critically dependent on the assumption that it's examining a consistent state of the database. This was undocumented though, so the seemingly-unrelated check for no active HS sessions might be thought to be merely an optional optimization. Improve comments, and add an explicit check of reachedConsistency just to be sure. This function returns InvalidTransactionId (thereby killing all HS transactions) in several cases that are not nearly unlikely enough for my taste. This commit doesn't attempt to fix those deficiencies, just document them. Back-patch to 9.2, not from any real functional need but just to keep the branches more closely synced to simplify possible future back-patching.
1 parent c1793f2 commit f786e91

File tree

1 file changed

+31
-10
lines changed

1 file changed

+31
-10
lines changed

src/backend/access/nbtree/nbtxlog.c

+31-10
Original file line numberDiff line numberDiff line change
@@ -581,15 +581,33 @@ btree_xlog_delete_get_latestRemovedXid(XLogRecord *record)
581581

582582
/*
583583
* If there's nothing running on the standby we don't need to derive a
584-
* full latestRemovedXid value, so use a fast path out of here. That
585-
* returns InvalidTransactionId, and so will conflict with users, but
586-
* since we just worked out that's zero people, its OK.
584+
* full latestRemovedXid value, so use a fast path out of here. This
585+
* returns InvalidTransactionId, and so will conflict with all HS
586+
* transactions; but since we just worked out that that's zero people,
587+
* it's OK.
588+
*
589+
* XXX There is a race condition here, which is that a new backend might
590+
* start just after we look. If so, it cannot need to conflict, but this
591+
* coding will result in throwing a conflict anyway.
587592
*/
588593
if (CountDBBackends(InvalidOid) == 0)
589594
return latestRemovedXid;
590595

591596
/*
592-
* Get index page
597+
* In what follows, we have to examine the previous state of the index
598+
* page, as well as the heap page(s) it points to. This is only valid if
599+
* WAL replay has reached a consistent database state; which means that
600+
* the preceding check is not just an optimization, but is *necessary*.
601+
* We won't have let in any user sessions before we reach consistency.
602+
*/
603+
if (!reachedConsistency)
604+
elog(PANIC, "btree_xlog_delete_get_latestRemovedXid: cannot operate with inconsistent data");
605+
606+
/*
607+
* Get index page. If the DB is consistent, this should not fail, nor
608+
* should any of the heap page fetches below. If one does, we return
609+
* InvalidTransactionId to cancel all HS transactions. That's probably
610+
* overkill, but it's safe, and certainly better than panicking here.
593611
*/
594612
ibuffer = XLogReadBuffer(xlrec->node, xlrec->block, false);
595613
if (!BufferIsValid(ibuffer))
@@ -671,12 +689,11 @@ btree_xlog_delete_get_latestRemovedXid(XLogRecord *record)
671689
UnlockReleaseBuffer(ibuffer);
672690

673691
/*
674-
* Note that if all heap tuples were LP_DEAD then we will be returning
675-
* InvalidTransactionId here. That can happen if we are re-replaying this
676-
* record type, though that will be before the consistency point and will
677-
* not cause problems. It should happen very rarely after the consistency
678-
* point, though note that we can't tell the difference between this and
679-
* the fast path exit above. May need to change that in future.
692+
* XXX If all heap tuples were LP_DEAD then we will be returning
693+
* InvalidTransactionId here, causing conflict for all HS
694+
* transactions. That should happen very rarely (reasoning please?). Also
695+
* note that caller can't tell the difference between this case and the
696+
* fast path exit above. May need to change that in future.
680697
*/
681698
return latestRemovedXid;
682699
}
@@ -940,6 +957,10 @@ btree_redo(XLogRecPtr lsn, XLogRecord *record)
940957
{
941958
uint8 info = record->xl_info & ~XLR_INFO_MASK;
942959

960+
/*
961+
* If we have any conflict processing to do, it must happen before we
962+
* update the page.
963+
*/
943964
if (InHotStandby)
944965
{
945966
switch (info)

0 commit comments

Comments
 (0)