PostgreSQL Source Code  git master
nbtpage.c File Reference
#include "postgres.h"
#include "access/nbtree.h"
#include "access/nbtxlog.h"
#include "access/transam.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
#include "miscadmin.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "storage/predicate.h"
#include "utils/snapmgr.h"
Include dependency graph for nbtpage.c:

Go to the source code of this file.

Functions

static void _bt_cachemetadata (Relation rel, BTMetaPageData *metad)
 
static bool _bt_mark_page_halfdead (Relation rel, Buffer buf, BTStack stack)
 
static bool _bt_unlink_halfdead_page (Relation rel, Buffer leafbuf, bool *rightsib_empty)
 
static bool _bt_lock_branch_parent (Relation rel, BlockNumber child, BTStack stack, Buffer *topparent, OffsetNumber *topoff, BlockNumber *target, BlockNumber *rightsib)
 
static void _bt_log_reuse_page (Relation rel, BlockNumber blkno, TransactionId latestRemovedXid)
 
void _bt_initmetapage (Page page, BlockNumber rootbknum, uint32 level)
 
void _bt_upgrademetapage (Page page)
 
void _bt_update_meta_cleanup_info (Relation rel, TransactionId oldestBtpoXact, float8 numHeapTuples)
 
Buffer _bt_getroot (Relation rel, int access)
 
Buffer _bt_gettrueroot (Relation rel)
 
int _bt_getrootheight (Relation rel)
 
void _bt_checkpage (Relation rel, Buffer buf)
 
Buffer _bt_getbuf (Relation rel, BlockNumber blkno, int access)
 
Buffer _bt_relandgetbuf (Relation rel, Buffer obuf, BlockNumber blkno, int access)
 
void _bt_relbuf (Relation rel, Buffer buf)
 
void _bt_pageinit (Page page, Size size)
 
bool _bt_page_recyclable (Page page)
 
void _bt_delitems_vacuum (Relation rel, Buffer buf, OffsetNumber *itemnos, int nitems, BlockNumber lastBlockVacuumed)
 
void _bt_delitems_delete (Relation rel, Buffer buf, OffsetNumber *itemnos, int nitems, Relation heapRel)
 
static bool _bt_is_page_halfdead (Relation rel, BlockNumber blk)
 
int _bt_pagedel (Relation rel, Buffer buf)
 

Function Documentation

◆ _bt_cachemetadata()

static void _bt_cachemetadata ( Relation  rel,
BTMetaPageData metad 
)
static

Definition at line 113 of file nbtpage.c.

References Assert, BTMetaPageData::btm_last_cleanup_num_heap_tuples, BTMetaPageData::btm_oldest_btpo_xact, BTMetaPageData::btm_version, BTREE_MIN_VERSION, BTREE_VERSION, InvalidTransactionId, MemoryContextAlloc(), offsetof, RelationData::rd_amcache, and RelationData::rd_indexcxt.

Referenced by _bt_getroot(), and _bt_getrootheight().

114 {
115  /* We assume rel->rd_amcache was already freed by caller */
116  Assert(rel->rd_amcache == NULL);
118  sizeof(BTMetaPageData));
119 
120  /*
121  * Meta page should be of supported version (should be already checked by
122  * caller).
123  */
125  metad->btm_version <= BTREE_VERSION);
126 
127  if (metad->btm_version == BTREE_VERSION)
128  {
129  /* Last version of meta-data, no need to upgrade */
130  memcpy(rel->rd_amcache, metad, sizeof(BTMetaPageData));
131  }
132  else
133  {
134  BTMetaPageData *cached_metad = (BTMetaPageData *) rel->rd_amcache;
135 
136  /*
137  * Upgrade meta-data: copy available information from meta-page and
138  * fill new fields with default values.
139  */
140  memcpy(rel->rd_amcache, metad, offsetof(BTMetaPageData, btm_oldest_btpo_xact));
141  cached_metad->btm_version = BTREE_VERSION;
143  cached_metad->btm_last_cleanup_num_heap_tuples = -1.0;
144  }
145 }
uint32 btm_version
Definition: nbtree.h:100
#define BTREE_VERSION
Definition: nbtree.h:117
#define InvalidTransactionId
Definition: transam.h:31
#define BTREE_MIN_VERSION
Definition: nbtree.h:118
#define Assert(condition)
Definition: c.h:699
float8 btm_last_cleanup_num_heap_tuples
Definition: nbtree.h:108
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:771
MemoryContext rd_indexcxt
Definition: rel.h:151
TransactionId btm_oldest_btpo_xact
Definition: nbtree.h:106
void * rd_amcache
Definition: rel.h:164
#define offsetof(type, field)
Definition: c.h:622

◆ _bt_checkpage()

void _bt_checkpage ( Relation  rel,
Buffer  buf 
)

Definition at line 662 of file nbtpage.c.

References BufferGetBlockNumber(), BufferGetPage, ereport, errcode(), errhint(), errmsg(), ERROR, MAXALIGN, PageGetSpecialSize, PageIsNew, and RelationGetRelationName.

Referenced by _bt_doinsert(), _bt_getbuf(), _bt_relandgetbuf(), btvacuumpage(), btvacuumscan(), and palloc_btree_page().

663 {
664  Page page = BufferGetPage(buf);
665 
666  /*
667  * ReadBuffer verifies that every newly-read page passes
668  * PageHeaderIsValid, which means it either contains a reasonably sane
669  * page header or is all-zero. We have to defend against the all-zero
670  * case, however.
671  */
672  if (PageIsNew(page))
673  ereport(ERROR,
674  (errcode(ERRCODE_INDEX_CORRUPTED),
675  errmsg("index \"%s\" contains unexpected zero page at block %u",
678  errhint("Please REINDEX it.")));
679 
680  /*
681  * Additionally check that the special area looks sane.
682  */
683  if (PageGetSpecialSize(page) != MAXALIGN(sizeof(BTPageOpaqueData)))
684  ereport(ERROR,
685  (errcode(ERRCODE_INDEX_CORRUPTED),
686  errmsg("index \"%s\" contains corrupted page at block %u",
689  errhint("Please REINDEX it.")));
690 }
int errhint(const char *fmt,...)
Definition: elog.c:987
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:67
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
#define MAXALIGN(LEN)
Definition: c.h:652
#define PageGetSpecialSize(page)
Definition: bufpage.h:296
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define PageIsNew(page)
Definition: bufpage.h:225
int errmsg(const char *fmt,...)
Definition: elog.c:797
Pointer Page
Definition: bufpage.h:74

◆ _bt_delitems_delete()

void _bt_delitems_delete ( Relation  rel,
Buffer  buf,
OffsetNumber itemnos,
int  nitems,
Relation  heapRel 
)

Definition at line 1021 of file nbtpage.c.

References Assert, BTP_HAS_GARBAGE, BTPageOpaqueData::btpo_flags, BufferGetPage, END_CRIT_SECTION, xl_btree_delete::hnode, MarkBufferDirty(), xl_btree_delete::nitems, PageGetSpecialPointer, PageIndexMultiDelete(), PageSetLSN, RelationData::rd_node, REGBUF_STANDARD, RelationNeedsWAL, SizeOfBtreeDelete, START_CRIT_SECTION, XLOG_BTREE_DELETE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by _bt_vacuum_one_page().

1024 {
1025  Page page = BufferGetPage(buf);
1026  BTPageOpaque opaque;
1027 
1028  /* Shouldn't be called unless there's something to do */
1029  Assert(nitems > 0);
1030 
1031  /* No ereport(ERROR) until changes are logged */
1033 
1034  /* Fix the page */
1035  PageIndexMultiDelete(page, itemnos, nitems);
1036 
1037  /*
1038  * Unlike _bt_delitems_vacuum, we *must not* clear the vacuum cycle ID,
1039  * because this is not called by VACUUM.
1040  */
1041 
1042  /*
1043  * Mark the page as not containing any LP_DEAD items. This is not
1044  * certainly true (there might be some that have recently been marked, but
1045  * weren't included in our target-item list), but it will almost always be
1046  * true and it doesn't seem worth an additional page scan to check it.
1047  * Remember that BTP_HAS_GARBAGE is only a hint anyway.
1048  */
1049  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1050  opaque->btpo_flags &= ~BTP_HAS_GARBAGE;
1051 
1053 
1054  /* XLOG stuff */
1055  if (RelationNeedsWAL(rel))
1056  {
1057  XLogRecPtr recptr;
1058  xl_btree_delete xlrec_delete;
1059 
1060  xlrec_delete.hnode = heapRel->rd_node;
1061  xlrec_delete.nitems = nitems;
1062 
1063  XLogBeginInsert();
1065  XLogRegisterData((char *) &xlrec_delete, SizeOfBtreeDelete);
1066 
1067  /*
1068  * We need the target-offsets array whether or not we store the whole
1069  * buffer, to allow us to find the latestRemovedXid on a standby
1070  * server.
1071  */
1072  XLogRegisterData((char *) itemnos, nitems * sizeof(OffsetNumber));
1073 
1074  recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_DELETE);
1075 
1076  PageSetLSN(page, recptr);
1077  }
1078 
1079  END_CRIT_SECTION();
1080 }
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
RelFileNode hnode
Definition: nbtxlog.h:126
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:68
uint16 OffsetNumber
Definition: off.h:24
static char * buf
Definition: pg_test_fsync.c:67
#define REGBUF_STANDARD
Definition: xloginsert.h:34
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define XLOG_BTREE_DELETE
Definition: nbtxlog.h:33
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
RelFileNode rd_node
Definition: rel.h:55
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:699
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:832
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
#define RelationNeedsWAL(relation)
Definition: rel.h:510
#define SizeOfBtreeDelete
Definition: nbtxlog.h:133
void XLogBeginInsert(void)
Definition: xloginsert.c:120
uint16 btpo_flags
Definition: nbtree.h:64
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
#define BTP_HAS_GARBAGE
Definition: nbtree.h:77
Pointer Page
Definition: bufpage.h:74

◆ _bt_delitems_vacuum()

void _bt_delitems_vacuum ( Relation  rel,
Buffer  buf,
OffsetNumber itemnos,
int  nitems,
BlockNumber  lastBlockVacuumed 
)

Definition at line 948 of file nbtpage.c.

References BTP_HAS_GARBAGE, BTPageOpaqueData::btpo_cycleid, BTPageOpaqueData::btpo_flags, BufferGetPage, END_CRIT_SECTION, xl_btree_vacuum::lastBlockVacuumed, MarkBufferDirty(), PageGetSpecialPointer, PageIndexMultiDelete(), PageSetLSN, REGBUF_STANDARD, RelationNeedsWAL, SizeOfBtreeVacuum, START_CRIT_SECTION, XLOG_BTREE_VACUUM, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by btvacuumpage(), and btvacuumscan().

951 {
952  Page page = BufferGetPage(buf);
953  BTPageOpaque opaque;
954 
955  /* No ereport(ERROR) until changes are logged */
957 
958  /* Fix the page */
959  if (nitems > 0)
960  PageIndexMultiDelete(page, itemnos, nitems);
961 
962  /*
963  * We can clear the vacuum cycle ID since this page has certainly been
964  * processed by the current vacuum scan.
965  */
966  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
967  opaque->btpo_cycleid = 0;
968 
969  /*
970  * Mark the page as not containing any LP_DEAD items. This is not
971  * certainly true (there might be some that have recently been marked, but
972  * weren't included in our target-item list), but it will almost always be
973  * true and it doesn't seem worth an additional page scan to check it.
974  * Remember that BTP_HAS_GARBAGE is only a hint anyway.
975  */
976  opaque->btpo_flags &= ~BTP_HAS_GARBAGE;
977 
979 
980  /* XLOG stuff */
981  if (RelationNeedsWAL(rel))
982  {
983  XLogRecPtr recptr;
984  xl_btree_vacuum xlrec_vacuum;
985 
986  xlrec_vacuum.lastBlockVacuumed = lastBlockVacuumed;
987 
988  XLogBeginInsert();
990  XLogRegisterData((char *) &xlrec_vacuum, SizeOfBtreeVacuum);
991 
992  /*
993  * The target-offsets array is not in the buffer, but pretend that it
994  * is. When XLogInsert stores the whole buffer, the offsets array
995  * need not be stored too.
996  */
997  if (nitems > 0)
998  XLogRegisterBufData(0, (char *) itemnos, nitems * sizeof(OffsetNumber));
999 
1000  recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_VACUUM);
1001 
1002  PageSetLSN(page, recptr);
1003  }
1004 
1005  END_CRIT_SECTION();
1006 }
BlockNumber lastBlockVacuumed
Definition: nbtxlog.h:172
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:68
uint16 OffsetNumber
Definition: off.h:24
#define SizeOfBtreeVacuum
Definition: nbtxlog.h:177
BTCycleId btpo_cycleid
Definition: nbtree.h:65
static char * buf
Definition: pg_test_fsync.c:67
#define REGBUF_STANDARD
Definition: xloginsert.h:34
#define XLOG_BTREE_VACUUM
Definition: nbtxlog.h:38
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:832
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
#define RelationNeedsWAL(relation)
Definition: rel.h:510
void XLogBeginInsert(void)
Definition: xloginsert.c:120
uint16 btpo_flags
Definition: nbtree.h:64
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
#define BTP_HAS_GARBAGE
Definition: nbtree.h:77
Pointer Page
Definition: bufpage.h:74

◆ _bt_getbuf()

Buffer _bt_getbuf ( Relation  rel,
BlockNumber  blkno,
int  access 
)

Definition at line 729 of file nbtpage.c.

References _bt_checkpage(), _bt_log_reuse_page(), _bt_page_recyclable(), _bt_pageinit(), _bt_relbuf(), Assert, BT_WRITE, BTPageOpaqueData::btpo, buf, BufferGetPage, BufferGetPageSize, ConditionalLockBuffer(), DEBUG2, elog, ExclusiveLock, GetFreeIndexPage(), InvalidBlockNumber, LockBuffer(), LockRelationForExtension(), P_NEW, PageGetSpecialPointer, PageIsNew, ReadBuffer(), RELATION_IS_LOCAL, RelationNeedsWAL, ReleaseBuffer(), UnlockRelationForExtension(), BTPageOpaqueData::xact, and XLogStandbyInfoActive.

Referenced by _bt_finish_split(), _bt_getroot(), _bt_getrootheight(), _bt_getstackbuf(), _bt_gettrueroot(), _bt_insertonpg(), _bt_is_page_halfdead(), _bt_killitems(), _bt_lock_branch_parent(), _bt_moveright(), _bt_newroot(), _bt_pagedel(), _bt_readnextpage(), _bt_split(), _bt_unlink_halfdead_page(), _bt_update_meta_cleanup_info(), _bt_vacuum_needs_cleanup(), and _bt_walk_left().

730 {
731  Buffer buf;
732 
733  if (blkno != P_NEW)
734  {
735  /* Read an existing block of the relation */
736  buf = ReadBuffer(rel, blkno);
737  LockBuffer(buf, access);
738  _bt_checkpage(rel, buf);
739  }
740  else
741  {
742  bool needLock;
743  Page page;
744 
745  Assert(access == BT_WRITE);
746 
747  /*
748  * First see if the FSM knows of any free pages.
749  *
750  * We can't trust the FSM's report unreservedly; we have to check that
751  * the page is still free. (For example, an already-free page could
752  * have been re-used between the time the last VACUUM scanned it and
753  * the time the VACUUM made its FSM updates.)
754  *
755  * In fact, it's worse than that: we can't even assume that it's safe
756  * to take a lock on the reported page. If somebody else has a lock
757  * on it, or even worse our own caller does, we could deadlock. (The
758  * own-caller scenario is actually not improbable. Consider an index
759  * on a serial or timestamp column. Nearly all splits will be at the
760  * rightmost page, so it's entirely likely that _bt_split will call us
761  * while holding a lock on the page most recently acquired from FSM. A
762  * VACUUM running concurrently with the previous split could well have
763  * placed that page back in FSM.)
764  *
765  * To get around that, we ask for only a conditional lock on the
766  * reported page. If we fail, then someone else is using the page,
767  * and we may reasonably assume it's not free. (If we happen to be
768  * wrong, the worst consequence is the page will be lost to use till
769  * the next VACUUM, which is no big problem.)
770  */
771  for (;;)
772  {
773  blkno = GetFreeIndexPage(rel);
774  if (blkno == InvalidBlockNumber)
775  break;
776  buf = ReadBuffer(rel, blkno);
777  if (ConditionalLockBuffer(buf))
778  {
779  page = BufferGetPage(buf);
780  if (_bt_page_recyclable(page))
781  {
782  /*
783  * If we are generating WAL for Hot Standby then create a
784  * WAL record that will allow us to conflict with queries
785  * running on standby.
786  */
788  {
790 
791  _bt_log_reuse_page(rel, blkno, opaque->btpo.xact);
792  }
793 
794  /* Okay to use page. Re-initialize and return it */
795  _bt_pageinit(page, BufferGetPageSize(buf));
796  return buf;
797  }
798  elog(DEBUG2, "FSM returned nonrecyclable page");
799  _bt_relbuf(rel, buf);
800  }
801  else
802  {
803  elog(DEBUG2, "FSM returned nonlockable page");
804  /* couldn't get lock, so just drop pin */
805  ReleaseBuffer(buf);
806  }
807  }
808 
809  /*
810  * Extend the relation by one page.
811  *
812  * We have to use a lock to ensure no one else is extending the rel at
813  * the same time, else we will both try to initialize the same new
814  * page. We can skip locking for new or temp relations, however,
815  * since no one else could be accessing them.
816  */
817  needLock = !RELATION_IS_LOCAL(rel);
818 
819  if (needLock)
821 
822  buf = ReadBuffer(rel, P_NEW);
823 
824  /* Acquire buffer lock on new page */
825  LockBuffer(buf, BT_WRITE);
826 
827  /*
828  * Release the file-extension lock; it's now OK for someone else to
829  * extend the relation some more. Note that we cannot release this
830  * lock before we have buffer lock on the new page, or we risk a race
831  * condition against btvacuumscan --- see comments therein.
832  */
833  if (needLock)
835 
836  /* Initialize the new page before returning it */
837  page = BufferGetPage(buf);
838  Assert(PageIsNew(page));
839  _bt_pageinit(page, BufferGetPageSize(buf));
840  }
841 
842  /* ref count and lock type are correct */
843  return buf;
844 }
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:528
union BTPageOpaqueData::@46 btpo
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define P_NEW
Definition: bufmgr.h:82
bool _bt_page_recyclable(Page page)
Definition: nbtpage.c:903
TransactionId xact
Definition: nbtree.h:62
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:68
void _bt_checkpage(Relation rel, Buffer buf)
Definition: nbtpage.c:662
#define DEBUG2
Definition: elog.h:24
static char * buf
Definition: pg_test_fsync.c:67
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3572
static void _bt_log_reuse_page(Relation rel, BlockNumber blkno, TransactionId latestRemovedXid)
Definition: nbtpage.c:696
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:332
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:382
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:147
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define XLogStandbyInfoActive()
Definition: xlog.h:160
void _bt_relbuf(Relation rel, Buffer buf)
Definition: nbtpage.c:879
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38
#define Assert(condition)
Definition: c.h:699
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
#define InvalidBlockNumber
Definition: block.h:33
#define RelationNeedsWAL(relation)
Definition: rel.h:510
#define PageIsNew(page)
Definition: bufpage.h:225
void _bt_pageinit(Page page, Size size)
Definition: nbtpage.c:891
#define elog
Definition: elog.h:219
#define BT_WRITE
Definition: nbtree.h:301
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

◆ _bt_getroot()

Buffer _bt_getroot ( Relation  rel,
int  access 
)

Definition at line 252 of file nbtpage.c.

References _bt_cachemetadata(), _bt_getbuf(), _bt_getroot(), _bt_relandgetbuf(), _bt_relbuf(), _bt_upgrademetapage(), Assert, BT_READ, BT_WRITE, BTMetaPageData::btm_fastlevel, BTMetaPageData::btm_fastroot, BTMetaPageData::btm_last_cleanup_num_heap_tuples, BTMetaPageData::btm_level, BTMetaPageData::btm_magic, BTMetaPageData::btm_oldest_btpo_xact, BTMetaPageData::btm_root, BTMetaPageData::btm_version, BTP_LEAF, BTP_ROOT, BTPageGetMeta, BTPageOpaqueData::btpo, BTPageOpaqueData::btpo_cycleid, BTPageOpaqueData::btpo_flags, BTPageOpaqueData::btpo_next, BTPageOpaqueData::btpo_prev, BTREE_MAGIC, BTREE_METAPAGE, BTREE_MIN_VERSION, BTREE_VERSION, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage, elog, END_CRIT_SECTION, ereport, errcode(), errmsg(), ERROR, xl_btree_metadata::fastlevel, xl_btree_metadata::fastroot, InvalidBuffer, InvalidTransactionId, xl_btree_metadata::last_cleanup_num_heap_tuples, xl_btree_metadata::level, BTPageOpaqueData::level, xl_btree_newroot::level, LockBuffer(), MarkBufferDirty(), xl_btree_metadata::oldest_btpo_xact, P_IGNORE, P_ISMETA, P_LEFTMOST, P_NEW, P_NONE, P_RIGHTMOST, PageGetSpecialPointer, PageSetLSN, pfree(), RelationData::rd_amcache, REGBUF_STANDARD, REGBUF_WILL_INIT, RelationGetRelationName, RelationNeedsWAL, xl_btree_metadata::root, xl_btree_newroot::rootblk, SizeOfBtreeNewroot, START_CRIT_SECTION, XLOG_BTREE_NEWROOT, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by _bt_get_endpoint(), _bt_getroot(), and _bt_search().

253 {
254  Buffer metabuf;
255  Page metapg;
256  BTPageOpaque metaopaque;
257  Buffer rootbuf;
258  Page rootpage;
259  BTPageOpaque rootopaque;
260  BlockNumber rootblkno;
261  uint32 rootlevel;
262  BTMetaPageData *metad;
263 
264  /*
265  * Try to use previously-cached metapage data to find the root. This
266  * normally saves one buffer access per index search, which is a very
267  * helpful savings in bufmgr traffic and hence contention.
268  */
269  if (rel->rd_amcache != NULL)
270  {
271  metad = (BTMetaPageData *) rel->rd_amcache;
272  /* We shouldn't have cached it if any of these fail */
273  Assert(metad->btm_magic == BTREE_MAGIC);
275  Assert(metad->btm_version <= BTREE_VERSION);
276  Assert(metad->btm_root != P_NONE);
277 
278  rootblkno = metad->btm_fastroot;
279  Assert(rootblkno != P_NONE);
280  rootlevel = metad->btm_fastlevel;
281 
282  rootbuf = _bt_getbuf(rel, rootblkno, BT_READ);
283  rootpage = BufferGetPage(rootbuf);
284  rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
285 
286  /*
287  * Since the cache might be stale, we check the page more carefully
288  * here than normal. We *must* check that it's not deleted. If it's
289  * not alone on its level, then we reject too --- this may be overly
290  * paranoid but better safe than sorry. Note we don't check P_ISROOT,
291  * because that's not set in a "fast root".
292  */
293  if (!P_IGNORE(rootopaque) &&
294  rootopaque->btpo.level == rootlevel &&
295  P_LEFTMOST(rootopaque) &&
296  P_RIGHTMOST(rootopaque))
297  {
298  /* OK, accept cached page as the root */
299  return rootbuf;
300  }
301  _bt_relbuf(rel, rootbuf);
302  /* Cache is stale, throw it away */
303  if (rel->rd_amcache)
304  pfree(rel->rd_amcache);
305  rel->rd_amcache = NULL;
306  }
307 
308  metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
309  metapg = BufferGetPage(metabuf);
310  metaopaque = (BTPageOpaque) PageGetSpecialPointer(metapg);
311  metad = BTPageGetMeta(metapg);
312 
313  /* sanity-check the metapage */
314  if (!P_ISMETA(metaopaque) ||
315  metad->btm_magic != BTREE_MAGIC)
316  ereport(ERROR,
317  (errcode(ERRCODE_INDEX_CORRUPTED),
318  errmsg("index \"%s\" is not a btree",
319  RelationGetRelationName(rel))));
320 
321  if (metad->btm_version < BTREE_MIN_VERSION ||
322  metad->btm_version > BTREE_VERSION)
323  ereport(ERROR,
324  (errcode(ERRCODE_INDEX_CORRUPTED),
325  errmsg("version mismatch in index \"%s\": file version %d, "
326  "current version %d, minimal supported version %d",
329 
330  /* if no root page initialized yet, do it */
331  if (metad->btm_root == P_NONE)
332  {
333  /* If access = BT_READ, caller doesn't want us to create root yet */
334  if (access == BT_READ)
335  {
336  _bt_relbuf(rel, metabuf);
337  return InvalidBuffer;
338  }
339 
340  /* trade in our read lock for a write lock */
341  LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
342  LockBuffer(metabuf, BT_WRITE);
343 
344  /* upgrade metapage if needed */
345  if (metad->btm_version < BTREE_VERSION)
346  _bt_upgrademetapage(metapg);
347 
348  /*
349  * Race condition: if someone else initialized the metadata between
350  * the time we released the read lock and acquired the write lock, we
351  * must avoid doing it again.
352  */
353  if (metad->btm_root != P_NONE)
354  {
355  /*
356  * Metadata initialized by someone else. In order to guarantee no
357  * deadlocks, we have to release the metadata page and start all
358  * over again. (Is that really true? But it's hardly worth trying
359  * to optimize this case.)
360  */
361  _bt_relbuf(rel, metabuf);
362  return _bt_getroot(rel, access);
363  }
364 
365  /*
366  * Get, initialize, write, and leave a lock of the appropriate type on
367  * the new root page. Since this is the first page in the tree, it's
368  * a leaf as well as the root.
369  */
370  rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
371  rootblkno = BufferGetBlockNumber(rootbuf);
372  rootpage = BufferGetPage(rootbuf);
373  rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
374  rootopaque->btpo_prev = rootopaque->btpo_next = P_NONE;
375  rootopaque->btpo_flags = (BTP_LEAF | BTP_ROOT);
376  rootopaque->btpo.level = 0;
377  rootopaque->btpo_cycleid = 0;
378 
379  /* NO ELOG(ERROR) till meta is updated */
381 
382  metad->btm_root = rootblkno;
383  metad->btm_level = 0;
384  metad->btm_fastroot = rootblkno;
385  metad->btm_fastlevel = 0;
387  metad->btm_last_cleanup_num_heap_tuples = -1.0;
388 
389  MarkBufferDirty(rootbuf);
390  MarkBufferDirty(metabuf);
391 
392  /* XLOG stuff */
393  if (RelationNeedsWAL(rel))
394  {
395  xl_btree_newroot xlrec;
396  XLogRecPtr recptr;
398 
399  XLogBeginInsert();
402 
403  md.root = rootblkno;
404  md.level = 0;
405  md.fastroot = rootblkno;
406  md.fastlevel = 0;
409 
410  XLogRegisterBufData(2, (char *) &md, sizeof(xl_btree_metadata));
411 
412  xlrec.rootblk = rootblkno;
413  xlrec.level = 0;
414 
415  XLogRegisterData((char *) &xlrec, SizeOfBtreeNewroot);
416 
417  recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_NEWROOT);
418 
419  PageSetLSN(rootpage, recptr);
420  PageSetLSN(metapg, recptr);
421  }
422 
424 
425  /*
426  * swap root write lock for read lock. There is no danger of anyone
427  * else accessing the new root page while it's unlocked, since no one
428  * else knows where it is yet.
429  */
430  LockBuffer(rootbuf, BUFFER_LOCK_UNLOCK);
431  LockBuffer(rootbuf, BT_READ);
432 
433  /* okay, metadata is correct, release lock on it */
434  _bt_relbuf(rel, metabuf);
435  }
436  else
437  {
438  rootblkno = metad->btm_fastroot;
439  Assert(rootblkno != P_NONE);
440  rootlevel = metad->btm_fastlevel;
441 
442  /*
443  * Cache the metapage data for next time
444  */
445  _bt_cachemetadata(rel, metad);
446 
447  /*
448  * We are done with the metapage; arrange to release it via first
449  * _bt_relandgetbuf call
450  */
451  rootbuf = metabuf;
452 
453  for (;;)
454  {
455  rootbuf = _bt_relandgetbuf(rel, rootbuf, rootblkno, BT_READ);
456  rootpage = BufferGetPage(rootbuf);
457  rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
458 
459  if (!P_IGNORE(rootopaque))
460  break;
461 
462  /* it's dead, Jim. step right one page */
463  if (P_RIGHTMOST(rootopaque))
464  elog(ERROR, "no live root page found in index \"%s\"",
466  rootblkno = rootopaque->btpo_next;
467  }
468 
469  /* Note: can't check btpo.level on deleted pages */
470  if (rootopaque->btpo.level != rootlevel)
471  elog(ERROR, "root page %u of index \"%s\" has level %u, expected %u",
472  rootblkno, RelationGetRelationName(rel),
473  rootopaque->btpo.level, rootlevel);
474  }
475 
476  /*
477  * By here, we have a pin and read lock on the root page, and no lock set
478  * on the metadata page. Return the root page's buffer.
479  */
480  return rootbuf;
481 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
BlockNumber rootblk
Definition: nbtxlog.h:245
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
#define BTP_ROOT
Definition: nbtree.h:72
BlockNumber btpo_next
Definition: nbtree.h:58
#define P_IGNORE(opaque)
Definition: nbtree.h:163
void _bt_upgrademetapage(Page page)
Definition: nbtpage.c:86
uint32 btm_version
Definition: nbtree.h:100
Buffer _bt_relandgetbuf(Relation rel, Buffer obuf, BlockNumber blkno, int access)
Definition: nbtpage.c:860
Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access)
Definition: nbtpage.c:729
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define BTREE_VERSION
Definition: nbtree.h:117
uint32 btm_magic
Definition: nbtree.h:99
#define BTP_LEAF
Definition: nbtree.h:71
union BTPageOpaqueData::@46 btpo
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
BlockNumber root
Definition: nbtxlog.h:50
#define P_NONE
Definition: nbtree.h:150
#define InvalidBuffer
Definition: buf.h:25
#define REGBUF_WILL_INIT
Definition: xloginsert.h:32
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
int errcode(int sqlerrcode)
Definition: elog.c:575
uint32 level
Definition: nbtxlog.h:246
uint32 BlockNumber
Definition: block.h:31
#define P_NEW
Definition: bufmgr.h:82
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:68
#define P_ISMETA(opaque)
Definition: nbtree.h:161
#define BT_READ
Definition: nbtree.h:300
BlockNumber btm_fastroot
Definition: nbtree.h:103
#define XLOG_BTREE_NEWROOT
Definition: nbtxlog.h:36
void pfree(void *pointer)
Definition: mcxt.c:1031
#define BTREE_MAGIC
Definition: nbtree.h:116
#define ERROR
Definition: elog.h:43
float8 last_cleanup_num_heap_tuples
Definition: nbtxlog.h:55
BTCycleId btpo_cycleid
Definition: nbtree.h:65
TransactionId oldest_btpo_xact
Definition: nbtxlog.h:54
#define BTPageGetMeta(p)
Definition: nbtree.h:112
BlockNumber btpo_prev
Definition: nbtree.h:57
#define REGBUF_STANDARD
Definition: xloginsert.h:34
#define InvalidTransactionId
Definition: transam.h:31
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define P_LEFTMOST(opaque)
Definition: nbtree.h:156
unsigned int uint32
Definition: c.h:325
Buffer _bt_getroot(Relation rel, int access)
Definition: nbtpage.c:252
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
#define BTREE_METAPAGE
Definition: nbtree.h:115
#define SizeOfBtreeNewroot
Definition: nbtxlog.h:249
uint32 btm_fastlevel
Definition: nbtree.h:104
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
uint32 level
Definition: nbtree.h:61
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
BlockNumber btm_root
Definition: nbtree.h:101
#define BTREE_MIN_VERSION
Definition: nbtree.h:118
void _bt_relbuf(Relation rel, Buffer buf)
Definition: nbtpage.c:879
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:699
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
float8 btm_last_cleanup_num_heap_tuples
Definition: nbtree.h:108
#define RelationNeedsWAL(relation)
Definition: rel.h:510
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
int errmsg(const char *fmt,...)
Definition: elog.c:797
static void _bt_cachemetadata(Relation rel, BTMetaPageData *metad)
Definition: nbtpage.c:113
uint32 fastlevel
Definition: nbtxlog.h:53
uint32 btm_level
Definition: nbtree.h:102
uint32 level
Definition: nbtxlog.h:51
BlockNumber fastroot
Definition: nbtxlog.h:52
#define elog
Definition: elog.h:219
TransactionId btm_oldest_btpo_xact
Definition: nbtree.h:106
void * rd_amcache
Definition: rel.h:164
#define BT_WRITE
Definition: nbtree.h:301
void XLogBeginInsert(void)
Definition: xloginsert.c:120
uint16 btpo_flags
Definition: nbtree.h:64
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
int Buffer
Definition: buf.h:23
#define P_RIGHTMOST(opaque)
Definition: nbtree.h:157
Pointer Page
Definition: bufpage.h:74

◆ _bt_getrootheight()

int _bt_getrootheight ( Relation  rel)

Definition at line 594 of file nbtpage.c.

References _bt_cachemetadata(), _bt_getbuf(), _bt_relbuf(), Assert, BT_READ, BTMetaPageData::btm_fastlevel, BTMetaPageData::btm_fastroot, BTMetaPageData::btm_magic, BTMetaPageData::btm_root, BTMetaPageData::btm_version, BTPageGetMeta, BTREE_MAGIC, BTREE_METAPAGE, BTREE_MIN_VERSION, BTREE_VERSION, BufferGetPage, ereport, errcode(), errmsg(), ERROR, P_ISMETA, P_NONE, PageGetSpecialPointer, RelationData::rd_amcache, and RelationGetRelationName.

Referenced by _bt_insertonpg(), and get_relation_info().

595 {
596  BTMetaPageData *metad;
597 
598  /*
599  * We can get what we need from the cached metapage data. If it's not
600  * cached yet, load it. Sanity checks here must match _bt_getroot().
601  */
602  if (rel->rd_amcache == NULL)
603  {
604  Buffer metabuf;
605  Page metapg;
606  BTPageOpaque metaopaque;
607 
608  metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
609  metapg = BufferGetPage(metabuf);
610  metaopaque = (BTPageOpaque) PageGetSpecialPointer(metapg);
611  metad = BTPageGetMeta(metapg);
612 
613  /* sanity-check the metapage */
614  if (!P_ISMETA(metaopaque) ||
615  metad->btm_magic != BTREE_MAGIC)
616  ereport(ERROR,
617  (errcode(ERRCODE_INDEX_CORRUPTED),
618  errmsg("index \"%s\" is not a btree",
619  RelationGetRelationName(rel))));
620 
621  if (metad->btm_version < BTREE_MIN_VERSION ||
622  metad->btm_version > BTREE_VERSION)
623  ereport(ERROR,
624  (errcode(ERRCODE_INDEX_CORRUPTED),
625  errmsg("version mismatch in index \"%s\": file version %d, "
626  "current version %d, minimal supported version %d",
629 
630  /*
631  * If there's no root page yet, _bt_getroot() doesn't expect a cache
632  * to be made, so just stop here and report the index height is zero.
633  * (XXX perhaps _bt_getroot() should be changed to allow this case.)
634  */
635  if (metad->btm_root == P_NONE)
636  {
637  _bt_relbuf(rel, metabuf);
638  return 0;
639  }
640 
641  /*
642  * Cache the metapage data for next time
643  */
644  _bt_cachemetadata(rel, metad);
645 
646  _bt_relbuf(rel, metabuf);
647  }
648 
649  metad = (BTMetaPageData *) rel->rd_amcache;
650  /* We shouldn't have cached it if any of these fail */
651  Assert(metad->btm_magic == BTREE_MAGIC);
652  Assert(metad->btm_version == BTREE_VERSION);
653  Assert(metad->btm_fastroot != P_NONE);
654 
655  return metad->btm_fastlevel;
656 }
uint32 btm_version
Definition: nbtree.h:100
Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access)
Definition: nbtpage.c:729
#define BTREE_VERSION
Definition: nbtree.h:117
uint32 btm_magic
Definition: nbtree.h:99
#define P_NONE
Definition: nbtree.h:150
int errcode(int sqlerrcode)
Definition: elog.c:575
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:68
#define P_ISMETA(opaque)
Definition: nbtree.h:161
#define BT_READ
Definition: nbtree.h:300
BlockNumber btm_fastroot
Definition: nbtree.h:103
#define BTREE_MAGIC
Definition: nbtree.h:116
#define ERROR
Definition: elog.h:43
#define BTPageGetMeta(p)
Definition: nbtree.h:112
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
#define BTREE_METAPAGE
Definition: nbtree.h:115
uint32 btm_fastlevel
Definition: nbtree.h:104
BlockNumber btm_root
Definition: nbtree.h:101
#define BTREE_MIN_VERSION
Definition: nbtree.h:118
void _bt_relbuf(Relation rel, Buffer buf)
Definition: nbtpage.c:879
#define Assert(condition)
Definition: c.h:699
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
int errmsg(const char *fmt,...)
Definition: elog.c:797
static void _bt_cachemetadata(Relation rel, BTMetaPageData *metad)
Definition: nbtpage.c:113
void * rd_amcache
Definition: rel.h:164
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

◆ _bt_gettrueroot()

Buffer _bt_gettrueroot ( Relation  rel)

Definition at line 498 of file nbtpage.c.

References _bt_getbuf(), _bt_relandgetbuf(), _bt_relbuf(), BT_READ, BTMetaPageData::btm_level, BTMetaPageData::btm_magic, BTMetaPageData::btm_root, BTMetaPageData::btm_version, BTPageGetMeta, BTPageOpaqueData::btpo, BTPageOpaqueData::btpo_next, BTREE_MAGIC, BTREE_METAPAGE, BTREE_MIN_VERSION, BTREE_VERSION, BufferGetPage, elog, ereport, errcode(), errmsg(), ERROR, InvalidBuffer, BTPageOpaqueData::level, P_IGNORE, P_ISMETA, P_NONE, P_RIGHTMOST, PageGetSpecialPointer, pfree(), RelationData::rd_amcache, and RelationGetRelationName.

Referenced by _bt_get_endpoint().

499 {
500  Buffer metabuf;
501  Page metapg;
502  BTPageOpaque metaopaque;
503  Buffer rootbuf;
504  Page rootpage;
505  BTPageOpaque rootopaque;
506  BlockNumber rootblkno;
507  uint32 rootlevel;
508  BTMetaPageData *metad;
509 
510  /*
511  * We don't try to use cached metapage data here, since (a) this path is
512  * not performance-critical, and (b) if we are here it suggests our cache
513  * is out-of-date anyway. In light of point (b), it's probably safest to
514  * actively flush any cached metapage info.
515  */
516  if (rel->rd_amcache)
517  pfree(rel->rd_amcache);
518  rel->rd_amcache = NULL;
519 
520  metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
521  metapg = BufferGetPage(metabuf);
522  metaopaque = (BTPageOpaque) PageGetSpecialPointer(metapg);
523  metad = BTPageGetMeta(metapg);
524 
525  if (!P_ISMETA(metaopaque) ||
526  metad->btm_magic != BTREE_MAGIC)
527  ereport(ERROR,
528  (errcode(ERRCODE_INDEX_CORRUPTED),
529  errmsg("index \"%s\" is not a btree",
530  RelationGetRelationName(rel))));
531 
532  if (metad->btm_version < BTREE_MIN_VERSION ||
533  metad->btm_version > BTREE_VERSION)
534  ereport(ERROR,
535  (errcode(ERRCODE_INDEX_CORRUPTED),
536  errmsg("version mismatch in index \"%s\": file version %d, "
537  "current version %d, minimal supported version %d",
540 
541  /* if no root page initialized yet, fail */
542  if (metad->btm_root == P_NONE)
543  {
544  _bt_relbuf(rel, metabuf);
545  return InvalidBuffer;
546  }
547 
548  rootblkno = metad->btm_root;
549  rootlevel = metad->btm_level;
550 
551  /*
552  * We are done with the metapage; arrange to release it via first
553  * _bt_relandgetbuf call
554  */
555  rootbuf = metabuf;
556 
557  for (;;)
558  {
559  rootbuf = _bt_relandgetbuf(rel, rootbuf, rootblkno, BT_READ);
560  rootpage = BufferGetPage(rootbuf);
561  rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
562 
563  if (!P_IGNORE(rootopaque))
564  break;
565 
566  /* it's dead, Jim. step right one page */
567  if (P_RIGHTMOST(rootopaque))
568  elog(ERROR, "no live root page found in index \"%s\"",
570  rootblkno = rootopaque->btpo_next;
571  }
572 
573  /* Note: can't check btpo.level on deleted pages */
574  if (rootopaque->btpo.level != rootlevel)
575  elog(ERROR, "root page %u of index \"%s\" has level %u, expected %u",
576  rootblkno, RelationGetRelationName(rel),
577  rootopaque->btpo.level, rootlevel);
578 
579  return rootbuf;
580 }
BlockNumber btpo_next
Definition: nbtree.h:58
#define P_IGNORE(opaque)
Definition: nbtree.h:163
uint32 btm_version
Definition: nbtree.h:100
Buffer _bt_relandgetbuf(Relation rel, Buffer obuf, BlockNumber blkno, int access)
Definition: nbtpage.c:860
Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access)
Definition: nbtpage.c:729
#define BTREE_VERSION
Definition: nbtree.h:117
uint32 btm_magic
Definition: nbtree.h:99
union BTPageOpaqueData::@46 btpo
#define P_NONE
Definition: nbtree.h:150
#define InvalidBuffer
Definition: buf.h:25
int errcode(int sqlerrcode)
Definition: elog.c:575
uint32 BlockNumber
Definition: block.h:31
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:68
#define P_ISMETA(opaque)
Definition: nbtree.h:161
#define BT_READ
Definition: nbtree.h:300
void pfree(void *pointer)
Definition: mcxt.c:1031
#define BTREE_MAGIC
Definition: nbtree.h:116
#define ERROR
Definition: elog.h:43
#define BTPageGetMeta(p)
Definition: nbtree.h:112
#define RelationGetRelationName(relation)
Definition: rel.h:441
unsigned int uint32
Definition: c.h:325
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
#define BTREE_METAPAGE
Definition: nbtree.h:115
uint32 level
Definition: nbtree.h:61
BlockNumber btm_root
Definition: nbtree.h:101
#define BTREE_MIN_VERSION
Definition: nbtree.h:118
void _bt_relbuf(Relation rel, Buffer buf)
Definition: nbtpage.c:879
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
int errmsg(const char *fmt,...)
Definition: elog.c:797
uint32 btm_level
Definition: nbtree.h:102
#define elog
Definition: elog.h:219
void * rd_amcache
Definition: rel.h:164
int Buffer
Definition: buf.h:23
#define P_RIGHTMOST(opaque)
Definition: nbtree.h:157
Pointer Page
Definition: bufpage.h:74

◆ _bt_initmetapage()

void _bt_initmetapage ( Page  page,
BlockNumber  rootbknum,
uint32  level 
)

Definition at line 50 of file nbtpage.c.

References _bt_pageinit(), BTMetaPageData::btm_fastlevel, BTMetaPageData::btm_fastroot, BTMetaPageData::btm_last_cleanup_num_heap_tuples, BTMetaPageData::btm_level, BTMetaPageData::btm_magic, BTMetaPageData::btm_oldest_btpo_xact, BTMetaPageData::btm_root, BTMetaPageData::btm_version, BTP_META, BTPageGetMeta, BTPageOpaqueData::btpo_flags, BTREE_MAGIC, BTREE_VERSION, InvalidTransactionId, and PageGetSpecialPointer.

Referenced by _bt_uppershutdown(), and btbuildempty().

51 {
52  BTMetaPageData *metad;
53  BTPageOpaque metaopaque;
54 
55  _bt_pageinit(page, BLCKSZ);
56 
57  metad = BTPageGetMeta(page);
58  metad->btm_magic = BTREE_MAGIC;
59  metad->btm_version = BTREE_VERSION;
60  metad->btm_root = rootbknum;
61  metad->btm_level = level;
62  metad->btm_fastroot = rootbknum;
63  metad->btm_fastlevel = level;
66 
67  metaopaque = (BTPageOpaque) PageGetSpecialPointer(page);
68  metaopaque->btpo_flags = BTP_META;
69 
70  /*
71  * Set pd_lower just past the end of the metadata. This is essential,
72  * because without doing so, metadata will be lost if xlog.c compresses
73  * the page.
74  */
75  ((PageHeader) page)->pd_lower =
76  ((char *) metad + sizeof(BTMetaPageData)) - (char *) page;
77 }
uint32 btm_version
Definition: nbtree.h:100
#define BTREE_VERSION
Definition: nbtree.h:117
uint32 btm_magic
Definition: nbtree.h:99
#define BTP_META
Definition: nbtree.h:74
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:68
BlockNumber btm_fastroot
Definition: nbtree.h:103
#define BTREE_MAGIC
Definition: nbtree.h:116
#define BTPageGetMeta(p)
Definition: nbtree.h:112
#define InvalidTransactionId
Definition: transam.h:31
uint32 btm_fastlevel
Definition: nbtree.h:104
BlockNumber btm_root
Definition: nbtree.h:101
PageHeaderData * PageHeader
Definition: bufpage.h:162
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
float8 btm_last_cleanup_num_heap_tuples
Definition: nbtree.h:108
uint32 btm_level
Definition: nbtree.h:102
void _bt_pageinit(Page page, Size size)
Definition: nbtpage.c:891
TransactionId btm_oldest_btpo_xact
Definition: nbtree.h:106
uint16 btpo_flags
Definition: nbtree.h:64

◆ _bt_is_page_halfdead()

static bool _bt_is_page_halfdead ( Relation  rel,
BlockNumber  blk 
)
static

Definition at line 1086 of file nbtpage.c.

References _bt_getbuf(), _bt_relbuf(), BT_READ, buf, BufferGetPage, P_ISHALFDEAD, and PageGetSpecialPointer.

Referenced by _bt_lock_branch_parent(), and _bt_mark_page_halfdead().

1087 {
1088  Buffer buf;
1089  Page page;
1090  BTPageOpaque opaque;
1091  bool result;
1092 
1093  buf = _bt_getbuf(rel, blk, BT_READ);
1094  page = BufferGetPage(buf);
1095  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1096 
1097  result = P_ISHALFDEAD(opaque);
1098  _bt_relbuf(rel, buf);
1099 
1100  return result;
1101 }
Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access)
Definition: nbtpage.c:729
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:68
#define BT_READ
Definition: nbtree.h:300
#define P_ISHALFDEAD(opaque)
Definition: nbtree.h:162
static char * buf
Definition: pg_test_fsync.c:67
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void _bt_relbuf(Relation rel, Buffer buf)
Definition: nbtpage.c:879
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

◆ _bt_lock_branch_parent()

static bool _bt_lock_branch_parent ( Relation  rel,
BlockNumber  child,
BTStack  stack,
Buffer topparent,
OffsetNumber topoff,
BlockNumber target,
BlockNumber rightsib 
)
static

Definition at line 1130 of file nbtpage.c.

References _bt_getbuf(), _bt_getstackbuf(), _bt_is_page_halfdead(), _bt_relbuf(), BT_READ, BT_WRITE, BTPageOpaqueData::btpo_next, BTPageOpaqueData::btpo_prev, BTStackData::bts_blkno, BTStackData::bts_btentry, BTStackData::bts_offset, BTStackData::bts_parent, BufferGetPage, DEBUG1, elog, ERROR, InvalidBuffer, P_FIRSTDATAKEY, P_INCOMPLETE_SPLIT, P_ISROOT, P_NONE, P_RIGHTMOST, PageGetMaxOffsetNumber, PageGetSpecialPointer, and RelationGetRelationName.

Referenced by _bt_mark_page_halfdead().

1133 {
1134  BlockNumber parent;
1135  OffsetNumber poffset,
1136  maxoff;
1137  Buffer pbuf;
1138  Page page;
1139  BTPageOpaque opaque;
1140  BlockNumber leftsib;
1141 
1142  /*
1143  * Locate the downlink of "child" in the parent (updating the stack entry
1144  * if needed)
1145  */
1146  stack->bts_btentry = child;
1147  pbuf = _bt_getstackbuf(rel, stack, BT_WRITE);
1148  if (pbuf == InvalidBuffer)
1149  elog(ERROR, "failed to re-find parent key in index \"%s\" for deletion target page %u",
1150  RelationGetRelationName(rel), child);
1151  parent = stack->bts_blkno;
1152  poffset = stack->bts_offset;
1153 
1154  page = BufferGetPage(pbuf);
1155  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1156  maxoff = PageGetMaxOffsetNumber(page);
1157 
1158  /*
1159  * If the target is the rightmost child of its parent, then we can't
1160  * delete, unless it's also the only child.
1161  */
1162  if (poffset >= maxoff)
1163  {
1164  /* It's rightmost child... */
1165  if (poffset == P_FIRSTDATAKEY(opaque))
1166  {
1167  /*
1168  * It's only child, so safe if parent would itself be removable.
1169  * We have to check the parent itself, and then recurse to test
1170  * the conditions at the parent's parent.
1171  */
1172  if (P_RIGHTMOST(opaque) || P_ISROOT(opaque) ||
1173  P_INCOMPLETE_SPLIT(opaque))
1174  {
1175  _bt_relbuf(rel, pbuf);
1176  return false;
1177  }
1178 
1179  *target = parent;
1180  *rightsib = opaque->btpo_next;
1181  leftsib = opaque->btpo_prev;
1182 
1183  _bt_relbuf(rel, pbuf);
1184 
1185  /*
1186  * Like in _bt_pagedel, check that the left sibling is not marked
1187  * with INCOMPLETE_SPLIT flag. That would mean that there is no
1188  * downlink to the page to be deleted, and the page deletion
1189  * algorithm isn't prepared to handle that.
1190  */
1191  if (leftsib != P_NONE)
1192  {
1193  Buffer lbuf;
1194  Page lpage;
1195  BTPageOpaque lopaque;
1196 
1197  lbuf = _bt_getbuf(rel, leftsib, BT_READ);
1198  lpage = BufferGetPage(lbuf);
1199  lopaque = (BTPageOpaque) PageGetSpecialPointer(lpage);
1200 
1201  /*
1202  * If the left sibling was concurrently split, so that its
1203  * next-pointer doesn't point to the current page anymore, the
1204  * split that created the current page must be completed. (We
1205  * don't allow splitting an incompletely split page again
1206  * until the previous split has been completed)
1207  */
1208  if (lopaque->btpo_next == parent &&
1209  P_INCOMPLETE_SPLIT(lopaque))
1210  {
1211  _bt_relbuf(rel, lbuf);
1212  return false;
1213  }
1214  _bt_relbuf(rel, lbuf);
1215  }
1216 
1217  /*
1218  * Perform the same check on this internal level that
1219  * _bt_mark_page_halfdead performed on the leaf level.
1220  */
1221  if (_bt_is_page_halfdead(rel, *rightsib))
1222  {
1223  elog(DEBUG1, "could not delete page %u because its right sibling %u is half-dead",
1224  parent, *rightsib);
1225  return false;
1226  }
1227 
1228  return _bt_lock_branch_parent(rel, parent, stack->bts_parent,
1229  topparent, topoff, target, rightsib);
1230  }
1231  else
1232  {
1233  /* Unsafe to delete */
1234  _bt_relbuf(rel, pbuf);
1235  return false;
1236  }
1237  }
1238  else
1239  {
1240  /* Not rightmost child, so safe to delete */
1241  *topparent = pbuf;
1242  *topoff = poffset;
1243  return true;
1244  }
1245 }
Buffer _bt_getstackbuf(Relation rel, BTStack stack, int access)
Definition: nbtinsert.c:1997
BlockNumber btpo_next
Definition: nbtree.h:58
#define DEBUG1
Definition: elog.h:25
Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access)
Definition: nbtpage.c:729
#define P_FIRSTDATAKEY(opaque)
Definition: nbtree.h:187
#define P_NONE
Definition: nbtree.h:150
#define InvalidBuffer
Definition: buf.h:25
uint32 BlockNumber
Definition: block.h:31
#define P_INCOMPLETE_SPLIT(opaque)
Definition: nbtree.h:165
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:68
uint16 OffsetNumber
Definition: off.h:24
#define BT_READ
Definition: nbtree.h:300
#define ERROR
Definition: elog.h:43
static bool _bt_lock_branch_parent(Relation rel, BlockNumber child, BTStack stack, Buffer *topparent, OffsetNumber *topoff, BlockNumber *target, BlockNumber *rightsib)
Definition: nbtpage.c:1130
BlockNumber btpo_prev
Definition: nbtree.h:57
OffsetNumber bts_offset
Definition: nbtree.h:316
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define P_ISROOT(opaque)
Definition: nbtree.h:159
static bool _bt_is_page_halfdead(Relation rel, BlockNumber blk)
Definition: nbtpage.c:1086
BlockNumber bts_blkno
Definition: nbtree.h:315
void _bt_relbuf(Relation rel, Buffer buf)
Definition: nbtpage.c:879
BlockNumber bts_btentry
Definition: nbtree.h:317
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
struct BTStackData * bts_parent
Definition: nbtree.h:318
#define elog
Definition: elog.h:219
#define BT_WRITE
Definition: nbtree.h:301
int Buffer
Definition: buf.h:23
#define P_RIGHTMOST(opaque)
Definition: nbtree.h:157
Pointer Page
Definition: bufpage.h:74

◆ _bt_log_reuse_page()

static void _bt_log_reuse_page ( Relation  rel,
BlockNumber  blkno,
TransactionId  latestRemovedXid 
)
static

Definition at line 696 of file nbtpage.c.

References xl_btree_reuse_page::block, xl_btree_reuse_page::latestRemovedXid, xl_btree_reuse_page::node, RelationData::rd_node, SizeOfBtreeReusePage, XLOG_BTREE_REUSE_PAGE, XLogBeginInsert(), XLogInsert(), and XLogRegisterData().

Referenced by _bt_getbuf().

697 {
698  xl_btree_reuse_page xlrec_reuse;
699 
700  /*
701  * Note that we don't register the buffer with the record, because this
702  * operation doesn't modify the page. This record only exists to provide a
703  * conflict point for Hot Standby.
704  */
705 
706  /* XLOG stuff */
707  xlrec_reuse.node = rel->rd_node;
708  xlrec_reuse.block = blkno;
709  xlrec_reuse.latestRemovedXid = latestRemovedXid;
710 
711  XLogBeginInsert();
712  XLogRegisterData((char *) &xlrec_reuse, SizeOfBtreeReusePage);
713 
714  XLogInsert(RM_BTREE_ID, XLOG_BTREE_REUSE_PAGE);
715 }
RelFileNode node
Definition: nbtxlog.h:140
#define SizeOfBtreeReusePage
Definition: nbtxlog.h:145
BlockNumber block
Definition: nbtxlog.h:141
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
#define XLOG_BTREE_REUSE_PAGE
Definition: nbtxlog.h:40
RelFileNode rd_node
Definition: rel.h:55
TransactionId latestRemovedXid
Definition: nbtxlog.h:142
void XLogBeginInsert(void)
Definition: xloginsert.c:120

◆ _bt_mark_page_halfdead()

static bool _bt_mark_page_halfdead ( Relation  rel,
Buffer  buf,
BTStack  stack 
)
static

Definition at line 1481 of file nbtpage.c.

References _bt_is_page_halfdead(), _bt_lock_branch_parent(), _bt_relbuf(), Assert, BTP_HALF_DEAD, BTPageOpaqueData::btpo_flags, BTPageOpaqueData::btpo_next, BTPageOpaqueData::btpo_prev, BTreeInnerTupleGetDownLink, BTreeInnerTupleSetDownLink, BTreeTupleSetTopParent, BufferGetBlockNumber(), BufferGetPage, DEBUG1, elog, END_CRIT_SECTION, ERROR, InvalidBlockNumber, InvalidOffsetNumber, xl_btree_mark_page_halfdead::leafblk, xl_btree_mark_page_halfdead::leftblk, MarkBufferDirty(), MemSet, OffsetNumberNext, P_FIRSTDATAKEY, P_HIKEY, P_ISDELETED, P_ISHALFDEAD, P_ISLEAF, P_ISROOT, P_RIGHTMOST, PageAddItem, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageGetSpecialPointer, PageIndexTupleDelete(), PageSetLSN, xl_btree_mark_page_halfdead::poffset, PredicateLockPageCombine(), REGBUF_STANDARD, REGBUF_WILL_INIT, RelationGetRelationName, RelationNeedsWAL, xl_btree_mark_page_halfdead::rightblk, SizeOfBtreeMarkPageHalfDead, START_CRIT_SECTION, IndexTupleData::t_info, xl_btree_mark_page_halfdead::topparent, XLOG_BTREE_MARK_PAGE_HALFDEAD, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by _bt_pagedel().

1482 {
1483  BlockNumber leafblkno;
1484  BlockNumber leafrightsib;
1485  BlockNumber target;
1486  BlockNumber rightsib;
1487  ItemId itemid;
1488  Page page;
1489  BTPageOpaque opaque;
1490  Buffer topparent;
1491  OffsetNumber topoff;
1492  OffsetNumber nextoffset;
1493  IndexTuple itup;
1494  IndexTupleData trunctuple;
1495 
1496  page = BufferGetPage(leafbuf);
1497  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1498 
1499  Assert(!P_RIGHTMOST(opaque) && !P_ISROOT(opaque) && !P_ISDELETED(opaque) &&
1500  !P_ISHALFDEAD(opaque) && P_ISLEAF(opaque) &&
1501  P_FIRSTDATAKEY(opaque) > PageGetMaxOffsetNumber(page));
1502 
1503  /*
1504  * Save info about the leaf page.
1505  */
1506  leafblkno = BufferGetBlockNumber(leafbuf);
1507  leafrightsib = opaque->btpo_next;
1508 
1509  /*
1510  * Before attempting to lock the parent page, check that the right sibling
1511  * is not in half-dead state. A half-dead right sibling would have no
1512  * downlink in the parent, which would be highly confusing later when we
1513  * delete the downlink that follows the current page's downlink. (I
1514  * believe the deletion would work correctly, but it would fail the
1515  * cross-check we make that the following downlink points to the right
1516  * sibling of the delete page.)
1517  */
1518  if (_bt_is_page_halfdead(rel, leafrightsib))
1519  {
1520  elog(DEBUG1, "could not delete page %u because its right sibling %u is half-dead",
1521  leafblkno, leafrightsib);
1522  return false;
1523  }
1524 
1525  /*
1526  * We cannot delete a page that is the rightmost child of its immediate
1527  * parent, unless it is the only child --- in which case the parent has to
1528  * be deleted too, and the same condition applies recursively to it. We
1529  * have to check this condition all the way up before trying to delete,
1530  * and lock the final parent of the to-be-deleted branch.
1531  */
1532  rightsib = leafrightsib;
1533  target = leafblkno;
1534  if (!_bt_lock_branch_parent(rel, leafblkno, stack,
1535  &topparent, &topoff, &target, &rightsib))
1536  return false;
1537 
1538  /*
1539  * Check that the parent-page index items we're about to delete/overwrite
1540  * contain what we expect. This can fail if the index has become corrupt
1541  * for some reason. We want to throw any error before entering the
1542  * critical section --- otherwise it'd be a PANIC.
1543  *
1544  * The test on the target item is just an Assert because
1545  * _bt_lock_branch_parent should have guaranteed it has the expected
1546  * contents. The test on the next-child downlink is known to sometimes
1547  * fail in the field, though.
1548  */
1549  page = BufferGetPage(topparent);
1550  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1551 
1552 #ifdef USE_ASSERT_CHECKING
1553  itemid = PageGetItemId(page, topoff);
1554  itup = (IndexTuple) PageGetItem(page, itemid);
1555  Assert(BTreeInnerTupleGetDownLink(itup) == target);
1556 #endif
1557 
1558  nextoffset = OffsetNumberNext(topoff);
1559  itemid = PageGetItemId(page, nextoffset);
1560  itup = (IndexTuple) PageGetItem(page, itemid);
1561  if (BTreeInnerTupleGetDownLink(itup) != rightsib)
1562  elog(ERROR, "right sibling %u of block %u is not next child %u of block %u in index \"%s\"",
1563  rightsib, target, BTreeInnerTupleGetDownLink(itup),
1565 
1566  /*
1567  * Any insert which would have gone on the leaf block will now go to its
1568  * right sibling.
1569  */
1570  PredicateLockPageCombine(rel, leafblkno, leafrightsib);
1571 
1572  /* No ereport(ERROR) until changes are logged */
1574 
1575  /*
1576  * Update parent. The normal case is a tad tricky because we want to
1577  * delete the target's downlink and the *following* key. Easiest way is
1578  * to copy the right sibling's downlink over the target downlink, and then
1579  * delete the following item.
1580  */
1581  page = BufferGetPage(topparent);
1582  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1583 
1584  itemid = PageGetItemId(page, topoff);
1585  itup = (IndexTuple) PageGetItem(page, itemid);
1586  BTreeInnerTupleSetDownLink(itup, rightsib);
1587 
1588  nextoffset = OffsetNumberNext(topoff);
1589  PageIndexTupleDelete(page, nextoffset);
1590 
1591  /*
1592  * Mark the leaf page as half-dead, and stamp it with a pointer to the
1593  * highest internal page in the branch we're deleting. We use the tid of
1594  * the high key to store it.
1595  */
1596  page = BufferGetPage(leafbuf);
1597  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1598  opaque->btpo_flags |= BTP_HALF_DEAD;
1599 
1601  Assert(PageGetMaxOffsetNumber(page) == 0);
1602  MemSet(&trunctuple, 0, sizeof(IndexTupleData));
1603  trunctuple.t_info = sizeof(IndexTupleData);
1604  if (target != leafblkno)
1605  BTreeTupleSetTopParent(&trunctuple, target);
1606  else
1608 
1609  if (PageAddItem(page, (Item) &trunctuple, sizeof(IndexTupleData), P_HIKEY,
1610  false, false) == InvalidOffsetNumber)
1611  elog(ERROR, "could not add dummy high key to half-dead page");
1612 
1613  /* Must mark buffers dirty before XLogInsert */
1614  MarkBufferDirty(topparent);
1615  MarkBufferDirty(leafbuf);
1616 
1617  /* XLOG stuff */
1618  if (RelationNeedsWAL(rel))
1619  {
1621  XLogRecPtr recptr;
1622 
1623  xlrec.poffset = topoff;
1624  xlrec.leafblk = leafblkno;
1625  if (target != leafblkno)
1626  xlrec.topparent = target;
1627  else
1628  xlrec.topparent = InvalidBlockNumber;
1629 
1630  XLogBeginInsert();
1631  XLogRegisterBuffer(0, leafbuf, REGBUF_WILL_INIT);
1632  XLogRegisterBuffer(1, topparent, REGBUF_STANDARD);
1633 
1634  page = BufferGetPage(leafbuf);
1635  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1636  xlrec.leftblk = opaque->btpo_prev;
1637  xlrec.rightblk = opaque->btpo_next;
1638 
1640 
1641  recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_MARK_PAGE_HALFDEAD);
1642 
1643  page = BufferGetPage(topparent);
1644  PageSetLSN(page, recptr);
1645  page = BufferGetPage(leafbuf);
1646  PageSetLSN(page, recptr);
1647  }
1648 
1649  END_CRIT_SECTION();
1650 
1651  _bt_relbuf(rel, topparent);
1652  return true;
1653 }
BlockNumber btpo_next
Definition: nbtree.h:58
#define DEBUG1
Definition: elog.h:25
#define BTreeInnerTupleGetDownLink(itup)
Definition: nbtree.h:224
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:723
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define P_FIRSTDATAKEY(opaque)
Definition: nbtree.h:187
#define SizeOfBtreeMarkPageHalfDead
Definition: nbtxlog.h:200
#define BTP_HALF_DEAD
Definition: nbtree.h:75
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
Pointer Item
Definition: item.h:17
#define REGBUF_WILL_INIT
Definition: xloginsert.h:32
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
#define MemSet(start, val, len)
Definition: c.h:908
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:412
uint32 BlockNumber
Definition: block.h:31
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:68
uint16 OffsetNumber
Definition: off.h:24
#define P_ISHALFDEAD(opaque)
Definition: nbtree.h:162
#define ERROR
Definition: elog.h:43
#define BTreeTupleSetTopParent(itup, blkno)
Definition: nbtree.h:237
static bool _bt_lock_branch_parent(Relation rel, BlockNumber child, BTStack stack, Buffer *topparent, OffsetNumber *topoff, BlockNumber *target, BlockNumber *rightsib)
Definition: nbtpage.c:1130
BlockNumber btpo_prev
Definition: nbtree.h:57
IndexTupleData * IndexTuple
Definition: itup.h:53
#define REGBUF_STANDARD
Definition: xloginsert.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define P_ISDELETED(opaque)
Definition: nbtree.h:160
#define P_ISROOT(opaque)
Definition: nbtree.h:159
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
static bool _bt_is_page_halfdead(Relation rel, BlockNumber blk)
Definition: nbtpage.c:1086
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
#define XLOG_BTREE_MARK_PAGE_HALFDEAD
Definition: nbtxlog.h:37
struct IndexTupleData IndexTupleData
#define InvalidOffsetNumber
Definition: off.h:26
void _bt_relbuf(Relation rel, Buffer buf)
Definition: nbtpage.c:879
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:699
#define OffsetNumberNext(offsetNumber)
Definition: off.h:53
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
#define InvalidBlockNumber
Definition: block.h:33
#define RelationNeedsWAL(relation)
Definition: rel.h:510
#define BTreeInnerTupleSetDownLink(itup, blkno)
Definition: nbtree.h:226
#define P_HIKEY
Definition: nbtree.h:185
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
void PredicateLockPageCombine(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3150
#define elog
Definition: elog.h:219
unsigned short t_info
Definition: itup.h:49
void XLogBeginInsert(void)
Definition: xloginsert.c:120
uint16 btpo_flags
Definition: nbtree.h:64
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
int Buffer
Definition: buf.h:23
#define P_RIGHTMOST(opaque)
Definition: nbtree.h:157
#define PageGetItem(page, itemId)
Definition: bufpage.h:336
Pointer Page
Definition: bufpage.h:74
#define P_ISLEAF(opaque)
Definition: nbtree.h:158

◆ _bt_page_recyclable()

bool _bt_page_recyclable ( Page  page)

Definition at line 903 of file nbtpage.c.

References BTPageOpaqueData::btpo, P_ISDELETED, PageGetSpecialPointer, PageIsNew, RecentGlobalXmin, TransactionIdPrecedes(), and BTPageOpaqueData::xact.

Referenced by _bt_getbuf(), and btvacuumpage().

904 {
905  BTPageOpaque opaque;
906 
907  /*
908  * It's possible to find an all-zeroes page in an index --- for example, a
909  * backend might successfully extend the relation one page and then crash
910  * before it is able to make a WAL entry for adding the page. If we find a
911  * zeroed page then reclaim it.
912  */
913  if (PageIsNew(page))
914  return true;
915 
916  /*
917  * Otherwise, recycle if deleted and too old to have any processes
918  * interested in it.
919  */
920  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
921  if (P_ISDELETED(opaque) &&
923  return true;
924  return false;
925 }
union BTPageOpaqueData::@46 btpo
TransactionId xact
Definition: nbtree.h:62
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:68
TransactionId RecentGlobalXmin
Definition: snapmgr.c:166
#define P_ISDELETED(opaque)
Definition: nbtree.h:160
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
#define PageIsNew(page)
Definition: bufpage.h:225

◆ _bt_pagedel()

int _bt_pagedel ( Relation  rel,
Buffer  buf 
)

Definition at line 1268 of file nbtpage.c.

References _bt_getbuf(), _bt_mark_page_halfdead(), _bt_mkscankey(), _bt_relbuf(), _bt_search(), _bt_unlink_halfdead_page(), Assert, BT_READ, BT_WRITE, BTPageOpaqueData::btpo_next, BTPageOpaqueData::btpo_prev, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage, CopyIndexTuple(), ereport, errcode(), errhint(), errmsg(), IndexRelationGetNumberOfKeyAttributes, LockBuffer(), LOG, P_FIRSTDATAKEY, P_HIKEY, P_INCOMPLETE_SPLIT, P_ISDELETED, P_ISHALFDEAD, P_ISLEAF, P_ISROOT, P_LEFTMOST, P_RIGHTMOST, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageGetSpecialPointer, RelationGetRelationName, and ReleaseBuffer().

Referenced by btvacuumpage().

1269 {
1270  int ndeleted = 0;
1271  BlockNumber rightsib;
1272  bool rightsib_empty;
1273  Page page;
1274  BTPageOpaque opaque;
1275 
1276  /*
1277  * "stack" is a search stack leading (approximately) to the target page.
1278  * It is initially NULL, but when iterating, we keep it to avoid
1279  * duplicated search effort.
1280  *
1281  * Also, when "stack" is not NULL, we have already checked that the
1282  * current page is not the right half of an incomplete split, i.e. the
1283  * left sibling does not have its INCOMPLETE_SPLIT flag set.
1284  */
1285  BTStack stack = NULL;
1286 
1287  for (;;)
1288  {
1289  page = BufferGetPage(buf);
1290  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1291 
1292  /*
1293  * Internal pages are never deleted directly, only as part of deleting
1294  * the whole branch all the way down to leaf level.
1295  */
1296  if (!P_ISLEAF(opaque))
1297  {
1298  /*
1299  * Pre-9.4 page deletion only marked internal pages as half-dead,
1300  * but now we only use that flag on leaf pages. The old algorithm
1301  * was never supposed to leave half-dead pages in the tree, it was
1302  * just a transient state, but it was nevertheless possible in
1303  * error scenarios. We don't know how to deal with them here. They
1304  * are harmless as far as searches are considered, but inserts
1305  * into the deleted keyspace could add out-of-order downlinks in
1306  * the upper levels. Log a notice, hopefully the admin will notice
1307  * and reindex.
1308  */
1309  if (P_ISHALFDEAD(opaque))
1310  ereport(LOG,
1311  (errcode(ERRCODE_INDEX_CORRUPTED),
1312  errmsg("index \"%s\" contains a half-dead internal page",
1314  errhint("This can be caused by an interrupted VACUUM in version 9.3 or older, before upgrade. Please REINDEX it.")));
1315  _bt_relbuf(rel, buf);
1316  return ndeleted;
1317  }
1318 
1319  /*
1320  * We can never delete rightmost pages nor root pages. While at it,
1321  * check that page is not already deleted and is empty.
1322  *
1323  * To keep the algorithm simple, we also never delete an incompletely
1324  * split page (they should be rare enough that this doesn't make any
1325  * meaningful difference to disk usage):
1326  *
1327  * The INCOMPLETE_SPLIT flag on the page tells us if the page is the
1328  * left half of an incomplete split, but ensuring that it's not the
1329  * right half is more complicated. For that, we have to check that
1330  * the left sibling doesn't have its INCOMPLETE_SPLIT flag set. On
1331  * the first iteration, we temporarily release the lock on the current
1332  * page, and check the left sibling and also construct a search stack
1333  * to. On subsequent iterations, we know we stepped right from a page
1334  * that passed these tests, so it's OK.
1335  */
1336  if (P_RIGHTMOST(opaque) || P_ISROOT(opaque) || P_ISDELETED(opaque) ||
1337  P_FIRSTDATAKEY(opaque) <= PageGetMaxOffsetNumber(page) ||
1338  P_INCOMPLETE_SPLIT(opaque))
1339  {
1340  /* Should never fail to delete a half-dead page */
1341  Assert(!P_ISHALFDEAD(opaque));
1342 
1343  _bt_relbuf(rel, buf);
1344  return ndeleted;
1345  }
1346 
1347  /*
1348  * First, remove downlink pointing to the page (or a parent of the
1349  * page, if we are going to delete a taller branch), and mark the page
1350  * as half-dead.
1351  */
1352  if (!P_ISHALFDEAD(opaque))
1353  {
1354  /*
1355  * We need an approximate pointer to the page's parent page. We
1356  * use the standard search mechanism to search for the page's high
1357  * key; this will give us a link to either the current parent or
1358  * someplace to its left (if there are multiple equal high keys).
1359  *
1360  * Also check if this is the right-half of an incomplete split
1361  * (see comment above).
1362  */
1363  if (!stack)
1364  {
1365  ScanKey itup_scankey;
1366  ItemId itemid;
1367  IndexTuple targetkey;
1368  Buffer lbuf;
1369  BlockNumber leftsib;
1370 
1371  itemid = PageGetItemId(page, P_HIKEY);
1372  targetkey = CopyIndexTuple((IndexTuple) PageGetItem(page, itemid));
1373 
1374  leftsib = opaque->btpo_prev;
1375 
1376  /*
1377  * To avoid deadlocks, we'd better drop the leaf page lock
1378  * before going further.
1379  */
1381 
1382  /*
1383  * Fetch the left sibling, to check that it's not marked with
1384  * INCOMPLETE_SPLIT flag. That would mean that the page
1385  * to-be-deleted doesn't have a downlink, and the page
1386  * deletion algorithm isn't prepared to handle that.
1387  */
1388  if (!P_LEFTMOST(opaque))
1389  {
1390  BTPageOpaque lopaque;
1391  Page lpage;
1392 
1393  lbuf = _bt_getbuf(rel, leftsib, BT_READ);
1394  lpage = BufferGetPage(lbuf);
1395  lopaque = (BTPageOpaque) PageGetSpecialPointer(lpage);
1396 
1397  /*
1398  * If the left sibling is split again by another backend,
1399  * after we released the lock, we know that the first
1400  * split must have finished, because we don't allow an
1401  * incompletely-split page to be split again. So we don't
1402  * need to walk right here.
1403  */
1404  if (lopaque->btpo_next == BufferGetBlockNumber(buf) &&
1405  P_INCOMPLETE_SPLIT(lopaque))
1406  {
1407  ReleaseBuffer(buf);
1408  _bt_relbuf(rel, lbuf);
1409  return ndeleted;
1410  }
1411  _bt_relbuf(rel, lbuf);
1412  }
1413 
1414  /* we need an insertion scan key for the search, so build one */
1415  itup_scankey = _bt_mkscankey(rel, targetkey);
1416  /* find the leftmost leaf page containing this key */
1417  stack = _bt_search(rel,
1419  itup_scankey, false, &lbuf, BT_READ, NULL);
1420  /* don't need a pin on the page */
1421  _bt_relbuf(rel, lbuf);
1422 
1423  /*
1424  * Re-lock the leaf page, and start over, to re-check that the
1425  * page can still be deleted.
1426  */
1428  continue;
1429  }
1430 
1431  if (!_bt_mark_page_halfdead(rel, buf, stack))
1432  {
1433  _bt_relbuf(rel, buf);
1434  return ndeleted;
1435  }
1436  }
1437 
1438  /*
1439  * Then unlink it from its siblings. Each call to
1440  * _bt_unlink_halfdead_page unlinks the topmost page from the branch,
1441  * making it shallower. Iterate until the leaf page is gone.
1442  */
1443  rightsib_empty = false;
1444  while (P_ISHALFDEAD(opaque))
1445  {
1446  if (!_bt_unlink_halfdead_page(rel, buf, &rightsib_empty))
1447  {
1448  /* _bt_unlink_halfdead_page already released buffer */
1449  return ndeleted;
1450  }
1451  ndeleted++;
1452  }
1453 
1454  rightsib = opaque->btpo_next;
1455 
1456  _bt_relbuf(rel, buf);
1457 
1458  /*
1459  * The page has now been deleted. If its right sibling is completely
1460  * empty, it's possible that the reason we haven't deleted it earlier
1461  * is that it was the rightmost child of the parent. Now that we
1462  * removed the downlink for this page, the right sibling might now be
1463  * the only child of the parent, and could be removed. It would be
1464  * picked up by the next vacuum anyway, but might as well try to
1465  * remove it now, so loop back to process the right sibling.
1466  */
1467  if (!rightsib_empty)
1468  break;
1469 
1470  buf = _bt_getbuf(rel, rightsib, BT_WRITE);
1471  }
1472 
1473  return ndeleted;
1474 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
BlockNumber btpo_next
Definition: nbtree.h:58
int errhint(const char *fmt,...)
Definition: elog.c:987
Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access)
Definition: nbtpage.c:729
static bool _bt_mark_page_halfdead(Relation rel, Buffer buf, BTStack stack)
Definition: nbtpage.c:1481
#define P_FIRSTDATAKEY(opaque)
Definition: nbtree.h:187
int errcode(int sqlerrcode)
Definition: elog.c:575
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define P_INCOMPLETE_SPLIT(opaque)
Definition: nbtree.h:165
#define LOG
Definition: elog.h:26
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:68
#define BT_READ
Definition: nbtree.h:300
#define P_ISHALFDEAD(opaque)
Definition: nbtree.h:162
BlockNumber btpo_prev
Definition: nbtree.h:57
IndexTuple CopyIndexTuple(IndexTuple source)
Definition: indextuple.c:441
static char * buf
Definition: pg_test_fsync.c:67
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define P_LEFTMOST(opaque)
Definition: nbtree.h:156
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:426
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
#define P_ISDELETED(opaque)
Definition: nbtree.h:160
#define P_ISROOT(opaque)
Definition: nbtree.h:159
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
BTStack _bt_search(Relation rel, int keysz, ScanKey scankey, bool nextkey, Buffer *bufP, int access, Snapshot snapshot)
Definition: nbtsearch.c:97
void _bt_relbuf(Relation rel, Buffer buf)
Definition: nbtpage.c:879
#define Assert(condition)
Definition: c.h:699
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
#define P_HIKEY
Definition: nbtree.h:185
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
int errmsg(const char *fmt,...)
Definition: elog.c:797
static bool _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty)
Definition: nbtpage.c:1673
ScanKey _bt_mkscankey(Relation rel, IndexTuple itup)
Definition: nbtutils.c:62
#define BT_WRITE
Definition: nbtree.h:301
int Buffer
Definition: buf.h:23
#define P_RIGHTMOST(opaque)
Definition: nbtree.h:157
#define PageGetItem(page, itemId)
Definition: bufpage.h:336
Pointer Page
Definition: bufpage.h:74
#define P_ISLEAF(opaque)
Definition: nbtree.h:158

◆ _bt_pageinit()

void _bt_pageinit ( Page  page,
Size  size 
)

Definition at line 891 of file nbtpage.c.

References PageInit().

Referenced by _bt_blnewpage(), _bt_getbuf(), _bt_initmetapage(), _bt_restore_meta(), _bt_split(), btree_xlog_mark_page_halfdead(), btree_xlog_newroot(), btree_xlog_split(), and btree_xlog_unlink_page().

892 {
893  PageInit(page, size, sizeof(BTPageOpaqueData));
894 }
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:41

◆ _bt_relandgetbuf()

Buffer _bt_relandgetbuf ( Relation  rel,
Buffer  obuf,
BlockNumber  blkno,
int  access 
)

Definition at line 860 of file nbtpage.c.

References _bt_checkpage(), Assert, buf, BUFFER_LOCK_UNLOCK, BufferIsValid, LockBuffer(), P_NEW, and ReleaseAndReadBuffer().

Referenced by _bt_check_unique(), _bt_findinsertloc(), _bt_get_endpoint(), _bt_getroot(), _bt_gettrueroot(), _bt_moveright(), _bt_search(), and _bt_walk_left().

861 {
862  Buffer buf;
863 
864  Assert(blkno != P_NEW);
865  if (BufferIsValid(obuf))
867  buf = ReleaseAndReadBuffer(obuf, rel, blkno);
868  LockBuffer(buf, access);
869  _bt_checkpage(rel, buf);
870  return buf;
871 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
#define P_NEW
Definition: bufmgr.h:82
void _bt_checkpage(Relation rel, Buffer buf)
Definition: nbtpage.c:662
static char * buf
Definition: pg_test_fsync.c:67
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define Assert(condition)
Definition: c.h:699
Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, BlockNumber blockNum)
Definition: bufmgr.c:1513
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
int Buffer
Definition: buf.h:23

◆ _bt_relbuf()

◆ _bt_unlink_halfdead_page()

static bool _bt_unlink_halfdead_page ( Relation  rel,
Buffer  leafbuf,
bool rightsib_empty 
)
static

Definition at line 1673 of file nbtpage.c.

References _bt_getbuf(), _bt_relbuf(), _bt_upgrademetapage(), Assert, BT_READ, BT_WRITE, BTMetaPageData::btm_fastlevel, BTMetaPageData::btm_fastroot, BTMetaPageData::btm_last_cleanup_num_heap_tuples, BTMetaPageData::btm_level, BTMetaPageData::btm_oldest_btpo_xact, BTMetaPageData::btm_root, BTMetaPageData::btm_version, BTP_DELETED, BTP_HALF_DEAD, BTPageGetMeta, BTPageOpaqueData::btpo, BTPageOpaqueData::btpo_flags, BTPageOpaqueData::btpo_next, BTPageOpaqueData::btpo_prev, xl_btree_unlink_page::btpo_xact, BTREE_METAPAGE, BTREE_VERSION, BTreeInnerTupleGetDownLink, BTreeTupleGetTopParent, BTreeTupleSetTopParent, buf, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage, BufferIsValid, elog, END_CRIT_SECTION, ERROR, xl_btree_metadata::fastlevel, xl_btree_metadata::fastroot, InvalidBlockNumber, InvalidBuffer, xl_btree_metadata::last_cleanup_num_heap_tuples, xl_btree_unlink_page::leafleftsib, xl_btree_unlink_page::leafrightsib, xl_btree_unlink_page::leftsib, xl_btree_metadata::level, BTPageOpaqueData::level, LockBuffer(), LOG, MarkBufferDirty(), xl_btree_metadata::oldest_btpo_xact, P_FIRSTDATAKEY, P_HIKEY, P_ISDELETED, P_ISHALFDEAD, P_ISLEAF, P_ISROOT, P_NONE, P_RIGHTMOST, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageGetSpecialPointer, PageSetLSN, ReadNewTransactionId(), REGBUF_STANDARD, REGBUF_WILL_INIT, RelationGetRelationName, RelationNeedsWAL, ReleaseBuffer(), xl_btree_unlink_page::rightsib, xl_btree_metadata::root, SizeOfBtreeUnlinkPage, START_CRIT_SECTION, xl_btree_unlink_page::topparent, BTPageOpaqueData::xact, XLOG_BTREE_UNLINK_PAGE, XLOG_BTREE_UNLINK_PAGE_META, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by _bt_pagedel().

1674 {
1675  BlockNumber leafblkno = BufferGetBlockNumber(leafbuf);
1676  BlockNumber leafleftsib;
1677  BlockNumber leafrightsib;
1678  BlockNumber target;
1679  BlockNumber leftsib;
1680  BlockNumber rightsib;
1681  Buffer lbuf = InvalidBuffer;
1682  Buffer buf;
1683  Buffer rbuf;
1684  Buffer metabuf = InvalidBuffer;
1685  Page metapg = NULL;
1686  BTMetaPageData *metad = NULL;
1687  ItemId itemid;
1688  Page page;
1689  BTPageOpaque opaque;
1690  bool rightsib_is_rightmost;
1691  int targetlevel;
1692  IndexTuple leafhikey;
1693  BlockNumber nextchild;
1694 
1695  page = BufferGetPage(leafbuf);
1696  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1697 
1698  Assert(P_ISLEAF(opaque) && P_ISHALFDEAD(opaque));
1699 
1700  /*
1701  * Remember some information about the leaf page.
1702  */
1703  itemid = PageGetItemId(page, P_HIKEY);
1704  leafhikey = (IndexTuple) PageGetItem(page, itemid);
1705  leafleftsib = opaque->btpo_prev;
1706  leafrightsib = opaque->btpo_next;
1707 
1708  LockBuffer(leafbuf, BUFFER_LOCK_UNLOCK);
1709 
1710  /*
1711  * If the leaf page still has a parent pointing to it (or a chain of
1712  * parents), we don't unlink the leaf page yet, but the topmost remaining
1713  * parent in the branch. Set 'target' and 'buf' to reference the page
1714  * actually being unlinked.
1715  */
1716  target = BTreeTupleGetTopParent(leafhikey);
1717 
1718  if (target != InvalidBlockNumber)
1719  {
1720  Assert(target != leafblkno);
1721 
1722  /* fetch the block number of the topmost parent's left sibling */
1723  buf = _bt_getbuf(rel, target, BT_READ);
1724  page = BufferGetPage(buf);
1725  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1726  leftsib = opaque->btpo_prev;
1727  targetlevel = opaque->btpo.level;
1728 
1729  /*
1730  * To avoid deadlocks, we'd better drop the target page lock before
1731  * going further.
1732  */
1734  }
1735  else
1736  {
1737  target = leafblkno;
1738 
1739  buf = leafbuf;
1740  leftsib = leafleftsib;
1741  targetlevel = 0;
1742  }
1743 
1744  /*
1745  * We have to lock the pages we need to modify in the standard order:
1746  * moving right, then up. Else we will deadlock against other writers.
1747  *
1748  * So, first lock the leaf page, if it's not the target. Then find and
1749  * write-lock the current left sibling of the target page. The sibling
1750  * that was current a moment ago could have split, so we may have to move
1751  * right. This search could fail if either the sibling or the target page
1752  * was deleted by someone else meanwhile; if so, give up. (Right now,
1753  * that should never happen, since page deletion is only done in VACUUM
1754  * and there shouldn't be multiple VACUUMs concurrently on the same
1755  * table.)
1756  */
1757  if (target != leafblkno)
1758  LockBuffer(leafbuf, BT_WRITE);
1759  if (leftsib != P_NONE)
1760  {
1761  lbuf = _bt_getbuf(rel, leftsib, BT_WRITE);
1762  page = BufferGetPage(lbuf);
1763  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1764  while (P_ISDELETED(opaque) || opaque->btpo_next != target)
1765  {
1766  /* step right one page */
1767  leftsib = opaque->btpo_next;
1768  _bt_relbuf(rel, lbuf);
1769  if (leftsib == P_NONE)
1770  {
1771  elog(LOG, "no left sibling (concurrent deletion?) of block %u in \"%s\"",
1772  target,
1774  if (target != leafblkno)
1775  {
1776  /* we have only a pin on target, but pin+lock on leafbuf */
1777  ReleaseBuffer(buf);
1778  _bt_relbuf(rel, leafbuf);
1779  }
1780  else
1781  {
1782  /* we have only a pin on leafbuf */
1783  ReleaseBuffer(leafbuf);
1784  }
1785  return false;
1786  }
1787  lbuf = _bt_getbuf(rel, leftsib, BT_WRITE);
1788  page = BufferGetPage(lbuf);
1789  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1790  }
1791  }
1792  else
1793  lbuf = InvalidBuffer;
1794 
1795  /*
1796  * Next write-lock the target page itself. It should be okay to take just
1797  * a write lock not a superexclusive lock, since no scans would stop on an
1798  * empty page.
1799  */
1800  LockBuffer(buf, BT_WRITE);
1801  page = BufferGetPage(buf);
1802  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1803 
1804  /*
1805  * Check page is still empty etc, else abandon deletion. This is just for
1806  * paranoia's sake; a half-dead page cannot resurrect because there can be
1807  * only one vacuum process running at a time.
1808  */
1809  if (P_RIGHTMOST(opaque) || P_ISROOT(opaque) || P_ISDELETED(opaque))
1810  {
1811  elog(ERROR, "half-dead page changed status unexpectedly in block %u of index \"%s\"",
1812  target, RelationGetRelationName(rel));
1813  }
1814  if (opaque->btpo_prev != leftsib)
1815  elog(ERROR, "left link changed unexpectedly in block %u of index \"%s\"",
1816  target, RelationGetRelationName(rel));
1817 
1818  if (target == leafblkno)
1819  {
1820  if (P_FIRSTDATAKEY(opaque) <= PageGetMaxOffsetNumber(page) ||
1821  !P_ISLEAF(opaque) || !P_ISHALFDEAD(opaque))
1822  elog(ERROR, "half-dead page changed status unexpectedly in block %u of index \"%s\"",
1823  target, RelationGetRelationName(rel));
1824  nextchild = InvalidBlockNumber;
1825  }
1826  else
1827  {
1828  if (P_FIRSTDATAKEY(opaque) != PageGetMaxOffsetNumber(page) ||
1829  P_ISLEAF(opaque))
1830  elog(ERROR, "half-dead page changed status unexpectedly in block %u of index \"%s\"",
1831  target, RelationGetRelationName(rel));
1832 
1833  /* remember the next non-leaf child down in the branch. */
1834  itemid = PageGetItemId(page, P_FIRSTDATAKEY(opaque));
1835  nextchild = BTreeInnerTupleGetDownLink((IndexTuple) PageGetItem(page, itemid));
1836  if (nextchild == leafblkno)
1837  nextchild = InvalidBlockNumber;
1838  }
1839 
1840  /*
1841  * And next write-lock the (current) right sibling.
1842  */
1843  rightsib = opaque->btpo_next;
1844  rbuf = _bt_getbuf(rel, rightsib, BT_WRITE);
1845  page = BufferGetPage(rbuf);
1846  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1847  if (opaque->btpo_prev != target)
1848  elog(ERROR, "right sibling's left-link doesn't match: "
1849  "block %u links to %u instead of expected %u in index \"%s\"",
1850  rightsib, opaque->btpo_prev, target,
1852  rightsib_is_rightmost = P_RIGHTMOST(opaque);
1853  *rightsib_empty = (P_FIRSTDATAKEY(opaque) > PageGetMaxOffsetNumber(page));
1854 
1855  /*
1856  * If we are deleting the next-to-last page on the target's level, then
1857  * the rightsib is a candidate to become the new fast root. (In theory, it
1858  * might be possible to push the fast root even further down, but the odds
1859  * of doing so are slim, and the locking considerations daunting.)
1860  *
1861  * We don't support handling this in the case where the parent is becoming
1862  * half-dead, even though it theoretically could occur.
1863  *
1864  * We can safely acquire a lock on the metapage here --- see comments for
1865  * _bt_newroot().
1866  */
1867  if (leftsib == P_NONE && rightsib_is_rightmost)
1868  {
1869  page = BufferGetPage(rbuf);
1870  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1871  if (P_RIGHTMOST(opaque))
1872  {
1873  /* rightsib will be the only one left on the level */
1874  metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_WRITE);
1875  metapg = BufferGetPage(metabuf);
1876  metad = BTPageGetMeta(metapg);
1877 
1878  /*
1879  * The expected case here is btm_fastlevel == targetlevel+1; if
1880  * the fastlevel is <= targetlevel, something is wrong, and we
1881  * choose to overwrite it to fix it.
1882  */
1883  if (metad->btm_fastlevel > targetlevel + 1)
1884  {
1885  /* no update wanted */
1886  _bt_relbuf(rel, metabuf);
1887  metabuf = InvalidBuffer;
1888  }
1889  }
1890  }
1891 
1892  /*
1893  * Here we begin doing the deletion.
1894  */
1895 
1896  /* No ereport(ERROR) until changes are logged */
1898 
1899  /*
1900  * Update siblings' side-links. Note the target page's side-links will
1901  * continue to point to the siblings. Asserts here are just rechecking
1902  * things we already verified above.
1903  */
1904  if (BufferIsValid(lbuf))
1905  {
1906  page = BufferGetPage(lbuf);
1907  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1908  Assert(opaque->btpo_next == target);
1909  opaque->btpo_next = rightsib;
1910  }
1911  page = BufferGetPage(rbuf);
1912  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1913  Assert(opaque->btpo_prev == target);
1914  opaque->btpo_prev = leftsib;
1915 
1916  /*
1917  * If we deleted a parent of the targeted leaf page, instead of the leaf
1918  * itself, update the leaf to point to the next remaining child in the
1919  * branch.
1920  */
1921  if (target != leafblkno)
1922  BTreeTupleSetTopParent(leafhikey, nextchild);
1923 
1924  /*
1925  * Mark the page itself deleted. It can be recycled when all current
1926  * transactions are gone. Storing GetTopTransactionId() would work, but
1927  * we're in VACUUM and would not otherwise have an XID. Having already
1928  * updated links to the target, ReadNewTransactionId() suffices as an
1929  * upper bound. Any scan having retained a now-stale link is advertising
1930  * in its PGXACT an xmin less than or equal to the value we read here. It
1931  * will continue to do so, holding back RecentGlobalXmin, for the duration
1932  * of that scan.
1933  */
1934  page = BufferGetPage(buf);
1935  opaque = (BTPageOpaque) PageGetSpecialPointer(page);
1936  opaque->btpo_flags &= ~BTP_HALF_DEAD;
1937  opaque->btpo_flags |= BTP_DELETED;
1938  opaque->btpo.xact = ReadNewTransactionId();
1939 
1940  /* And update the metapage, if needed */
1941  if (BufferIsValid(metabuf))
1942  {
1943  /* upgrade metapage if needed */
1944  if (metad->btm_version < BTREE_VERSION)
1945  _bt_upgrademetapage(metapg);
1946  metad->btm_fastroot = rightsib;
1947  metad->btm_fastlevel = targetlevel;
1948  MarkBufferDirty(metabuf);
1949  }
1950 
1951  /* Must mark buffers dirty before XLogInsert */
1952  MarkBufferDirty(rbuf);
1953  MarkBufferDirty(buf);
1954  if (BufferIsValid(lbuf))
1955  MarkBufferDirty(lbuf);
1956  if (target != leafblkno)
1957  MarkBufferDirty(leafbuf);
1958 
1959  /* XLOG stuff */
1960  if (RelationNeedsWAL(rel))
1961  {
1962  xl_btree_unlink_page xlrec;
1963  xl_btree_metadata xlmeta;
1964  uint8 xlinfo;
1965  XLogRecPtr recptr;
1966 
1967  XLogBeginInsert();
1968 
1970  if (BufferIsValid(lbuf))
1973  if (target != leafblkno)
1974  XLogRegisterBuffer(3, leafbuf, REGBUF_WILL_INIT);
1975 
1976  /* information on the unlinked block */
1977  xlrec.leftsib = leftsib;
1978  xlrec.rightsib = rightsib;
1979  xlrec.btpo_xact = opaque->btpo.xact;
1980 
1981  /* information needed to recreate the leaf block (if not the target) */
1982  xlrec.leafleftsib = leafleftsib;
1983  xlrec.leafrightsib = leafrightsib;
1984  xlrec.topparent = nextchild;
1985 
1986  XLogRegisterData((char *) &xlrec, SizeOfBtreeUnlinkPage);
1987 
1988  if (BufferIsValid(metabuf))
1989  {
1991 
1992  xlmeta.root = metad->btm_root;
1993  xlmeta.level = metad->btm_level;
1994  xlmeta.fastroot = metad->btm_fastroot;
1995  xlmeta.fastlevel = metad->btm_fastlevel;
1996  xlmeta.oldest_btpo_xact = metad->btm_oldest_btpo_xact;
1998 
1999  XLogRegisterBufData(4, (char *) &xlmeta, sizeof(xl_btree_metadata));
2000  xlinfo = XLOG_BTREE_UNLINK_PAGE_META;
2001  }
2002  else
2003  xlinfo = XLOG_BTREE_UNLINK_PAGE;
2004 
2005  recptr = XLogInsert(RM_BTREE_ID, xlinfo);
2006 
2007  if (BufferIsValid(metabuf))
2008  {
2009  PageSetLSN(metapg, recptr);
2010  }
2011  page = BufferGetPage(rbuf);
2012  PageSetLSN(page, recptr);
2013  page = BufferGetPage(buf);
2014  PageSetLSN(page, recptr);
2015  if (BufferIsValid(lbuf))
2016  {
2017  page = BufferGetPage(lbuf);
2018  PageSetLSN(page, recptr);
2019  }
2020  if (target != leafblkno)
2021  {
2022  page = BufferGetPage(leafbuf);
2023  PageSetLSN(page, recptr);
2024  }
2025  }
2026 
2027  END_CRIT_SECTION();
2028 
2029  /* release metapage */
2030  if (BufferIsValid(metabuf))
2031  _bt_relbuf(rel, metabuf);
2032 
2033  /* release siblings */
2034  if (BufferIsValid(lbuf))
2035  _bt_relbuf(rel, lbuf);
2036  _bt_relbuf(rel, rbuf);
2037 
2038  /*
2039  * Release the target, if it was not the leaf block. The leaf is always
2040  * kept locked.
2041  */
2042  if (target != leafblkno)
2043  _bt_relbuf(rel, buf);
2044 
2045  return true;
2046 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
BlockNumber btpo_next
Definition: nbtree.h:58
#define BTreeInnerTupleGetDownLink(itup)
Definition: nbtree.h:224
void _bt_upgrademetapage(Page page)
Definition: nbtpage.c:86
uint32 btm_version
Definition: nbtree.h:100
Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access)
Definition: nbtpage.c:729
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define BTREE_VERSION
Definition: nbtree.h:117
#define P_FIRSTDATAKEY(opaque)
Definition: nbtree.h:187
#define BTP_HALF_DEAD
Definition: nbtree.h:75
union BTPageOpaqueData::@46 btpo
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
BlockNumber root
Definition: nbtxlog.h:50
unsigned char uint8
Definition: c.h:323
#define P_NONE
Definition: nbtree.h:150
#define InvalidBuffer
Definition: buf.h:25
#define REGBUF_WILL_INIT
Definition: xloginsert.h:32
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define BTP_DELETED
Definition: nbtree.h:73
#define LOG
Definition: elog.h:26
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
TransactionId xact
Definition: nbtree.h:62
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:68
#define BT_READ
Definition: nbtree.h:300
BlockNumber btm_fastroot
Definition: nbtree.h:103
#define P_ISHALFDEAD(opaque)
Definition: nbtree.h:162
#define ERROR
Definition: elog.h:43
float8 last_cleanup_num_heap_tuples
Definition: nbtxlog.h:55
#define BTreeTupleSetTopParent(itup, blkno)
Definition: nbtree.h:237
TransactionId oldest_btpo_xact
Definition: nbtxlog.h:54
#define BTPageGetMeta(p)
Definition: nbtree.h:112
BlockNumber btpo_prev
Definition: nbtree.h:57
static char * buf
Definition: pg_test_fsync.c:67
IndexTupleData * IndexTuple
Definition: itup.h:53
#define REGBUF_STANDARD
Definition: xloginsert.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:441
TransactionId ReadNewTransactionId(void)
Definition: varsup.c:250
#define XLOG_BTREE_UNLINK_PAGE
Definition: nbtxlog.h:34
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define BTREE_METAPAGE
Definition: nbtree.h:115
#define P_ISDELETED(opaque)
Definition: nbtree.h:160
#define P_ISROOT(opaque)
Definition: nbtree.h:159
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
uint32 btm_fastlevel
Definition: nbtree.h:104
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
uint32 level
Definition: nbtree.h:61
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
BlockNumber btm_root
Definition: nbtree.h:101
void _bt_relbuf(Relation rel, Buffer buf)
Definition: nbtpage.c:879
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:699
#define BTreeTupleGetTopParent(itup)
Definition: nbtree.h:235
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
#define InvalidBlockNumber
Definition: block.h:33
float8 btm_last_cleanup_num_heap_tuples
Definition: nbtree.h:108
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
#define RelationNeedsWAL(relation)
Definition: rel.h:510
#define P_HIKEY
Definition: nbtree.h:185
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
uint32 fastlevel
Definition: nbtxlog.h:53
uint32 btm_level
Definition: nbtree.h:102
uint32 level
Definition: nbtxlog.h:51
#define SizeOfBtreeUnlinkPage
Definition: nbtxlog.h:230
BlockNumber fastroot
Definition: nbtxlog.h:52
#define XLOG_BTREE_UNLINK_PAGE_META
Definition: nbtxlog.h:35
#define elog
Definition: elog.h:219
TransactionId btm_oldest_btpo_xact
Definition: nbtree.h:106
#define BT_WRITE
Definition: nbtree.h:301
void XLogBeginInsert(void)
Definition: xloginsert.c:120
uint16 btpo_flags
Definition: nbtree.h:64
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
int Buffer
Definition: buf.h:23
#define P_RIGHTMOST(opaque)
Definition: nbtree.h:157
#define PageGetItem(page, itemId)
Definition: bufpage.h:336
Pointer Page
Definition: bufpage.h:74
#define P_ISLEAF(opaque)
Definition: nbtree.h:158

◆ _bt_update_meta_cleanup_info()

void _bt_update_meta_cleanup_info ( Relation  rel,
TransactionId  oldestBtpoXact,
float8  numHeapTuples 
)

Definition at line 155 of file nbtpage.c.

References _bt_getbuf(), _bt_relbuf(), _bt_upgrademetapage(), BT_READ, BT_WRITE, BTMetaPageData::btm_fastlevel, BTMetaPageData::btm_fastroot, BTMetaPageData::btm_last_cleanup_num_heap_tuples, BTMetaPageData::btm_level, BTMetaPageData::btm_oldest_btpo_xact, BTMetaPageData::btm_root, BTMetaPageData::btm_version, BTPageGetMeta, BTREE_METAPAGE, BTREE_VERSION, BUFFER_LOCK_UNLOCK, BufferGetPage, END_CRIT_SECTION, xl_btree_metadata::fastlevel, xl_btree_metadata::fastroot, xl_btree_metadata::last_cleanup_num_heap_tuples, xl_btree_metadata::level, LockBuffer(), MarkBufferDirty(), xl_btree_metadata::oldest_btpo_xact, PageSetLSN, REGBUF_STANDARD, REGBUF_WILL_INIT, RelationNeedsWAL, xl_btree_metadata::root, START_CRIT_SECTION, XLOG_BTREE_META_CLEANUP, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), and XLogRegisterBuffer().

Referenced by btbulkdelete(), and btvacuumcleanup().

157 {
158  Buffer metabuf;
159  Page metapg;
160  BTMetaPageData *metad;
161  bool needsRewrite = false;
162  XLogRecPtr recptr;
163 
164  /* read the metapage and check if it needs rewrite */
165  metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
166  metapg = BufferGetPage(metabuf);
167  metad = BTPageGetMeta(metapg);
168 
169  /* outdated version of metapage always needs rewrite */
170  if (metad->btm_version < BTREE_VERSION)
171  needsRewrite = true;
172  else if (metad->btm_oldest_btpo_xact != oldestBtpoXact ||
173  metad->btm_last_cleanup_num_heap_tuples != numHeapTuples)
174  needsRewrite = true;
175 
176  if (!needsRewrite)
177  {
178  _bt_relbuf(rel, metabuf);
179  return;
180  }
181 
182  /* trade in our read lock for a write lock */
183  LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
184  LockBuffer(metabuf, BT_WRITE);
185 
187 
188  /* upgrade meta-page if needed */
189  if (metad->btm_version < BTREE_VERSION)
190  _bt_upgrademetapage(metapg);
191 
192  /* update cleanup-related information */
193  metad->btm_oldest_btpo_xact = oldestBtpoXact;
194  metad->btm_last_cleanup_num_heap_tuples = numHeapTuples;
195  MarkBufferDirty(metabuf);
196 
197  /* write wal record if needed */
198  if (RelationNeedsWAL(rel))
199  {
201 
202  XLogBeginInsert();
204 
205  md.root = metad->btm_root;
206  md.level = metad->btm_level;
207  md.fastroot = metad->btm_fastroot;
208  md.fastlevel = metad->btm_fastlevel;
209  md.oldest_btpo_xact = oldestBtpoXact;
210  md.last_cleanup_num_heap_tuples = numHeapTuples;
211 
212  XLogRegisterBufData(0, (char *) &md, sizeof(xl_btree_metadata));
213 
214  recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_META_CLEANUP);
215 
216  PageSetLSN(metapg, recptr);
217  }
218 
220  _bt_relbuf(rel, metabuf);
221 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
void _bt_upgrademetapage(Page page)
Definition: nbtpage.c:86
uint32 btm_version
Definition: nbtree.h:100
Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access)
Definition: nbtpage.c:729
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define BTREE_VERSION
Definition: nbtree.h:117
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
BlockNumber root
Definition: nbtxlog.h:50
#define REGBUF_WILL_INIT
Definition: xloginsert.h:32
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
#define BT_READ
Definition: nbtree.h:300
BlockNumber btm_fastroot
Definition: nbtree.h:103
float8 last_cleanup_num_heap_tuples
Definition: nbtxlog.h:55
TransactionId oldest_btpo_xact
Definition: nbtxlog.h:54
#define BTPageGetMeta(p)
Definition: nbtree.h:112
#define REGBUF_STANDARD
Definition: xloginsert.h:34
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define BTREE_METAPAGE
Definition: nbtree.h:115
uint32 btm_fastlevel
Definition: nbtree.h:104
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
BlockNumber btm_root
Definition: nbtree.h:101
void _bt_relbuf(Relation rel, Buffer buf)
Definition: nbtpage.c:879
uint64 XLogRecPtr
Definition: xlogdefs.h:21
float8 btm_last_cleanup_num_heap_tuples
Definition: nbtree.h:108
#define RelationNeedsWAL(relation)
Definition: rel.h:510
uint32 fastlevel
Definition: nbtxlog.h:53
uint32 btm_level
Definition: nbtree.h:102
uint32 level
Definition: nbtxlog.h:51
BlockNumber fastroot
Definition: nbtxlog.h:52
TransactionId btm_oldest_btpo_xact
Definition: nbtree.h:106
#define BT_WRITE
Definition: nbtree.h:301
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
int Buffer
Definition: buf.h:23
#define XLOG_BTREE_META_CLEANUP
Definition: nbtxlog.h:42
Pointer Page
Definition: bufpage.h:74

◆ _bt_upgrademetapage()

void _bt_upgrademetapage ( Page  page)

Definition at line 86 of file nbtpage.c.

References Assert, BTMetaPageData::btm_last_cleanup_num_heap_tuples, BTMetaPageData::btm_oldest_btpo_xact, BTMetaPageData::btm_version, BTP_META, BTPageGetMeta, BTREE_MIN_VERSION, BTREE_VERSION, InvalidTransactionId, PageGetSpecialPointer, and PG_USED_FOR_ASSERTS_ONLY.

Referenced by _bt_getroot(), _bt_insertonpg(), _bt_newroot(), _bt_unlink_halfdead_page(), and _bt_update_meta_cleanup_info().

87 {
88  BTMetaPageData *metad;
90 
91  metad = BTPageGetMeta(page);
92  metaopaque = (BTPageOpaque) PageGetSpecialPointer(page);
93 
94  /* It must be really a meta page of upgradable version */
95  Assert(metaopaque->btpo_flags & BTP_META);
98 
99  /* Set version number and fill extra fields added into version 3 */
100  metad->btm_version = BTREE_VERSION;
102  metad->btm_last_cleanup_num_heap_tuples = -1.0;
103 
104  /* Adjust pd_lower (see _bt_initmetapage() for details) */
105  ((PageHeader) page)->pd_lower =
106  ((char *) metad + sizeof(BTMetaPageData)) - (char *) page;
107 }
uint32 btm_version
Definition: nbtree.h:100
#define BTREE_VERSION
Definition: nbtree.h:117
#define BTP_META
Definition: nbtree.h:74
BTPageOpaqueData * BTPageOpaque
Definition: nbtree.h:68
#define BTPageGetMeta(p)
Definition: nbtree.h:112
#define InvalidTransactionId
Definition: transam.h:31
#define BTREE_MIN_VERSION
Definition: nbtree.h:118
PageHeaderData * PageHeader
Definition: bufpage.h:162
#define Assert(condition)
Definition: c.h:699
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
float8 btm_last_cleanup_num_heap_tuples
Definition: nbtree.h:108
TransactionId btm_oldest_btpo_xact
Definition: nbtree.h:106
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:123