220
220
datalen -= sizeof(xl_btree_metadata);
223
if ((record->xl_info & XLR_BKP_BLOCK_1) && !ismeta && isleaf)
224
return; /* nothing to do */
226
if (!(record->xl_info & XLR_BKP_BLOCK_1))
223
if (record->xl_info & XLR_BKP_BLOCK(0))
224
(void) RestoreBackupBlock(lsn, record, 0, false, false);
228
227
buffer = XLogReadBuffer(xlrec->target.node,
229
228
ItemPointerGetBlockNumber(&(xlrec->target.tid)),
254
* Note: in normal operation, we'd update the metapage while still holding
255
* lock on the page we inserted into. But during replay it's not
256
* necessary to hold that lock, since no other index updates can be
257
* happening concurrently, and readers will cope fine with following an
258
* obsolete link from the metapage.
255
261
_bt_restore_meta(xlrec->target.node, lsn,
256
262
md.root, md.level,
292
298
forget_matching_split(xlrec->node, downlink, false);
294
300
/* Extract left hikey and its size (still assuming 16-bit alignment) */
295
if (!(record->xl_info & XLR_BKP_BLOCK_1))
301
if (!(record->xl_info & XLR_BKP_BLOCK(0)))
297
303
/* We assume 16-bit alignment is enough for IndexTupleSize */
298
304
left_hikey = (Item) datapos;
360
366
/* don't release the buffer yet; we touch right page's first item below */
363
* Reconstruct left (original) sibling if needed. Note that this code
364
* ensures that the items remaining on the left page are in the correct
365
* item number order, but it does not reproduce the physical order they
366
* would have had. Is this worth changing? See also _bt_restore_page().
368
if (!(record->xl_info & XLR_BKP_BLOCK_1))
368
/* Now reconstruct left (original) sibling page */
369
if (record->xl_info & XLR_BKP_BLOCK(0))
370
(void) RestoreBackupBlock(lsn, record, 0, false, false);
370
373
Buffer lbuf = XLogReadBuffer(xlrec->node, xlrec->leftsib, false);
372
375
if (BufferIsValid(lbuf))
378
* Note that this code ensures that the items remaining on the
379
* left page are in the correct item number order, but it does not
380
* reproduce the physical order they would have had. Is this
381
* worth changing? See also _bt_restore_page().
374
383
Page lpage = (Page) BufferGetPage(lbuf);
375
384
BTPageOpaque lopaque = (BTPageOpaque) PageGetSpecialPointer(lpage);
434
443
/* We no longer need the right buffer */
435
444
UnlockReleaseBuffer(rbuf);
437
/* Fix left-link of the page to the right of the new right sibling */
438
if (xlrec->rnext != P_NONE && !(record->xl_info & XLR_BKP_BLOCK_2))
447
* Fix left-link of the page to the right of the new right sibling.
449
* Note: in normal operation, we do this while still holding lock on the
450
* two split pages. However, that's not necessary for correctness in WAL
451
* replay, because no other index update can be in progress, and readers
452
* will cope properly when following an obsolete left-link.
454
if (record->xl_info & XLR_BKP_BLOCK(1))
455
(void) RestoreBackupBlock(lsn, record, 1, false, false);
456
else if (xlrec->rnext != P_NONE)
440
458
Buffer buffer = XLogReadBuffer(xlrec->node, xlrec->rnext, false);
466
484
btree_xlog_vacuum(XLogRecPtr lsn, XLogRecord *record)
468
xl_btree_vacuum *xlrec;
486
xl_btree_vacuum *xlrec = (xl_btree_vacuum *) XLogRecGetData(record);
471
489
BTPageOpaque opaque;
473
xlrec = (xl_btree_vacuum *) XLogRecGetData(record);
476
492
* If queries might be active then we need to ensure every block is
477
493
* unpinned between the lastBlockVacuumed and the current block, if there
507
* If the block was restored from a full page image, nothing more to do.
508
* The RestoreBkpBlocks() call already pinned and took cleanup lock on it.
509
* XXX: Perhaps we should call RestoreBkpBlocks() *after* the loop above,
510
* to make the disk access more sequential.
523
* If we have a full-page image, restore it (using a cleanup lock) and
512
if (record->xl_info & XLR_BKP_BLOCK_1)
526
if (record->xl_info & XLR_BKP_BLOCK(0))
528
(void) RestoreBackupBlock(lsn, record, 0, true, false);
516
533
* Like in btvacuumpage(), we need to take a cleanup lock on every leaf
688
704
btree_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
690
xl_btree_delete *xlrec;
706
xl_btree_delete *xlrec = (xl_btree_delete *) XLogRecGetData(record);
693
709
BTPageOpaque opaque;
695
if (record->xl_info & XLR_BKP_BLOCK_1)
712
* If we have any conflict processing to do, it must happen before we
715
* Btree delete records can conflict with standby queries. You might
716
* think that vacuum records would conflict as well, but we've handled
717
* that already. XLOG_HEAP2_CLEANUP_INFO records provide the highest xid
718
* cleaned by the vacuum of the heap and so we can resolve any conflicts
719
* just once when that arrives. After that we know that no conflicts
720
* exist from individual btree vacuum records on that index.
724
TransactionId latestRemovedXid = btree_xlog_delete_get_latestRemovedXid(xlrec);
726
ResolveRecoveryConflictWithSnapshot(latestRemovedXid, xlrec->node);
729
/* If we have a full-page image, restore it and we're done */
730
if (record->xl_info & XLR_BKP_BLOCK(0))
732
(void) RestoreBackupBlock(lsn, record, 0, false, false);
698
xlrec = (xl_btree_delete *) XLogRecGetData(record);
701
737
* We don't need to take a cleanup lock to apply these changes. See
751
787
leftsib = xlrec->leftblk;
752
788
rightsib = xlrec->rightblk;
791
* In normal operation, we would lock all the pages this WAL record
792
* touches before changing any of them. In WAL replay, it should be okay
793
* to lock just one page at a time, since no concurrent index updates can
794
* be happening, and readers should not care whether they arrive at the
795
* target page or not (since it's surely empty).
754
798
/* parent page */
755
if (!(record->xl_info & XLR_BKP_BLOCK_1))
799
if (record->xl_info & XLR_BKP_BLOCK(0))
800
(void) RestoreBackupBlock(lsn, record, 0, false, false);
757
803
buffer = XLogReadBuffer(xlrec->target.node, parent, false);
758
804
if (BufferIsValid(buffer))
800
846
/* Fix left-link of right sibling */
801
if (!(record->xl_info & XLR_BKP_BLOCK_2))
847
if (record->xl_info & XLR_BKP_BLOCK(1))
848
(void) RestoreBackupBlock(lsn, record, 1, false, false);
803
851
buffer = XLogReadBuffer(xlrec->target.node, rightsib, false);
804
852
if (BufferIsValid(buffer))
824
872
/* Fix right-link of left sibling, if any */
825
if (!(record->xl_info & XLR_BKP_BLOCK_3))
873
if (record->xl_info & XLR_BKP_BLOCK(2))
874
(void) RestoreBackupBlock(lsn, record, 2, false, false);
827
877
if (leftsib != P_NONE)
896
946
BTPageOpaque pageop;
897
947
BlockNumber downlink = 0;
949
/* Backup blocks are not used in newroot records */
950
Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
899
952
buffer = XLogReadBuffer(xlrec->node, xlrec->rootblk, true);
900
953
Assert(BufferIsValid(buffer));
901
954
page = (Page) BufferGetPage(buffer);
937
990
forget_matching_split(xlrec->node, downlink, true);
994
btree_xlog_reuse_page(XLogRecPtr lsn, XLogRecord *record)
996
xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) XLogRecGetData(record);
999
* Btree reuse_page records exist to provide a conflict point when we
1000
* reuse pages in the index via the FSM. That's all they do though.
1002
* latestRemovedXid was the page's btpo.xact. The btpo.xact <
1003
* RecentGlobalXmin test in _bt_page_recyclable() conceptually mirrors the
1004
* pgxact->xmin > limitXmin test in GetConflictingVirtualXIDs().
1005
* Consequently, one XID value achieves the same exclusion effect on
1006
* master and standby.
1010
ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid,
1014
/* Backup blocks are not used in reuse_page records */
1015
Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
942
1020
btree_redo(XLogRecPtr lsn, XLogRecord *record)
944
1022
uint8 info = record->xl_info & ~XLR_INFO_MASK;
950
case XLOG_BTREE_DELETE:
953
* Btree delete records can conflict with standby queries. You
954
* might think that vacuum records would conflict as well, but
955
* we've handled that already. XLOG_HEAP2_CLEANUP_INFO records
956
* provide the highest xid cleaned by the vacuum of the heap
957
* and so we can resolve any conflicts just once when that
958
* arrives. After that any we know that no conflicts exist
959
* from individual btree vacuum records on that index.
962
TransactionId latestRemovedXid = btree_xlog_delete_get_latestRemovedXid(record);
963
xl_btree_delete *xlrec = (xl_btree_delete *) XLogRecGetData(record);
965
ResolveRecoveryConflictWithSnapshot(latestRemovedXid, xlrec->node);
969
case XLOG_BTREE_REUSE_PAGE:
972
* Btree reuse page records exist to provide a conflict point
973
* when we reuse pages in the index via the FSM. That's all it
974
* does though. latestRemovedXid was the page's btpo.xact. The
975
* btpo.xact < RecentGlobalXmin test in _bt_page_recyclable()
976
* conceptually mirrors the pgxact->xmin > limitXmin test in
977
* GetConflictingVirtualXIDs(). Consequently, one XID value
978
* achieves the same exclusion effect on master and standby.
981
xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) XLogRecGetData(record);
983
ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid, xlrec->node);
993
* Vacuum needs to pin and take cleanup lock on every leaf page, a regular
994
* exclusive lock is enough for all other purposes.
996
RestoreBkpBlocks(lsn, record, (info == XLOG_BTREE_VACUUM));
1000
1026
case XLOG_BTREE_INSERT_LEAF:
1033
1059
btree_xlog_newroot(lsn, record);
1035
1061
case XLOG_BTREE_REUSE_PAGE:
1036
/* Handled above before restoring bkp block */
1062
btree_xlog_reuse_page(lsn, record);
1039
1065
elog(PANIC, "btree_redo: unknown op code %u", info);