PostgreSQL Source Code  git master
gindatapage.c File Reference
#include "postgres.h"
#include "access/gin_private.h"
#include "access/ginxlog.h"
#include "access/xloginsert.h"
#include "lib/ilist.h"
#include "miscadmin.h"
#include "storage/predicate.h"
#include "utils/rel.h"
Include dependency graph for gindatapage.c:

Go to the source code of this file.

Data Structures

struct  disassembledLeaf
 
struct  leafSegmentInfo
 

Macros

#define GinPostingListSegmentMaxSize   384
 
#define GinPostingListSegmentTargetSize   256
 
#define GinPostingListSegmentMinSize   128
 
#define MinTuplesPerSegment   ((GinPostingListSegmentMaxSize - 2) / 6)
 

Functions

static ItemPointer dataLeafPageGetUncompressed (Page page, int *nitems)
 
static void dataSplitPageInternal (GinBtree btree, Buffer origbuf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, Page *newlpage, Page *newrpage)
 
static disassembledLeafdisassembleLeaf (Page page)
 
static bool leafRepackItems (disassembledLeaf *leaf, ItemPointer remaining)
 
static bool addItemsToLeaf (disassembledLeaf *leaf, ItemPointer newItems, int nNewItems)
 
static void computeLeafRecompressWALData (disassembledLeaf *leaf)
 
static void dataPlaceToPageLeafRecompress (Buffer buf, disassembledLeaf *leaf)
 
static void dataPlaceToPageLeafSplit (disassembledLeaf *leaf, ItemPointerData lbound, ItemPointerData rbound, Page lpage, Page rpage)
 
ItemPointer GinDataLeafPageGetItems (Page page, int *nitems, ItemPointerData advancePast)
 
int GinDataLeafPageGetItemsToTbm (Page page, TIDBitmap *tbm)
 
static bool dataIsMoveRight (GinBtree btree, Page page)
 
static BlockNumber dataLocateItem (GinBtree btree, GinBtreeStack *stack)
 
static OffsetNumber dataFindChildPtr (GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
 
static BlockNumber dataGetLeftMostPage (GinBtree btree, Page page)
 
void GinDataPageAddPostingItem (Page page, PostingItem *data, OffsetNumber offset)
 
void GinPageDeletePostingItem (Page page, OffsetNumber offset)
 
static GinPlaceToPageRC dataBeginPlaceToPageLeaf (GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, void **ptp_workspace, Page *newlpage, Page *newrpage)
 
static void dataExecPlaceToPageLeaf (GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, void *ptp_workspace)
 
void ginVacuumPostingTreeLeaf (Relation indexrel, Buffer buffer, GinVacuumState *gvs)
 
static GinPlaceToPageRC dataBeginPlaceToPageInternal (GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, void **ptp_workspace, Page *newlpage, Page *newrpage)
 
static void dataExecPlaceToPageInternal (GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, void *ptp_workspace)
 
static GinPlaceToPageRC dataBeginPlaceToPage (GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, void **ptp_workspace, Page *newlpage, Page *newrpage)
 
static void dataExecPlaceToPage (GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, void *ptp_workspace)
 
static void * dataPrepareDownlink (GinBtree btree, Buffer lbuf)
 
void ginDataFillRoot (GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
 
BlockNumber createPostingTree (Relation index, ItemPointerData *items, uint32 nitems, GinStatsData *buildStats, Buffer entrybuffer)
 
static void ginPrepareDataScan (GinBtree btree, Relation index, BlockNumber rootBlkno)
 
void ginInsertItemPointers (Relation index, BlockNumber rootBlkno, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
 
GinBtreeStackginScanBeginPostingTree (GinBtree btree, Relation index, BlockNumber rootBlkno)
 

Macro Definition Documentation

◆ GinPostingListSegmentMaxSize

#define GinPostingListSegmentMaxSize   384

Definition at line 34 of file gindatapage.c.

◆ GinPostingListSegmentMinSize

#define GinPostingListSegmentMinSize   128

Definition at line 36 of file gindatapage.c.

◆ GinPostingListSegmentTargetSize

#define GinPostingListSegmentTargetSize   256

Definition at line 35 of file gindatapage.c.

◆ MinTuplesPerSegment

#define MinTuplesPerSegment   ((GinPostingListSegmentMaxSize - 2) / 6)

Definition at line 43 of file gindatapage.c.

Function Documentation

◆ addItemsToLeaf()

static bool addItemsToLeaf ( disassembledLeaf leaf,
ItemPointer  newItems,
int  nNewItems 
)
static

Definition at line 1444 of file gindatapage.c.

1445 {
1446  dlist_iter iter;
1447  ItemPointer nextnew = newItems;
1448  int newleft = nNewItems;
1449  bool modified = false;
1450  leafSegmentInfo *newseg;
1451 
1452  /*
1453  * If the page is completely empty, just construct one new segment to hold
1454  * all the new items.
1455  */
1456  if (dlist_is_empty(&leaf->segments))
1457  {
1458  newseg = palloc(sizeof(leafSegmentInfo));
1459  newseg->seg = NULL;
1460  newseg->items = newItems;
1461  newseg->nitems = nNewItems;
1462  newseg->action = GIN_SEGMENT_INSERT;
1463  dlist_push_tail(&leaf->segments, &newseg->node);
1464  return true;
1465  }
1466 
1467  dlist_foreach(iter, &leaf->segments)
1468  {
1470  int nthis;
1471  ItemPointer tmpitems;
1472  int ntmpitems;
1473 
1474  /*
1475  * How many of the new items fall into this segment?
1476  */
1477  if (!dlist_has_next(&leaf->segments, iter.cur))
1478  nthis = newleft;
1479  else
1480  {
1482  ItemPointerData next_first;
1483 
1485  dlist_next_node(&leaf->segments, iter.cur));
1486  if (next->items)
1487  next_first = next->items[0];
1488  else
1489  {
1490  Assert(next->seg != NULL);
1491  next_first = next->seg->first;
1492  }
1493 
1494  nthis = 0;
1495  while (nthis < newleft && ginCompareItemPointers(&nextnew[nthis], &next_first) < 0)
1496  nthis++;
1497  }
1498  if (nthis == 0)
1499  continue;
1500 
1501  /* Merge the new items with the existing items. */
1502  if (!cur->items)
1503  cur->items = ginPostingListDecode(cur->seg, &cur->nitems);
1504 
1505  /*
1506  * Fast path for the important special case that we're appending to
1507  * the end of the page: don't let the last segment on the page grow
1508  * larger than the target, create a new segment before that happens.
1509  */
1510  if (!dlist_has_next(&leaf->segments, iter.cur) &&
1511  ginCompareItemPointers(&cur->items[cur->nitems - 1], &nextnew[0]) < 0 &&
1512  cur->seg != NULL &&
1514  {
1515  newseg = palloc(sizeof(leafSegmentInfo));
1516  newseg->seg = NULL;
1517  newseg->items = nextnew;
1518  newseg->nitems = nthis;
1519  newseg->action = GIN_SEGMENT_INSERT;
1520  dlist_push_tail(&leaf->segments, &newseg->node);
1521  modified = true;
1522  break;
1523  }
1524 
1525  tmpitems = ginMergeItemPointers(cur->items, cur->nitems,
1526  nextnew, nthis,
1527  &ntmpitems);
1528  if (ntmpitems != cur->nitems)
1529  {
1530  /*
1531  * If there are no duplicates, track the added items so that we
1532  * can emit a compact ADDITEMS WAL record later on. (it doesn't
1533  * seem worth re-checking which items were duplicates, if there
1534  * were any)
1535  */
1536  if (ntmpitems == nthis + cur->nitems &&
1537  cur->action == GIN_SEGMENT_UNMODIFIED)
1538  {
1539  cur->action = GIN_SEGMENT_ADDITEMS;
1540  cur->modifieditems = nextnew;
1541  cur->nmodifieditems = nthis;
1542  }
1543  else
1544  cur->action = GIN_SEGMENT_REPLACE;
1545 
1546  cur->items = tmpitems;
1547  cur->nitems = ntmpitems;
1548  cur->seg = NULL;
1549  modified = true;
1550  }
1551 
1552  nextnew += nthis;
1553  newleft -= nthis;
1554  if (newleft == 0)
1555  break;
1556  }
1557 
1558  return modified;
1559 }
static int32 next
Definition: blutils.c:221
struct cursor * cur
Definition: ecpg.c:28
static int ginCompareItemPointers(ItemPointer a, ItemPointer b)
Definition: gin_private.h:488
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:342
#define GinPostingListSegmentTargetSize
Definition: gindatapage.c:35
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded_out)
ItemPointer ginMergeItemPointers(ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb, int *nmerged)
#define GIN_SEGMENT_ADDITEMS
Definition: ginxlog.h:95
#define GIN_SEGMENT_UNMODIFIED
Definition: ginxlog.h:91
#define GIN_SEGMENT_INSERT
Definition: ginxlog.h:93
#define GIN_SEGMENT_REPLACE
Definition: ginxlog.h:94
#define dlist_foreach(iter, lhead)
Definition: ilist.h:623
static bool dlist_has_next(const dlist_head *head, const dlist_node *node)
Definition: ilist.h:503
static dlist_node * dlist_next_node(dlist_head *head, dlist_node *node)
Definition: ilist.h:537
static bool dlist_is_empty(const dlist_head *head)
Definition: ilist.h:336
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:364
#define dlist_container(type, membername, ptr)
Definition: ilist.h:593
Assert(fmt[strlen(fmt) - 1] !='\n')
void * palloc(Size size)
Definition: mcxt.c:1201
dlist_head segments
Definition: gindatapage.c:50
dlist_node * cur
Definition: ilist.h:179
dlist_node node
Definition: gindatapage.c:72
ItemPointer items
Definition: gindatapage.c:101
GinPostingList * seg
Definition: gindatapage.c:100

References leafSegmentInfo::action, Assert(), dlist_iter::cur, cur, dlist_container, dlist_foreach, dlist_has_next(), dlist_is_empty(), dlist_next_node(), dlist_push_tail(), GIN_SEGMENT_ADDITEMS, GIN_SEGMENT_INSERT, GIN_SEGMENT_REPLACE, GIN_SEGMENT_UNMODIFIED, ginCompareItemPointers(), ginMergeItemPointers(), ginPostingListDecode(), GinPostingListSegmentTargetSize, leafSegmentInfo::items, next, leafSegmentInfo::nitems, leafSegmentInfo::node, palloc(), leafSegmentInfo::seg, disassembledLeaf::segments, and SizeOfGinPostingList.

Referenced by dataBeginPlaceToPageLeaf().

◆ computeLeafRecompressWALData()

static void computeLeafRecompressWALData ( disassembledLeaf leaf)
static

Definition at line 872 of file gindatapage.c.

873 {
874  int nmodified = 0;
875  char *walbufbegin;
876  char *walbufend;
877  dlist_iter iter;
878  int segno;
879  ginxlogRecompressDataLeaf *recompress_xlog;
880 
881  /* Count the modified segments */
882  dlist_foreach(iter, &leaf->segments)
883  {
885  iter.cur);
886 
887  if (seginfo->action != GIN_SEGMENT_UNMODIFIED)
888  nmodified++;
889  }
890 
891  walbufbegin =
893  BLCKSZ + /* max size needed to hold the segment data */
894  nmodified * 2 /* (segno + action) per action */
895  );
896  walbufend = walbufbegin;
897 
898  recompress_xlog = (ginxlogRecompressDataLeaf *) walbufend;
899  walbufend += sizeof(ginxlogRecompressDataLeaf);
900 
901  recompress_xlog->nactions = nmodified;
902 
903  segno = 0;
904  dlist_foreach(iter, &leaf->segments)
905  {
907  iter.cur);
908  int segsize = 0;
909  int datalen;
910  uint8 action = seginfo->action;
911 
913  {
914  segno++;
915  continue;
916  }
917 
918  if (action != GIN_SEGMENT_DELETE)
919  segsize = SizeOfGinPostingList(seginfo->seg);
920 
921  /*
922  * If storing the uncompressed list of added item pointers would take
923  * more space than storing the compressed segment as is, do that
924  * instead.
925  */
926  if (action == GIN_SEGMENT_ADDITEMS &&
927  seginfo->nmodifieditems * sizeof(ItemPointerData) > segsize)
928  {
930  }
931 
932  *((uint8 *) (walbufend++)) = segno;
933  *(walbufend++) = action;
934 
935  switch (action)
936  {
937  case GIN_SEGMENT_DELETE:
938  datalen = 0;
939  break;
940 
942  datalen = seginfo->nmodifieditems * sizeof(ItemPointerData);
943  memcpy(walbufend, &seginfo->nmodifieditems, sizeof(uint16));
944  memcpy(walbufend + sizeof(uint16), seginfo->modifieditems, datalen);
945  datalen += sizeof(uint16);
946  break;
947 
948  case GIN_SEGMENT_INSERT:
949  case GIN_SEGMENT_REPLACE:
950  datalen = SHORTALIGN(segsize);
951  memcpy(walbufend, seginfo->seg, segsize);
952  break;
953 
954  default:
955  elog(ERROR, "unexpected GIN leaf action %d", action);
956  }
957  walbufend += datalen;
958 
959  if (action != GIN_SEGMENT_INSERT)
960  segno++;
961  }
962 
963  /* Pass back the constructed info via *leaf */
964  leaf->walinfo = walbufbegin;
965  leaf->walinfolen = walbufend - walbufbegin;
966 }
unsigned short uint16
Definition: c.h:494
#define SHORTALIGN(LEN)
Definition: c.h:796
unsigned char uint8
Definition: c.h:493
#define ERROR
Definition: elog.h:39
#define GIN_SEGMENT_DELETE
Definition: ginxlog.h:92
struct ItemPointerData ItemPointerData
ItemPointerData * modifieditems
Definition: gindatapage.c:90
uint16 nmodifieditems
Definition: gindatapage.c:91

References generate_unaccent_rules::action, leafSegmentInfo::action, dlist_iter::cur, dlist_container, dlist_foreach, elog(), ERROR, GIN_SEGMENT_ADDITEMS, GIN_SEGMENT_DELETE, GIN_SEGMENT_INSERT, GIN_SEGMENT_REPLACE, GIN_SEGMENT_UNMODIFIED, leafSegmentInfo::modifieditems, ginxlogRecompressDataLeaf::nactions, leafSegmentInfo::nmodifieditems, palloc(), leafSegmentInfo::seg, disassembledLeaf::segments, SHORTALIGN, SizeOfGinPostingList, disassembledLeaf::walinfo, and disassembledLeaf::walinfolen.

Referenced by dataBeginPlaceToPageLeaf(), and ginVacuumPostingTreeLeaf().

◆ createPostingTree()

BlockNumber createPostingTree ( Relation  index,
ItemPointerData items,
uint32  nitems,
GinStatsData buildStats,
Buffer  entrybuffer 
)

Definition at line 1775 of file gindatapage.c.

1777 {
1778  BlockNumber blkno;
1779  Buffer buffer;
1780  Page tmppage;
1781  Page page;
1782  Pointer ptr;
1783  int nrootitems;
1784  int rootsize;
1785  bool is_build = (buildStats != NULL);
1786 
1787  /* Construct the new root page in memory first. */
1788  tmppage = (Page) palloc(BLCKSZ);
1789  GinInitPage(tmppage, GIN_DATA | GIN_LEAF | GIN_COMPRESSED, BLCKSZ);
1790  GinPageGetOpaque(tmppage)->rightlink = InvalidBlockNumber;
1791 
1792  /*
1793  * Write as many of the items to the root page as fit. In segments of max
1794  * GinPostingListSegmentMaxSize bytes each.
1795  */
1796  nrootitems = 0;
1797  rootsize = 0;
1798  ptr = (Pointer) GinDataLeafPageGetPostingList(tmppage);
1799  while (nrootitems < nitems)
1800  {
1801  GinPostingList *segment;
1802  int npacked;
1803  int segsize;
1804 
1805  segment = ginCompressPostingList(&items[nrootitems],
1806  nitems - nrootitems,
1808  &npacked);
1809  segsize = SizeOfGinPostingList(segment);
1810  if (rootsize + segsize > GinDataPageMaxDataSize)
1811  break;
1812 
1813  memcpy(ptr, segment, segsize);
1814  ptr += segsize;
1815  rootsize += segsize;
1816  nrootitems += npacked;
1817  pfree(segment);
1818  }
1819  GinDataPageSetDataSize(tmppage, rootsize);
1820 
1821  /*
1822  * All set. Get a new physical page, and copy the in-memory page to it.
1823  */
1824  buffer = GinNewBuffer(index);
1825  page = BufferGetPage(buffer);
1826  blkno = BufferGetBlockNumber(buffer);
1827 
1828  /*
1829  * Copy any predicate locks from the entry tree leaf (containing posting
1830  * list) to the posting tree.
1831  */
1832  PredicateLockPageSplit(index, BufferGetBlockNumber(entrybuffer), blkno);
1833 
1835 
1836  PageRestoreTempPage(tmppage, page);
1837  MarkBufferDirty(buffer);
1838 
1839  if (RelationNeedsWAL(index) && !is_build)
1840  {
1841  XLogRecPtr recptr;
1843 
1844  data.size = rootsize;
1845 
1846  XLogBeginInsert();
1847  XLogRegisterData((char *) &data, sizeof(ginxlogCreatePostingTree));
1848 
1850  rootsize);
1852 
1853  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_PTREE);
1854  PageSetLSN(page, recptr);
1855  }
1856 
1857  UnlockReleaseBuffer(buffer);
1858 
1859  END_CRIT_SECTION();
1860 
1861  /* During index build, count the newly-added data page */
1862  if (buildStats)
1863  buildStats->nDataPages++;
1864 
1865  elog(DEBUG2, "created GIN posting tree with %d items", nrootitems);
1866 
1867  /*
1868  * Add any remaining TIDs to the newly-created posting tree.
1869  */
1870  if (nitems > nrootitems)
1871  {
1873  items + nrootitems,
1874  nitems - nrootitems,
1875  buildStats);
1876  }
1877 
1878  return blkno;
1879 }
uint32 BlockNumber
Definition: block.h:31
#define InvalidBlockNumber
Definition: block.h:33
int Buffer
Definition: buf.h:23
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:3378
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4578
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2190
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:350
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:424
Pointer Page
Definition: bufpage.h:78
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:388
char * Pointer
Definition: c.h:472
#define DEBUG2
Definition: elog.h:29
#define GIN_DATA
Definition: ginblock.h:41
#define GIN_COMPRESSED
Definition: ginblock.h:48
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
#define GIN_LEAF
Definition: ginblock.h:42
#define GinDataPageSetDataSize(page, size)
Definition: ginblock.h:309
#define GinDataPageMaxDataSize
Definition: ginblock.h:319
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:278
#define GinPostingListSegmentMaxSize
Definition: gindatapage.c:34
void ginInsertItemPointers(Relation index, BlockNumber rootBlkno, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gindatapage.c:1908
GinPostingList * ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:339
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:301
#define XLOG_GIN_CREATE_PTREE
Definition: ginxlog.h:19
#define nitems(x)
Definition: indent.h:31
void pfree(void *pointer)
Definition: mcxt.c:1431
#define START_CRIT_SECTION()
Definition: miscadmin.h:149
#define END_CRIT_SECTION()
Definition: miscadmin.h:151
const void * data
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3114
#define RelationNeedsWAL(relation)
Definition: rel.h:627
BlockNumber nDataPages
Definition: gin.h:47
Definition: type.h:95
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:365
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:475
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:243
void XLogBeginInsert(void)
Definition: xloginsert.c:150
#define REGBUF_WILL_INIT
Definition: xloginsert.h:33

References BufferGetBlockNumber(), BufferGetPage(), data, DEBUG2, elog(), END_CRIT_SECTION, GIN_COMPRESSED, GIN_DATA, GIN_LEAF, ginCompressPostingList(), GinDataLeafPageGetPostingList, GinDataPageMaxDataSize, GinDataPageSetDataSize, GinInitPage(), ginInsertItemPointers(), GinNewBuffer(), GinPageGetOpaque, GinPostingListSegmentMaxSize, InvalidBlockNumber, MarkBufferDirty(), GinStatsData::nDataPages, nitems, PageRestoreTempPage(), PageSetLSN(), palloc(), pfree(), PredicateLockPageSplit(), REGBUF_WILL_INIT, RelationNeedsWAL, SizeOfGinPostingList, START_CRIT_SECTION, UnlockReleaseBuffer(), XLOG_GIN_CREATE_PTREE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by addItemPointersToLeafTuple(), and buildFreshLeafTuple().

◆ dataBeginPlaceToPage()

static GinPlaceToPageRC dataBeginPlaceToPage ( GinBtree  btree,
Buffer  buf,
GinBtreeStack stack,
void *  insertdata,
BlockNumber  updateblkno,
void **  ptp_workspace,
Page newlpage,
Page newrpage 
)
static

Definition at line 1201 of file gindatapage.c.

1205 {
1206  Page page = BufferGetPage(buf);
1207 
1208  Assert(GinPageIsData(page));
1209 
1210  if (GinPageIsLeaf(page))
1211  return dataBeginPlaceToPageLeaf(btree, buf, stack, insertdata,
1212  ptp_workspace,
1213  newlpage, newrpage);
1214  else
1215  return dataBeginPlaceToPageInternal(btree, buf, stack,
1216  insertdata, updateblkno,
1217  ptp_workspace,
1218  newlpage, newrpage);
1219 }
#define GinPageIsData(page)
Definition: ginblock.h:115
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
static GinPlaceToPageRC dataBeginPlaceToPageLeaf(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, void **ptp_workspace, Page *newlpage, Page *newrpage)
Definition: gindatapage.c:448
static GinPlaceToPageRC dataBeginPlaceToPageInternal(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, void **ptp_workspace, Page *newlpage, Page *newrpage)
Definition: gindatapage.c:1119
static char * buf
Definition: pg_test_fsync.c:73

References Assert(), buf, BufferGetPage(), dataBeginPlaceToPageInternal(), dataBeginPlaceToPageLeaf(), GinPageIsData, and GinPageIsLeaf.

Referenced by ginPrepareDataScan().

◆ dataBeginPlaceToPageInternal()

static GinPlaceToPageRC dataBeginPlaceToPageInternal ( GinBtree  btree,
Buffer  buf,
GinBtreeStack stack,
void *  insertdata,
BlockNumber  updateblkno,
void **  ptp_workspace,
Page newlpage,
Page newrpage 
)
static

Definition at line 1119 of file gindatapage.c.

1123 {
1124  Page page = BufferGetPage(buf);
1125 
1126  /* If it doesn't fit, deal with split case */
1127  if (GinNonLeafDataPageGetFreeSpace(page) < sizeof(PostingItem))
1128  {
1129  dataSplitPageInternal(btree, buf, stack, insertdata, updateblkno,
1130  newlpage, newrpage);
1131  return GPTP_SPLIT;
1132  }
1133 
1134  /* Else, we're ready to proceed with insertion */
1135  return GPTP_INSERT;
1136 }
@ GPTP_INSERT
Definition: gin_private.h:146
@ GPTP_SPLIT
Definition: gin_private.h:147
#define GinNonLeafDataPageGetFreeSpace(page)
Definition: ginblock.h:315
static void dataSplitPageInternal(GinBtree btree, Buffer origbuf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, Page *newlpage, Page *newrpage)
Definition: gindatapage.c:1252

References buf, BufferGetPage(), dataSplitPageInternal(), GinNonLeafDataPageGetFreeSpace, GPTP_INSERT, and GPTP_SPLIT.

Referenced by dataBeginPlaceToPage().

◆ dataBeginPlaceToPageLeaf()

static GinPlaceToPageRC dataBeginPlaceToPageLeaf ( GinBtree  btree,
Buffer  buf,
GinBtreeStack stack,
void *  insertdata,
void **  ptp_workspace,
Page newlpage,
Page newrpage 
)
static

Definition at line 448 of file gindatapage.c.

452 {
453  GinBtreeDataLeafInsertData *items = insertdata;
454  ItemPointer newItems = &items->items[items->curitem];
455  int maxitems = items->nitem - items->curitem;
456  Page page = BufferGetPage(buf);
457  int i;
458  ItemPointerData rbound;
459  ItemPointerData lbound;
460  bool needsplit;
461  bool append;
462  int segsize;
463  Size freespace;
464  disassembledLeaf *leaf;
465  leafSegmentInfo *lastleftinfo;
466  ItemPointerData maxOldItem;
468 
469  rbound = *GinDataPageGetRightBound(page);
470 
471  /*
472  * Count how many of the new items belong to this page.
473  */
474  if (!GinPageRightMost(page))
475  {
476  for (i = 0; i < maxitems; i++)
477  {
478  if (ginCompareItemPointers(&newItems[i], &rbound) > 0)
479  {
480  /*
481  * This needs to go to some other location in the tree. (The
482  * caller should've chosen the insert location so that at
483  * least the first item goes here.)
484  */
485  Assert(i > 0);
486  break;
487  }
488  }
489  maxitems = i;
490  }
491 
492  /* Disassemble the data on the page */
493  leaf = disassembleLeaf(page);
494 
495  /*
496  * Are we appending to the end of the page? IOW, are all the new items
497  * larger than any of the existing items.
498  */
499  if (!dlist_is_empty(&leaf->segments))
500  {
501  lastleftinfo = dlist_container(leafSegmentInfo, node,
502  dlist_tail_node(&leaf->segments));
503  if (!lastleftinfo->items)
504  lastleftinfo->items = ginPostingListDecode(lastleftinfo->seg,
505  &lastleftinfo->nitems);
506  maxOldItem = lastleftinfo->items[lastleftinfo->nitems - 1];
507  if (ginCompareItemPointers(&newItems[0], &maxOldItem) >= 0)
508  append = true;
509  else
510  append = false;
511  }
512  else
513  {
514  ItemPointerSetMin(&maxOldItem);
515  append = true;
516  }
517 
518  /*
519  * If we're appending to the end of the page, we will append as many items
520  * as we can fit (after splitting), and stop when the pages becomes full.
521  * Otherwise we have to limit the number of new items to insert, because
522  * once we start packing we can't just stop when we run out of space,
523  * because we must make sure that all the old items still fit.
524  */
525  if (GinPageIsCompressed(page))
526  freespace = GinDataLeafPageGetFreeSpace(page);
527  else
528  freespace = 0;
529  if (append)
530  {
531  /*
532  * Even when appending, trying to append more items than will fit is
533  * not completely free, because we will merge the new items and old
534  * items into an array below. In the best case, every new item fits in
535  * a single byte, and we can use all the free space on the old page as
536  * well as the new page. For simplicity, ignore segment overhead etc.
537  */
538  maxitems = Min(maxitems, freespace + GinDataPageMaxDataSize);
539  }
540  else
541  {
542  /*
543  * Calculate a conservative estimate of how many new items we can fit
544  * on the two pages after splitting.
545  *
546  * We can use any remaining free space on the old page to store full
547  * segments, as well as the new page. Each full-sized segment can hold
548  * at least MinTuplesPerSegment items
549  */
550  int nnewsegments;
551 
552  nnewsegments = freespace / GinPostingListSegmentMaxSize;
554  maxitems = Min(maxitems, nnewsegments * MinTuplesPerSegment);
555  }
556 
557  /* Add the new items to the segment list */
558  if (!addItemsToLeaf(leaf, newItems, maxitems))
559  {
560  /* all items were duplicates, we have nothing to do */
561  items->curitem += maxitems;
562 
563  return GPTP_NO_WORK;
564  }
565 
566  /*
567  * Pack the items back to compressed segments, ready for writing to disk.
568  */
569  needsplit = leafRepackItems(leaf, &remaining);
570 
571  /*
572  * Did all the new items fit?
573  *
574  * If we're appending, it's OK if they didn't. But as a sanity check,
575  * verify that all the old items fit.
576  */
578  {
579  if (!append || ItemPointerCompare(&maxOldItem, &remaining) >= 0)
580  elog(ERROR, "could not split GIN page; all old items didn't fit");
581 
582  /* Count how many of the new items did fit. */
583  for (i = 0; i < maxitems; i++)
584  {
585  if (ginCompareItemPointers(&newItems[i], &remaining) >= 0)
586  break;
587  }
588  if (i == 0)
589  elog(ERROR, "could not split GIN page; no new items fit");
590  maxitems = i;
591  }
592 
593  if (!needsplit)
594  {
595  /*
596  * Great, all the items fit on a single page. If needed, prepare data
597  * for a WAL record describing the changes we'll make.
598  */
599  if (RelationNeedsWAL(btree->index) && !btree->isBuild)
601 
602  /*
603  * We're ready to enter the critical section, but
604  * dataExecPlaceToPageLeaf will need access to the "leaf" data.
605  */
606  *ptp_workspace = leaf;
607 
608  if (append)
609  elog(DEBUG2, "appended %d new items to block %u; %d bytes (%d to go)",
610  maxitems, BufferGetBlockNumber(buf), (int) leaf->lsize,
611  items->nitem - items->curitem - maxitems);
612  else
613  elog(DEBUG2, "inserted %d new items to block %u; %d bytes (%d to go)",
614  maxitems, BufferGetBlockNumber(buf), (int) leaf->lsize,
615  items->nitem - items->curitem - maxitems);
616  }
617  else
618  {
619  /*
620  * Have to split.
621  *
622  * leafRepackItems already divided the segments between the left and
623  * the right page. It filled the left page as full as possible, and
624  * put the rest to the right page. When building a new index, that's
625  * good, because the table is scanned from beginning to end and there
626  * won't be any more insertions to the left page during the build.
627  * This packs the index as tight as possible. But otherwise, split
628  * 50/50, by moving segments from the left page to the right page
629  * until they're balanced.
630  *
631  * As a further heuristic, when appending items to the end of the
632  * page, try to make the left page 75% full, on the assumption that
633  * subsequent insertions will probably also go to the end. This packs
634  * the index somewhat tighter when appending to a table, which is very
635  * common.
636  */
637  if (!btree->isBuild)
638  {
639  while (dlist_has_prev(&leaf->segments, leaf->lastleft))
640  {
641  lastleftinfo = dlist_container(leafSegmentInfo, node, leaf->lastleft);
642 
643  /* ignore deleted segments */
644  if (lastleftinfo->action != GIN_SEGMENT_DELETE)
645  {
646  segsize = SizeOfGinPostingList(lastleftinfo->seg);
647 
648  /*
649  * Note that we check that the right page doesn't become
650  * more full than the left page even when appending. It's
651  * possible that we added enough items to make both pages
652  * more than 75% full.
653  */
654  if ((leaf->lsize - segsize) - (leaf->rsize + segsize) < 0)
655  break;
656  if (append)
657  {
658  if ((leaf->lsize - segsize) < (BLCKSZ * 3) / 4)
659  break;
660  }
661 
662  leaf->lsize -= segsize;
663  leaf->rsize += segsize;
664  }
665  leaf->lastleft = dlist_prev_node(&leaf->segments, leaf->lastleft);
666  }
667  }
670 
671  /*
672  * Fetch the max item in the left page's last segment; it becomes the
673  * right bound of the page.
674  */
675  lastleftinfo = dlist_container(leafSegmentInfo, node, leaf->lastleft);
676  if (!lastleftinfo->items)
677  lastleftinfo->items = ginPostingListDecode(lastleftinfo->seg,
678  &lastleftinfo->nitems);
679  lbound = lastleftinfo->items[lastleftinfo->nitems - 1];
680 
681  /*
682  * Now allocate a couple of temporary page images, and fill them.
683  */
684  *newlpage = palloc(BLCKSZ);
685  *newrpage = palloc(BLCKSZ);
686 
687  dataPlaceToPageLeafSplit(leaf, lbound, rbound,
688  *newlpage, *newrpage);
689 
690  Assert(GinPageRightMost(page) ||
692  GinDataPageGetRightBound(*newrpage)) < 0);
693 
694  if (append)
695  elog(DEBUG2, "appended %d items to block %u; split %d/%d (%d to go)",
696  maxitems, BufferGetBlockNumber(buf), (int) leaf->lsize, (int) leaf->rsize,
697  items->nitem - items->curitem - maxitems);
698  else
699  elog(DEBUG2, "inserted %d items to block %u; split %d/%d (%d to go)",
700  maxitems, BufferGetBlockNumber(buf), (int) leaf->lsize, (int) leaf->rsize,
701  items->nitem - items->curitem - maxitems);
702  }
703 
704  items->curitem += maxitems;
705 
706  return needsplit ? GPTP_SPLIT : GPTP_INSERT;
707 }
#define Min(x, y)
Definition: c.h:993
size_t Size
Definition: c.h:594
@ GPTP_NO_WORK
Definition: gin_private.h:145
#define GinDataLeafPageGetFreeSpace(page)
Definition: ginblock.h:286
#define GinDataPageGetRightBound(page)
Definition: ginblock.h:288
#define GinPageRightMost(page)
Definition: ginblock.h:129
#define ItemPointerSetMin(p)
Definition: ginblock.h:166
#define GinPageIsCompressed(page)
Definition: ginblock.h:121
#define MinTuplesPerSegment
Definition: gindatapage.c:43
static bool addItemsToLeaf(disassembledLeaf *leaf, ItemPointer newItems, int nNewItems)
Definition: gindatapage.c:1444
static bool leafRepackItems(disassembledLeaf *leaf, ItemPointer remaining)
Definition: gindatapage.c:1571
static void dataPlaceToPageLeafSplit(disassembledLeaf *leaf, ItemPointerData lbound, ItemPointerData rbound, Page lpage, Page rpage)
Definition: gindatapage.c:1034
static void computeLeafRecompressWALData(disassembledLeaf *leaf)
Definition: gindatapage.c:872
static disassembledLeaf * disassembleLeaf(Page page)
Definition: gindatapage.c:1370
static dlist_node * dlist_prev_node(dlist_head *head, dlist_node *node)
Definition: ilist.h:547
static bool dlist_has_prev(const dlist_head *head, const dlist_node *node)
Definition: ilist.h:513
static dlist_node * dlist_tail_node(dlist_head *head)
Definition: ilist.h:582
int remaining
Definition: informix.c:667
int i
Definition: isn.c:73
int32 ItemPointerCompare(ItemPointer arg1, ItemPointer arg2)
Definition: itemptr.c:51
static bool ItemPointerIsValid(const ItemPointerData *pointer)
Definition: itemptr.h:83
ItemPointerData * items
Definition: gin_private.h:195
Relation index
Definition: gin_private.h:167
dlist_node * lastleft
Definition: gindatapage.c:56

References leafSegmentInfo::action, addItemsToLeaf(), Assert(), buf, BufferGetBlockNumber(), BufferGetPage(), computeLeafRecompressWALData(), GinBtreeDataLeafInsertData::curitem, dataPlaceToPageLeafSplit(), DEBUG2, disassembleLeaf(), dlist_container, dlist_has_prev(), dlist_is_empty(), dlist_prev_node(), dlist_tail_node(), elog(), ERROR, GIN_SEGMENT_DELETE, ginCompareItemPointers(), GinDataLeafPageGetFreeSpace, GinDataPageGetRightBound, GinDataPageMaxDataSize, GinPageIsCompressed, GinPageRightMost, ginPostingListDecode(), GinPostingListSegmentMaxSize, GPTP_INSERT, GPTP_NO_WORK, GPTP_SPLIT, i, GinBtreeData::index, GinBtreeData::isBuild, ItemPointerCompare(), ItemPointerIsValid(), ItemPointerSetMin, leafSegmentInfo::items, GinBtreeDataLeafInsertData::items, disassembledLeaf::lastleft, leafRepackItems(), disassembledLeaf::lsize, Min, MinTuplesPerSegment, GinBtreeDataLeafInsertData::nitem, leafSegmentInfo::nitems, palloc(), RelationNeedsWAL, remaining, disassembledLeaf::rsize, leafSegmentInfo::seg, disassembledLeaf::segments, and SizeOfGinPostingList.

Referenced by dataBeginPlaceToPage().

◆ dataExecPlaceToPage()

static void dataExecPlaceToPage ( GinBtree  btree,
Buffer  buf,
GinBtreeStack stack,
void *  insertdata,
BlockNumber  updateblkno,
void *  ptp_workspace 
)
static

Definition at line 1231 of file gindatapage.c.

1234 {
1235  Page page = BufferGetPage(buf);
1236 
1237  if (GinPageIsLeaf(page))
1238  dataExecPlaceToPageLeaf(btree, buf, stack, insertdata,
1239  ptp_workspace);
1240  else
1241  dataExecPlaceToPageInternal(btree, buf, stack, insertdata,
1242  updateblkno, ptp_workspace);
1243 }
static void dataExecPlaceToPageLeaf(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, void *ptp_workspace)
Definition: gindatapage.c:716
static void dataExecPlaceToPageInternal(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, void *ptp_workspace)
Definition: gindatapage.c:1145

References buf, BufferGetPage(), dataExecPlaceToPageInternal(), dataExecPlaceToPageLeaf(), and GinPageIsLeaf.

Referenced by ginPrepareDataScan().

◆ dataExecPlaceToPageInternal()

static void dataExecPlaceToPageInternal ( GinBtree  btree,
Buffer  buf,
GinBtreeStack stack,
void *  insertdata,
BlockNumber  updateblkno,
void *  ptp_workspace 
)
static

Definition at line 1145 of file gindatapage.c.

1148 {
1149  Page page = BufferGetPage(buf);
1150  OffsetNumber off = stack->off;
1151  PostingItem *pitem;
1152 
1153  /* Update existing downlink to point to next page (on internal page) */
1154  pitem = GinDataPageGetPostingItem(page, off);
1155  PostingItemSetBlockNumber(pitem, updateblkno);
1156 
1157  /* Add new item */
1158  pitem = (PostingItem *) insertdata;
1159  GinDataPageAddPostingItem(page, pitem, off);
1160 
1162 
1163  if (RelationNeedsWAL(btree->index) && !btree->isBuild)
1164  {
1165  /*
1166  * This must be static, because it has to survive until XLogInsert,
1167  * and we can't palloc here. Ugly, but the XLogInsert infrastructure
1168  * isn't reentrant anyway.
1169  */
1171 
1172  data.offset = off;
1173  data.newitem = *pitem;
1174 
1176  XLogRegisterBufData(0, (char *) &data,
1177  sizeof(ginxlogInsertDataInternal));
1178  }
1179 }
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:298
#define PostingItemSetBlockNumber(pointer, blockNumber)
Definition: ginblock.h:192
void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset)
Definition: gindatapage.c:380
uint16 OffsetNumber
Definition: off.h:24
OffsetNumber off
Definition: gin_private.h:133
void XLogRegisterBufData(uint8 block_id, char *data, uint32 len)
Definition: xloginsert.c:406
#define REGBUF_STANDARD
Definition: xloginsert.h:34

References buf, BufferGetPage(), data, GinDataPageAddPostingItem(), GinDataPageGetPostingItem, GinBtreeData::index, GinBtreeData::isBuild, MarkBufferDirty(), GinBtreeStack::off, PostingItemSetBlockNumber, REGBUF_STANDARD, RelationNeedsWAL, XLogRegisterBufData(), and XLogRegisterBuffer().

Referenced by dataExecPlaceToPage().

◆ dataExecPlaceToPageLeaf()

static void dataExecPlaceToPageLeaf ( GinBtree  btree,
Buffer  buf,
GinBtreeStack stack,
void *  insertdata,
void *  ptp_workspace 
)
static

Definition at line 716 of file gindatapage.c.

718 {
719  disassembledLeaf *leaf = (disassembledLeaf *) ptp_workspace;
720 
721  /* Apply changes to page */
723 
725 
726  /* If needed, register WAL data built by computeLeafRecompressWALData */
727  if (RelationNeedsWAL(btree->index) && !btree->isBuild)
728  {
730  XLogRegisterBufData(0, leaf->walinfo, leaf->walinfolen);
731  }
732 }
static void dataPlaceToPageLeafRecompress(Buffer buf, disassembledLeaf *leaf)
Definition: gindatapage.c:978

References buf, dataPlaceToPageLeafRecompress(), GinBtreeData::index, GinBtreeData::isBuild, MarkBufferDirty(), REGBUF_STANDARD, RelationNeedsWAL, disassembledLeaf::walinfo, disassembledLeaf::walinfolen, XLogRegisterBufData(), and XLogRegisterBuffer().

Referenced by dataExecPlaceToPage().

◆ dataFindChildPtr()

static OffsetNumber dataFindChildPtr ( GinBtree  btree,
Page  page,
BlockNumber  blkno,
OffsetNumber  storedOff 
)
static

Definition at line 319 of file gindatapage.c.

320 {
321  OffsetNumber i,
322  maxoff = GinPageGetOpaque(page)->maxoff;
323  PostingItem *pitem;
324 
325  Assert(!GinPageIsLeaf(page));
326  Assert(GinPageIsData(page));
327 
328  /* if page isn't changed, we return storedOff */
329  if (storedOff >= FirstOffsetNumber && storedOff <= maxoff)
330  {
331  pitem = GinDataPageGetPostingItem(page, storedOff);
332  if (PostingItemGetBlockNumber(pitem) == blkno)
333  return storedOff;
334 
335  /*
336  * we hope, that needed pointer goes to right. It's true if there
337  * wasn't a deletion
338  */
339  for (i = storedOff + 1; i <= maxoff; i++)
340  {
341  pitem = GinDataPageGetPostingItem(page, i);
342  if (PostingItemGetBlockNumber(pitem) == blkno)
343  return i;
344  }
345 
346  maxoff = storedOff - 1;
347  }
348 
349  /* last chance */
350  for (i = FirstOffsetNumber; i <= maxoff; i++)
351  {
352  pitem = GinDataPageGetPostingItem(page, i);
353  if (PostingItemGetBlockNumber(pitem) == blkno)
354  return i;
355  }
356 
357  return InvalidOffsetNumber;
358 }
#define PostingItemGetBlockNumber(pointer)
Definition: ginblock.h:189
#define InvalidOffsetNumber
Definition: off.h:26
#define FirstOffsetNumber
Definition: off.h:27

References Assert(), FirstOffsetNumber, GinDataPageGetPostingItem, GinPageGetOpaque, GinPageIsData, GinPageIsLeaf, i, InvalidOffsetNumber, and PostingItemGetBlockNumber.

Referenced by ginPrepareDataScan().

◆ dataGetLeftMostPage()

static BlockNumber dataGetLeftMostPage ( GinBtree  btree,
Page  page 
)
static

Definition at line 364 of file gindatapage.c.

365 {
366  PostingItem *pitem;
367 
368  Assert(!GinPageIsLeaf(page));
369  Assert(GinPageIsData(page));
370  Assert(GinPageGetOpaque(page)->maxoff >= FirstOffsetNumber);
371 
373  return PostingItemGetBlockNumber(pitem);
374 }

References Assert(), FirstOffsetNumber, GinDataPageGetPostingItem, GinPageGetOpaque, GinPageIsData, GinPageIsLeaf, and PostingItemGetBlockNumber.

Referenced by ginPrepareDataScan().

◆ dataIsMoveRight()

static bool dataIsMoveRight ( GinBtree  btree,
Page  page 
)
static

Definition at line 234 of file gindatapage.c.

235 {
237 
238  if (GinPageRightMost(page))
239  return false;
240 
241  if (GinPageIsDeleted(page))
242  return true;
243 
244  return (ginCompareItemPointers(&btree->itemptr, iptr) > 0);
245 }
#define GinPageIsDeleted(page)
Definition: ginblock.h:124
ItemPointerData itemptr
Definition: gin_private.h:179

References ginCompareItemPointers(), GinDataPageGetRightBound, GinPageIsDeleted, GinPageRightMost, and GinBtreeData::itemptr.

Referenced by ginPrepareDataScan().

◆ dataLeafPageGetUncompressed()

static ItemPointer dataLeafPageGetUncompressed ( Page  page,
int *  nitems 
)
static

Definition at line 211 of file gindatapage.c.

212 {
213  ItemPointer items;
214 
215  Assert(!GinPageIsCompressed(page));
216 
217  /*
218  * In the old pre-9.4 page format, the whole page content is used for
219  * uncompressed items, and the number of items is stored in 'maxoff'
220  */
221  items = (ItemPointer) GinDataPageGetData(page);
222  *nitems = GinPageGetOpaque(page)->maxoff;
223 
224  return items;
225 }
#define GinDataPageGetData(page)
Definition: ginblock.h:295
ItemPointerData * ItemPointer
Definition: itemptr.h:49

References Assert(), GinDataPageGetData, GinPageGetOpaque, GinPageIsCompressed, and nitems.

Referenced by disassembleLeaf(), GinDataLeafPageGetItems(), and GinDataLeafPageGetItemsToTbm().

◆ dataLocateItem()

static BlockNumber dataLocateItem ( GinBtree  btree,
GinBtreeStack stack 
)
static

Definition at line 252 of file gindatapage.c.

253 {
254  OffsetNumber low,
255  high,
256  maxoff;
257  PostingItem *pitem = NULL;
258  int result;
259  Page page = BufferGetPage(stack->buffer);
260 
261  Assert(!GinPageIsLeaf(page));
262  Assert(GinPageIsData(page));
263 
264  if (btree->fullScan)
265  {
266  stack->off = FirstOffsetNumber;
267  stack->predictNumber *= GinPageGetOpaque(page)->maxoff;
268  return btree->getLeftMostChild(btree, page);
269  }
270 
271  low = FirstOffsetNumber;
272  maxoff = high = GinPageGetOpaque(page)->maxoff;
273  Assert(high >= low);
274 
275  high++;
276 
277  while (high > low)
278  {
279  OffsetNumber mid = low + ((high - low) / 2);
280 
281  pitem = GinDataPageGetPostingItem(page, mid);
282 
283  if (mid == maxoff)
284  {
285  /*
286  * Right infinity, page already correctly chosen with a help of
287  * dataIsMoveRight
288  */
289  result = -1;
290  }
291  else
292  {
293  pitem = GinDataPageGetPostingItem(page, mid);
294  result = ginCompareItemPointers(&btree->itemptr, &(pitem->key));
295  }
296 
297  if (result == 0)
298  {
299  stack->off = mid;
300  return PostingItemGetBlockNumber(pitem);
301  }
302  else if (result > 0)
303  low = mid + 1;
304  else
305  high = mid;
306  }
307 
308  Assert(high >= FirstOffsetNumber && high <= maxoff);
309 
310  stack->off = high;
311  pitem = GinDataPageGetPostingItem(page, high);
312  return PostingItemGetBlockNumber(pitem);
313 }
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:154
uint32 predictNumber
Definition: gin_private.h:136
ItemPointerData key
Definition: ginblock.h:186

References Assert(), GinBtreeStack::buffer, BufferGetPage(), FirstOffsetNumber, GinBtreeData::fullScan, GinBtreeData::getLeftMostChild, ginCompareItemPointers(), GinDataPageGetPostingItem, GinPageGetOpaque, GinPageIsData, GinPageIsLeaf, GinBtreeData::itemptr, PostingItem::key, GinBtreeStack::off, PostingItemGetBlockNumber, and GinBtreeStack::predictNumber.

Referenced by ginPrepareDataScan().

◆ dataPlaceToPageLeafRecompress()

static void dataPlaceToPageLeafRecompress ( Buffer  buf,
disassembledLeaf leaf 
)
static

Definition at line 978 of file gindatapage.c.

979 {
980  Page page = BufferGetPage(buf);
981  char *ptr;
982  int newsize;
983  bool modified = false;
984  dlist_iter iter;
985  int segsize;
986 
987  /*
988  * If the page was in pre-9.4 format before, convert the header, and force
989  * all segments to be copied to the page whether they were modified or
990  * not.
991  */
992  if (!GinPageIsCompressed(page))
993  {
994  Assert(leaf->oldformat);
995  GinPageSetCompressed(page);
996  GinPageGetOpaque(page)->maxoff = InvalidOffsetNumber;
997  modified = true;
998  }
999 
1000  ptr = (char *) GinDataLeafPageGetPostingList(page);
1001  newsize = 0;
1002  dlist_foreach(iter, &leaf->segments)
1003  {
1004  leafSegmentInfo *seginfo = dlist_container(leafSegmentInfo, node, iter.cur);
1005 
1006  if (seginfo->action != GIN_SEGMENT_UNMODIFIED)
1007  modified = true;
1008 
1009  if (seginfo->action != GIN_SEGMENT_DELETE)
1010  {
1011  segsize = SizeOfGinPostingList(seginfo->seg);
1012 
1013  if (modified)
1014  memcpy(ptr, seginfo->seg, segsize);
1015 
1016  ptr += segsize;
1017  newsize += segsize;
1018  }
1019  }
1020 
1021  Assert(newsize <= GinDataPageMaxDataSize);
1022  GinDataPageSetDataSize(page, newsize);
1023 }
#define GinPageSetCompressed(page)
Definition: ginblock.h:122

References leafSegmentInfo::action, Assert(), buf, BufferGetPage(), dlist_iter::cur, dlist_container, dlist_foreach, GIN_SEGMENT_DELETE, GIN_SEGMENT_UNMODIFIED, GinDataLeafPageGetPostingList, GinDataPageMaxDataSize, GinDataPageSetDataSize, GinPageGetOpaque, GinPageIsCompressed, GinPageSetCompressed, InvalidOffsetNumber, disassembledLeaf::oldformat, leafSegmentInfo::seg, disassembledLeaf::segments, and SizeOfGinPostingList.

Referenced by dataExecPlaceToPageLeaf(), and ginVacuumPostingTreeLeaf().

◆ dataPlaceToPageLeafSplit()

static void dataPlaceToPageLeafSplit ( disassembledLeaf leaf,
ItemPointerData  lbound,
ItemPointerData  rbound,
Page  lpage,
Page  rpage 
)
static

Definition at line 1034 of file gindatapage.c.

1037 {
1038  char *ptr;
1039  int segsize;
1040  int lsize;
1041  int rsize;
1042  dlist_node *node;
1043  dlist_node *firstright;
1044  leafSegmentInfo *seginfo;
1045 
1046  /* Initialize temporary pages to hold the new left and right pages */
1047  GinInitPage(lpage, GIN_DATA | GIN_LEAF | GIN_COMPRESSED, BLCKSZ);
1048  GinInitPage(rpage, GIN_DATA | GIN_LEAF | GIN_COMPRESSED, BLCKSZ);
1049 
1050  /*
1051  * Copy the segments that go to the left page.
1052  *
1053  * XXX: We should skip copying the unmodified part of the left page, like
1054  * we do when recompressing.
1055  */
1056  lsize = 0;
1057  ptr = (char *) GinDataLeafPageGetPostingList(lpage);
1058  firstright = dlist_next_node(&leaf->segments, leaf->lastleft);
1059  for (node = dlist_head_node(&leaf->segments);
1060  node != firstright;
1061  node = dlist_next_node(&leaf->segments, node))
1062  {
1063  seginfo = dlist_container(leafSegmentInfo, node, node);
1064 
1065  if (seginfo->action != GIN_SEGMENT_DELETE)
1066  {
1067  segsize = SizeOfGinPostingList(seginfo->seg);
1068  memcpy(ptr, seginfo->seg, segsize);
1069  ptr += segsize;
1070  lsize += segsize;
1071  }
1072  }
1073  Assert(lsize == leaf->lsize);
1074  GinDataPageSetDataSize(lpage, lsize);
1075  *GinDataPageGetRightBound(lpage) = lbound;
1076 
1077  /* Copy the segments that go to the right page */
1078  ptr = (char *) GinDataLeafPageGetPostingList(rpage);
1079  rsize = 0;
1080  for (node = firstright;
1081  ;
1082  node = dlist_next_node(&leaf->segments, node))
1083  {
1084  seginfo = dlist_container(leafSegmentInfo, node, node);
1085 
1086  if (seginfo->action != GIN_SEGMENT_DELETE)
1087  {
1088  segsize = SizeOfGinPostingList(seginfo->seg);
1089  memcpy(ptr, seginfo->seg, segsize);
1090  ptr += segsize;
1091  rsize += segsize;
1092  }
1093 
1094  if (!dlist_has_next(&leaf->segments, node))
1095  break;
1096  }
1097  Assert(rsize == leaf->rsize);
1098  GinDataPageSetDataSize(rpage, rsize);
1099  *GinDataPageGetRightBound(rpage) = rbound;
1100 }
static dlist_node * dlist_head_node(dlist_head *head)
Definition: ilist.h:565

References leafSegmentInfo::action, Assert(), dlist_container, dlist_has_next(), dlist_head_node(), dlist_next_node(), GIN_COMPRESSED, GIN_DATA, GIN_LEAF, GIN_SEGMENT_DELETE, GinDataLeafPageGetPostingList, GinDataPageGetRightBound, GinDataPageSetDataSize, GinInitPage(), disassembledLeaf::lastleft, disassembledLeaf::lsize, disassembledLeaf::rsize, leafSegmentInfo::seg, disassembledLeaf::segments, and SizeOfGinPostingList.

Referenced by dataBeginPlaceToPageLeaf().

◆ dataPrepareDownlink()

static void* dataPrepareDownlink ( GinBtree  btree,
Buffer  lbuf 
)
static

Definition at line 1333 of file gindatapage.c.

1334 {
1335  PostingItem *pitem = palloc(sizeof(PostingItem));
1336  Page lpage = BufferGetPage(lbuf);
1337 
1339  pitem->key = *GinDataPageGetRightBound(lpage);
1340 
1341  return pitem;
1342 }

References BufferGetBlockNumber(), BufferGetPage(), GinDataPageGetRightBound, PostingItem::key, palloc(), and PostingItemSetBlockNumber.

Referenced by ginPrepareDataScan().

◆ dataSplitPageInternal()

static void dataSplitPageInternal ( GinBtree  btree,
Buffer  origbuf,
GinBtreeStack stack,
void *  insertdata,
BlockNumber  updateblkno,
Page newlpage,
Page newrpage 
)
static

Definition at line 1252 of file gindatapage.c.

1256 {
1257  Page oldpage = BufferGetPage(origbuf);
1258  OffsetNumber off = stack->off;
1259  int nitems = GinPageGetOpaque(oldpage)->maxoff;
1260  int nleftitems;
1261  int nrightitems;
1262  Size pageSize = PageGetPageSize(oldpage);
1263  ItemPointerData oldbound = *GinDataPageGetRightBound(oldpage);
1264  ItemPointer bound;
1265  Page lpage;
1266  Page rpage;
1268  PostingItem allitems[(BLCKSZ / sizeof(PostingItem)) + 1];
1269 
1270  lpage = PageGetTempPage(oldpage);
1271  rpage = PageGetTempPage(oldpage);
1272  GinInitPage(lpage, GinPageGetOpaque(oldpage)->flags, pageSize);
1273  GinInitPage(rpage, GinPageGetOpaque(oldpage)->flags, pageSize);
1274 
1275  /*
1276  * First construct a new list of PostingItems, which includes all the old
1277  * items, and the new item.
1278  */
1279  memcpy(allitems, GinDataPageGetPostingItem(oldpage, FirstOffsetNumber),
1280  (off - 1) * sizeof(PostingItem));
1281 
1282  allitems[off - 1] = *((PostingItem *) insertdata);
1283  memcpy(&allitems[off], GinDataPageGetPostingItem(oldpage, off),
1284  (nitems - (off - 1)) * sizeof(PostingItem));
1285  nitems++;
1286 
1287  /* Update existing downlink to point to next page */
1288  PostingItemSetBlockNumber(&allitems[off], updateblkno);
1289 
1290  /*
1291  * When creating a new index, fit as many tuples as possible on the left
1292  * page, on the assumption that the table is scanned from beginning to
1293  * end. This packs the index as tight as possible.
1294  */
1295  if (btree->isBuild && GinPageRightMost(oldpage))
1297  else
1298  separator = nitems / 2;
1299  nleftitems = separator;
1300  nrightitems = nitems - separator;
1301 
1303  allitems,
1304  nleftitems * sizeof(PostingItem));
1305  GinPageGetOpaque(lpage)->maxoff = nleftitems;
1307  &allitems[separator],
1308  nrightitems * sizeof(PostingItem));
1309  GinPageGetOpaque(rpage)->maxoff = nrightitems;
1310 
1311  /*
1312  * Also set pd_lower for both pages, like GinDataPageAddPostingItem does.
1313  */
1314  GinDataPageSetDataSize(lpage, nleftitems * sizeof(PostingItem));
1315  GinDataPageSetDataSize(rpage, nrightitems * sizeof(PostingItem));
1316 
1317  /* set up right bound for left page */
1318  bound = GinDataPageGetRightBound(lpage);
1319  *bound = GinDataPageGetPostingItem(lpage, nleftitems)->key;
1320 
1321  /* set up right bound for right page */
1322  *GinDataPageGetRightBound(rpage) = oldbound;
1323 
1324  /* return temp pages to caller */
1325  *newlpage = lpage;
1326  *newrpage = rpage;
1327 }
Page PageGetTempPage(Page page)
Definition: bufpage.c:365
static Size PageGetPageSize(Page page)
Definition: bufpage.h:273

References BufferGetPage(), FirstOffsetNumber, GinDataPageGetPostingItem, GinDataPageGetRightBound, GinDataPageSetDataSize, GinInitPage(), GinNonLeafDataPageGetFreeSpace, GinPageGetOpaque, GinPageRightMost, GinBtreeData::isBuild, nitems, GinBtreeStack::off, PageGetPageSize(), PageGetTempPage(), and PostingItemSetBlockNumber.

Referenced by dataBeginPlaceToPageInternal().

◆ disassembleLeaf()

static disassembledLeaf * disassembleLeaf ( Page  page)
static

Definition at line 1370 of file gindatapage.c.

1371 {
1372  disassembledLeaf *leaf;
1373  GinPostingList *seg;
1374  Pointer segbegin;
1375  Pointer segend;
1376 
1377  leaf = palloc0(sizeof(disassembledLeaf));
1378  dlist_init(&leaf->segments);
1379 
1380  if (GinPageIsCompressed(page))
1381  {
1382  /*
1383  * Create a leafSegmentInfo entry for each segment.
1384  */
1385  seg = GinDataLeafPageGetPostingList(page);
1386  segbegin = (Pointer) seg;
1387  segend = segbegin + GinDataLeafPageGetPostingListSize(page);
1388  while ((Pointer) seg < segend)
1389  {
1390  leafSegmentInfo *seginfo = palloc(sizeof(leafSegmentInfo));
1391 
1392  seginfo->action = GIN_SEGMENT_UNMODIFIED;
1393  seginfo->seg = seg;
1394  seginfo->items = NULL;
1395  seginfo->nitems = 0;
1396  dlist_push_tail(&leaf->segments, &seginfo->node);
1397 
1398  seg = GinNextPostingListSegment(seg);
1399  }
1400  leaf->oldformat = false;
1401  }
1402  else
1403  {
1404  /*
1405  * A pre-9.4 format uncompressed page is represented by a single
1406  * segment, with an array of items. The corner case is uncompressed
1407  * page containing no items, which is represented as no segments.
1408  */
1409  ItemPointer uncompressed;
1410  int nuncompressed;
1411  leafSegmentInfo *seginfo;
1412 
1413  uncompressed = dataLeafPageGetUncompressed(page, &nuncompressed);
1414 
1415  if (nuncompressed > 0)
1416  {
1417  seginfo = palloc(sizeof(leafSegmentInfo));
1418 
1419  seginfo->action = GIN_SEGMENT_REPLACE;
1420  seginfo->seg = NULL;
1421  seginfo->items = palloc(nuncompressed * sizeof(ItemPointerData));
1422  memcpy(seginfo->items, uncompressed, nuncompressed * sizeof(ItemPointerData));
1423  seginfo->nitems = nuncompressed;
1424 
1425  dlist_push_tail(&leaf->segments, &seginfo->node);
1426  }
1427 
1428  leaf->oldformat = true;
1429  }
1430 
1431  return leaf;
1432 }
#define GinDataLeafPageGetPostingListSize(page)
Definition: ginblock.h:280
#define GinNextPostingListSegment(cur)
Definition: ginblock.h:343
static ItemPointer dataLeafPageGetUncompressed(Page page, int *nitems)
Definition: gindatapage.c:211
static void dlist_init(dlist_head *head)
Definition: ilist.h:314
void * palloc0(Size size)
Definition: mcxt.c:1232

References leafSegmentInfo::action, dataLeafPageGetUncompressed(), dlist_init(), dlist_push_tail(), GIN_SEGMENT_REPLACE, GIN_SEGMENT_UNMODIFIED, GinDataLeafPageGetPostingList, GinDataLeafPageGetPostingListSize, GinNextPostingListSegment, GinPageIsCompressed, leafSegmentInfo::items, leafSegmentInfo::nitems, leafSegmentInfo::node, disassembledLeaf::oldformat, palloc(), palloc0(), leafSegmentInfo::seg, and disassembledLeaf::segments.

Referenced by dataBeginPlaceToPageLeaf(), and ginVacuumPostingTreeLeaf().

◆ ginDataFillRoot()

void ginDataFillRoot ( GinBtree  btree,
Page  root,
BlockNumber  lblkno,
Page  lpage,
BlockNumber  rblkno,
Page  rpage 
)

Definition at line 1349 of file gindatapage.c.

1350 {
1351  PostingItem li,
1352  ri;
1353 
1354  li.key = *GinDataPageGetRightBound(lpage);
1355  PostingItemSetBlockNumber(&li, lblkno);
1357 
1358  ri.key = *GinDataPageGetRightBound(rpage);
1359  PostingItemSetBlockNumber(&ri, rblkno);
1361 }

References GinDataPageAddPostingItem(), GinDataPageGetRightBound, InvalidOffsetNumber, PostingItem::key, and PostingItemSetBlockNumber.

Referenced by ginPrepareDataScan().

◆ GinDataLeafPageGetItems()

ItemPointer GinDataLeafPageGetItems ( Page  page,
int *  nitems,
ItemPointerData  advancePast 
)

Definition at line 135 of file gindatapage.c.

136 {
137  ItemPointer result;
138 
139  if (GinPageIsCompressed(page))
140  {
143  Pointer endptr = ((Pointer) seg) + len;
145 
146  /* Skip to the segment containing advancePast+1 */
147  if (ItemPointerIsValid(&advancePast))
148  {
150  while ((Pointer) next < endptr &&
151  ginCompareItemPointers(&next->first, &advancePast) <= 0)
152  {
153  seg = next;
155  }
156  len = endptr - (Pointer) seg;
157  }
158 
159  if (len > 0)
161  else
162  {
163  result = NULL;
164  *nitems = 0;
165  }
166  }
167  else
168  {
170 
171  result = palloc((*nitems) * sizeof(ItemPointerData));
172  memcpy(result, tmp, (*nitems) * sizeof(ItemPointerData));
173  }
174 
175  return result;
176 }
ItemPointer ginPostingListDecodeAllSegments(GinPostingList *segment, int len, int *ndecoded_out)
const void size_t len

References dataLeafPageGetUncompressed(), ginCompareItemPointers(), GinDataLeafPageGetPostingList, GinDataLeafPageGetPostingListSize, GinNextPostingListSegment, GinPageIsCompressed, ginPostingListDecodeAllSegments(), ItemPointerIsValid(), len, next, nitems, and palloc().

Referenced by entryLoadMoreItems(), and startScanEntry().

◆ GinDataLeafPageGetItemsToTbm()

int GinDataLeafPageGetItemsToTbm ( Page  page,
TIDBitmap tbm 
)

Definition at line 182 of file gindatapage.c.

183 {
184  ItemPointer uncompressed;
185  int nitems;
186 
187  if (GinPageIsCompressed(page))
188  {
191 
193  }
194  else
195  {
196  uncompressed = dataLeafPageGetUncompressed(page, &nitems);
197 
198  if (nitems > 0)
199  tbm_add_tuples(tbm, uncompressed, nitems, false);
200  }
201 
202  return nitems;
203 }
int ginPostingListDecodeAllSegmentsToTbm(GinPostingList *ptr, int len, TIDBitmap *tbm)
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:377

References dataLeafPageGetUncompressed(), GinDataLeafPageGetPostingList, GinDataLeafPageGetPostingListSize, GinPageIsCompressed, ginPostingListDecodeAllSegmentsToTbm(), len, nitems, and tbm_add_tuples().

Referenced by scanPostingTree().

◆ GinDataPageAddPostingItem()

void GinDataPageAddPostingItem ( Page  page,
PostingItem data,
OffsetNumber  offset 
)

Definition at line 380 of file gindatapage.c.

381 {
382  OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
383  char *ptr;
384 
386  Assert(!GinPageIsLeaf(page));
387 
388  if (offset == InvalidOffsetNumber)
389  {
390  ptr = (char *) GinDataPageGetPostingItem(page, maxoff + 1);
391  }
392  else
393  {
394  ptr = (char *) GinDataPageGetPostingItem(page, offset);
395  if (offset != maxoff + 1)
396  memmove(ptr + sizeof(PostingItem),
397  ptr,
398  (maxoff - offset + 1) * sizeof(PostingItem));
399  }
400  memcpy(ptr, data, sizeof(PostingItem));
401 
402  maxoff++;
403  GinPageGetOpaque(page)->maxoff = maxoff;
404 
405  /*
406  * Also set pd_lower to the end of the posting items, to follow the
407  * "standard" page layout, so that we can squeeze out the unused space
408  * from full-page images.
409  */
410  GinDataPageSetDataSize(page, maxoff * sizeof(PostingItem));
411 }

References Assert(), data, GinDataPageGetPostingItem, GinDataPageSetDataSize, GinPageGetOpaque, GinPageIsLeaf, InvalidBlockNumber, InvalidOffsetNumber, and PostingItemGetBlockNumber.

Referenced by dataExecPlaceToPageInternal(), ginDataFillRoot(), and ginRedoInsertData().

◆ ginInsertItemPointers()

void ginInsertItemPointers ( Relation  index,
BlockNumber  rootBlkno,
ItemPointerData items,
uint32  nitem,
GinStatsData buildStats 
)

Definition at line 1908 of file gindatapage.c.

1911 {
1912  GinBtreeData btree;
1913  GinBtreeDataLeafInsertData insertdata;
1914  GinBtreeStack *stack;
1915 
1916  ginPrepareDataScan(&btree, index, rootBlkno);
1917  btree.isBuild = (buildStats != NULL);
1918  insertdata.items = items;
1919  insertdata.nitem = nitem;
1920  insertdata.curitem = 0;
1921 
1922  while (insertdata.curitem < insertdata.nitem)
1923  {
1924  /* search for the leaf page where the first item should go to */
1925  btree.itemptr = insertdata.items[insertdata.curitem];
1926  stack = ginFindLeafPage(&btree, false, true);
1927 
1928  ginInsertValue(&btree, stack, &insertdata, buildStats);
1929  }
1930 }
void ginInsertValue(GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
Definition: ginbtree.c:816
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, bool rootConflictCheck)
Definition: ginbtree.c:83
static void ginPrepareDataScan(GinBtree btree, Relation index, BlockNumber rootBlkno)
Definition: gindatapage.c:1882

References GinBtreeDataLeafInsertData::curitem, ginFindLeafPage(), ginInsertValue(), ginPrepareDataScan(), GinBtreeData::isBuild, GinBtreeData::itemptr, GinBtreeDataLeafInsertData::items, and GinBtreeDataLeafInsertData::nitem.

Referenced by addItemPointersToLeafTuple(), createPostingTree(), and ginEntryInsert().

◆ GinPageDeletePostingItem()

void GinPageDeletePostingItem ( Page  page,
OffsetNumber  offset 
)

Definition at line 417 of file gindatapage.c.

418 {
419  OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
420 
421  Assert(!GinPageIsLeaf(page));
422  Assert(offset >= FirstOffsetNumber && offset <= maxoff);
423 
424  if (offset != maxoff)
425  memmove(GinDataPageGetPostingItem(page, offset),
426  GinDataPageGetPostingItem(page, offset + 1),
427  sizeof(PostingItem) * (maxoff - offset));
428 
429  maxoff--;
430  GinPageGetOpaque(page)->maxoff = maxoff;
431 
432  GinDataPageSetDataSize(page, maxoff * sizeof(PostingItem));
433 }

References Assert(), FirstOffsetNumber, GinDataPageGetPostingItem, GinDataPageSetDataSize, GinPageGetOpaque, and GinPageIsLeaf.

Referenced by ginDeletePage(), and ginRedoDeletePage().

◆ ginPrepareDataScan()

static void ginPrepareDataScan ( GinBtree  btree,
Relation  index,
BlockNumber  rootBlkno 
)
static

Definition at line 1882 of file gindatapage.c.

1883 {
1884  memset(btree, 0, sizeof(GinBtreeData));
1885 
1886  btree->index = index;
1887  btree->rootBlkno = rootBlkno;
1888 
1889  btree->findChildPage = dataLocateItem;
1891  btree->isMoveRight = dataIsMoveRight;
1892  btree->findItem = NULL;
1893  btree->findChildPtr = dataFindChildPtr;
1896  btree->fillRoot = ginDataFillRoot;
1898 
1899  btree->isData = true;
1900  btree->fullScan = false;
1901  btree->isBuild = false;
1902 }
static OffsetNumber dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
Definition: gindatapage.c:319
static BlockNumber dataGetLeftMostPage(GinBtree btree, Page page)
Definition: gindatapage.c:364
static void * dataPrepareDownlink(GinBtree btree, Buffer lbuf)
Definition: gindatapage.c:1333
static GinPlaceToPageRC dataBeginPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, void **ptp_workspace, Page *newlpage, Page *newrpage)
Definition: gindatapage.c:1201
static void dataExecPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, void *ptp_workspace)
Definition: gindatapage.c:1231
static bool dataIsMoveRight(GinBtree btree, Page page)
Definition: gindatapage.c:234
static BlockNumber dataLocateItem(GinBtree btree, GinBtreeStack *stack)
Definition: gindatapage.c:252
void ginDataFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
Definition: gindatapage.c:1349
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:153
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
Definition: gin_private.h:161
bool(* findItem)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:156
bool(* isMoveRight)(GinBtree, Page)
Definition: gin_private.h:155
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
Definition: gin_private.h:160
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:162
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:159
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
Definition: gin_private.h:163
BlockNumber rootBlkno
Definition: gin_private.h:168

References GinBtreeData::beginPlaceToPage, dataBeginPlaceToPage(), dataExecPlaceToPage(), dataFindChildPtr(), dataGetLeftMostPage(), dataIsMoveRight(), dataLocateItem(), dataPrepareDownlink(), GinBtreeData::execPlaceToPage, GinBtreeData::fillRoot, GinBtreeData::findChildPage, GinBtreeData::findChildPtr, GinBtreeData::findItem, GinBtreeData::fullScan, GinBtreeData::getLeftMostChild, ginDataFillRoot(), GinBtreeData::index, GinBtreeData::isBuild, GinBtreeData::isData, GinBtreeData::isMoveRight, GinBtreeData::prepareDownlink, and GinBtreeData::rootBlkno.

Referenced by ginInsertItemPointers(), and ginScanBeginPostingTree().

◆ ginScanBeginPostingTree()

GinBtreeStack* ginScanBeginPostingTree ( GinBtree  btree,
Relation  index,
BlockNumber  rootBlkno 
)

Definition at line 1936 of file gindatapage.c.

1937 {
1938  GinBtreeStack *stack;
1939 
1940  ginPrepareDataScan(btree, index, rootBlkno);
1941 
1942  btree->fullScan = true;
1943 
1944  stack = ginFindLeafPage(btree, true, false);
1945 
1946  return stack;
1947 }

References GinBtreeData::fullScan, ginFindLeafPage(), and ginPrepareDataScan().

Referenced by scanPostingTree(), and startScanEntry().

◆ ginVacuumPostingTreeLeaf()

void ginVacuumPostingTreeLeaf ( Relation  indexrel,
Buffer  buffer,
GinVacuumState gvs 
)

Definition at line 738 of file gindatapage.c.

739 {
740  Page page = BufferGetPage(buffer);
741  disassembledLeaf *leaf;
742  bool removedsomething = false;
743  dlist_iter iter;
744 
745  leaf = disassembleLeaf(page);
746 
747  /* Vacuum each segment. */
748  dlist_foreach(iter, &leaf->segments)
749  {
750  leafSegmentInfo *seginfo = dlist_container(leafSegmentInfo, node, iter.cur);
751  int oldsegsize;
752  ItemPointer cleaned;
753  int ncleaned;
754 
755  if (!seginfo->items)
756  seginfo->items = ginPostingListDecode(seginfo->seg,
757  &seginfo->nitems);
758  if (seginfo->seg)
759  oldsegsize = SizeOfGinPostingList(seginfo->seg);
760  else
761  oldsegsize = GinDataPageMaxDataSize;
762 
763  cleaned = ginVacuumItemPointers(gvs,
764  seginfo->items,
765  seginfo->nitems,
766  &ncleaned);
767  pfree(seginfo->items);
768  seginfo->items = NULL;
769  seginfo->nitems = 0;
770  if (cleaned)
771  {
772  if (ncleaned > 0)
773  {
774  int npacked;
775 
776  seginfo->seg = ginCompressPostingList(cleaned,
777  ncleaned,
778  oldsegsize,
779  &npacked);
780  /* Removing an item never increases the size of the segment */
781  if (npacked != ncleaned)
782  elog(ERROR, "could not fit vacuumed posting list");
783  seginfo->action = GIN_SEGMENT_REPLACE;
784  }
785  else
786  {
787  seginfo->seg = NULL;
788  seginfo->items = NULL;
789  seginfo->action = GIN_SEGMENT_DELETE;
790  }
791  seginfo->nitems = ncleaned;
792 
793  removedsomething = true;
794  }
795  }
796 
797  /*
798  * If we removed any items, reconstruct the page from the pieces.
799  *
800  * We don't try to re-encode the segments here, even though some of them
801  * might be really small now that we've removed some items from them. It
802  * seems like a waste of effort, as there isn't really any benefit from
803  * larger segments per se; larger segments only help to pack more items in
804  * the same space. We might as well delay doing that until the next
805  * insertion, which will need to re-encode at least part of the page
806  * anyway.
807  *
808  * Also note if the page was in uncompressed, pre-9.4 format before, it is
809  * now represented as one huge segment that contains all the items. It
810  * might make sense to split that, to speed up random access, but we don't
811  * bother. You'll have to REINDEX anyway if you want the full gain of the
812  * new tighter index format.
813  */
814  if (removedsomething)
815  {
816  bool modified;
817 
818  /*
819  * Make sure we have a palloc'd copy of all segments, after the first
820  * segment that is modified. (dataPlaceToPageLeafRecompress requires
821  * this).
822  */
823  modified = false;
824  dlist_foreach(iter, &leaf->segments)
825  {
827  iter.cur);
828 
829  if (seginfo->action != GIN_SEGMENT_UNMODIFIED)
830  modified = true;
831  if (modified && seginfo->action != GIN_SEGMENT_DELETE)
832  {
833  int segsize = SizeOfGinPostingList(seginfo->seg);
834  GinPostingList *tmp = (GinPostingList *) palloc(segsize);
835 
836  memcpy(tmp, seginfo->seg, segsize);
837  seginfo->seg = tmp;
838  }
839  }
840 
841  if (RelationNeedsWAL(indexrel))
843 
844  /* Apply changes to page */
846 
847  dataPlaceToPageLeafRecompress(buffer, leaf);
848 
849  MarkBufferDirty(buffer);
850 
851  if (RelationNeedsWAL(indexrel))
852  {
853  XLogRecPtr recptr;
854 
855  XLogBeginInsert();
857  XLogRegisterBufData(0, leaf->walinfo, leaf->walinfolen);
858  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_VACUUM_DATA_LEAF_PAGE);
859  PageSetLSN(page, recptr);
860  }
861 
863  }
864 }
ItemPointer ginVacuumItemPointers(GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining)
Definition: ginvacuum.c:48
#define XLOG_GIN_VACUUM_DATA_LEAF_PAGE
Definition: ginxlog.h:141

References leafSegmentInfo::action, BufferGetPage(), computeLeafRecompressWALData(), dlist_iter::cur, dataPlaceToPageLeafRecompress(), disassembleLeaf(), dlist_container, dlist_foreach, elog(), END_CRIT_SECTION, ERROR, GIN_SEGMENT_DELETE, GIN_SEGMENT_REPLACE, GIN_SEGMENT_UNMODIFIED, ginCompressPostingList(), GinDataPageMaxDataSize, ginPostingListDecode(), ginVacuumItemPointers(), leafSegmentInfo::items, MarkBufferDirty(), leafSegmentInfo::nitems, PageSetLSN(), palloc(), pfree(), REGBUF_STANDARD, RelationNeedsWAL, leafSegmentInfo::seg, disassembledLeaf::segments, SizeOfGinPostingList, START_CRIT_SECTION, disassembledLeaf::walinfo, disassembledLeaf::walinfolen, XLOG_GIN_VACUUM_DATA_LEAF_PAGE, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), and XLogRegisterBuffer().

Referenced by ginVacuumPostingTreeLeaves().

◆ leafRepackItems()

static bool leafRepackItems ( disassembledLeaf leaf,
ItemPointer  remaining 
)
static

Definition at line 1571 of file gindatapage.c.

1572 {
1573  int pgused = 0;
1574  bool needsplit = false;
1575  dlist_iter iter;
1576  int segsize;
1577  leafSegmentInfo *nextseg;
1578  int npacked;
1579  bool modified;
1580  dlist_node *cur_node;
1581  dlist_node *next_node;
1582 
1584 
1585  /*
1586  * cannot use dlist_foreach_modify here because we insert adjacent items
1587  * while iterating.
1588  */
1589  for (cur_node = dlist_head_node(&leaf->segments);
1590  cur_node != NULL;
1591  cur_node = next_node)
1592  {
1594  cur_node);
1595 
1596  if (dlist_has_next(&leaf->segments, cur_node))
1597  next_node = dlist_next_node(&leaf->segments, cur_node);
1598  else
1599  next_node = NULL;
1600 
1601  /* Compress the posting list, if necessary */
1602  if (seginfo->action != GIN_SEGMENT_DELETE)
1603  {
1604  if (seginfo->seg == NULL)
1605  {
1606  if (seginfo->nitems > GinPostingListSegmentMaxSize)
1607  npacked = 0; /* no chance that it would fit. */
1608  else
1609  {
1610  seginfo->seg = ginCompressPostingList(seginfo->items,
1611  seginfo->nitems,
1613  &npacked);
1614  }
1615  if (npacked != seginfo->nitems)
1616  {
1617  /*
1618  * Too large. Compress again to the target size, and
1619  * create a new segment to represent the remaining items.
1620  * The new segment is inserted after this one, so it will
1621  * be processed in the next iteration of this loop.
1622  */
1623  if (seginfo->seg)
1624  pfree(seginfo->seg);
1625  seginfo->seg = ginCompressPostingList(seginfo->items,
1626  seginfo->nitems,
1628  &npacked);
1629  if (seginfo->action != GIN_SEGMENT_INSERT)
1630  seginfo->action = GIN_SEGMENT_REPLACE;
1631 
1632  nextseg = palloc(sizeof(leafSegmentInfo));
1633  nextseg->action = GIN_SEGMENT_INSERT;
1634  nextseg->seg = NULL;
1635  nextseg->items = &seginfo->items[npacked];
1636  nextseg->nitems = seginfo->nitems - npacked;
1637  next_node = &nextseg->node;
1638  dlist_insert_after(cur_node, next_node);
1639  }
1640  }
1641 
1642  /*
1643  * If the segment is very small, merge it with the next segment.
1644  */
1645  if (SizeOfGinPostingList(seginfo->seg) < GinPostingListSegmentMinSize && next_node)
1646  {
1647  int nmerged;
1648 
1649  nextseg = dlist_container(leafSegmentInfo, node, next_node);
1650 
1651  if (seginfo->items == NULL)
1652  seginfo->items = ginPostingListDecode(seginfo->seg,
1653  &seginfo->nitems);
1654  if (nextseg->items == NULL)
1655  nextseg->items = ginPostingListDecode(nextseg->seg,
1656  &nextseg->nitems);
1657  nextseg->items =
1658  ginMergeItemPointers(seginfo->items, seginfo->nitems,
1659  nextseg->items, nextseg->nitems,
1660  &nmerged);
1661  Assert(nmerged == seginfo->nitems + nextseg->nitems);
1662  nextseg->nitems = nmerged;
1663  nextseg->seg = NULL;
1664 
1665  nextseg->action = GIN_SEGMENT_REPLACE;
1666  nextseg->modifieditems = NULL;
1667  nextseg->nmodifieditems = 0;
1668 
1669  if (seginfo->action == GIN_SEGMENT_INSERT)
1670  {
1671  dlist_delete(cur_node);
1672  continue;
1673  }
1674  else
1675  {
1676  seginfo->action = GIN_SEGMENT_DELETE;
1677  seginfo->seg = NULL;
1678  }
1679  }
1680 
1681  seginfo->items = NULL;
1682  seginfo->nitems = 0;
1683  }
1684 
1685  if (seginfo->action == GIN_SEGMENT_DELETE)
1686  continue;
1687 
1688  /*
1689  * OK, we now have a compressed version of this segment ready for
1690  * copying to the page. Did we exceed the size that fits on one page?
1691  */
1692  segsize = SizeOfGinPostingList(seginfo->seg);
1693  if (pgused + segsize > GinDataPageMaxDataSize)
1694  {
1695  if (!needsplit)
1696  {
1697  /* switch to right page */
1698  Assert(pgused > 0);
1699  leaf->lastleft = dlist_prev_node(&leaf->segments, cur_node);
1700  needsplit = true;
1701  leaf->lsize = pgused;
1702  pgused = 0;
1703  }
1704  else
1705  {
1706  /*
1707  * Filled both pages. The last segment we constructed did not
1708  * fit.
1709  */
1710  *remaining = seginfo->seg->first;
1711 
1712  /*
1713  * remove all segments that did not fit from the list.
1714  */
1715  while (dlist_has_next(&leaf->segments, cur_node))
1716  dlist_delete(dlist_next_node(&leaf->segments, cur_node));
1717  dlist_delete(cur_node);
1718  break;
1719  }
1720  }
1721 
1722  pgused += segsize;
1723  }
1724 
1725  if (!needsplit)
1726  {
1727  leaf->lsize = pgused;
1728  leaf->rsize = 0;
1729  }
1730  else
1731  leaf->rsize = pgused;
1732 
1735 
1736  /*
1737  * Make a palloc'd copy of every segment after the first modified one,
1738  * because as we start copying items to the original page, we might
1739  * overwrite an existing segment.
1740  */
1741  modified = false;
1742  dlist_foreach(iter, &leaf->segments)
1743  {
1745  iter.cur);
1746 
1747  if (!modified && seginfo->action != GIN_SEGMENT_UNMODIFIED)
1748  {
1749  modified = true;
1750  }
1751  else if (modified && seginfo->action == GIN_SEGMENT_UNMODIFIED)
1752  {
1753  GinPostingList *tmp;
1754 
1755  segsize = SizeOfGinPostingList(seginfo->seg);
1756  tmp = palloc(segsize);
1757  memcpy(tmp, seginfo->seg, segsize);
1758  seginfo->seg = tmp;
1759  }
1760  }
1761 
1762  return needsplit;
1763 }
#define GinPostingListSegmentMinSize
Definition: gindatapage.c:36
static void dlist_insert_after(dlist_node *after, dlist_node *node)
Definition: ilist.h:381
static void dlist_delete(dlist_node *node)
Definition: ilist.h:405
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition: itemptr.h:184
ItemPointerData first
Definition: ginblock.h:337

References leafSegmentInfo::action, Assert(), dlist_iter::cur, dlist_container, dlist_delete(), dlist_foreach, dlist_has_next(), dlist_head_node(), dlist_insert_after(), dlist_next_node(), dlist_prev_node(), GinPostingList::first, GIN_SEGMENT_DELETE, GIN_SEGMENT_INSERT, GIN_SEGMENT_REPLACE, GIN_SEGMENT_UNMODIFIED, ginCompressPostingList(), GinDataPageMaxDataSize, ginMergeItemPointers(), ginPostingListDecode(), GinPostingListSegmentMaxSize, GinPostingListSegmentMinSize, GinPostingListSegmentTargetSize, ItemPointerSetInvalid(), leafSegmentInfo::items, disassembledLeaf::lastleft, disassembledLeaf::lsize, leafSegmentInfo::modifieditems, leafSegmentInfo::nitems, leafSegmentInfo::nmodifieditems, leafSegmentInfo::node, palloc(), pfree(), remaining, disassembledLeaf::rsize, leafSegmentInfo::seg, disassembledLeaf::segments, and SizeOfGinPostingList.

Referenced by dataBeginPlaceToPageLeaf().