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, Snapshot snapshot)
 

Macro Definition Documentation

◆ GinPostingListSegmentMaxSize

#define GinPostingListSegmentMaxSize   384

Definition at line 34 of file gindatapage.c.

Referenced by createPostingTree(), dataBeginPlaceToPageLeaf(), and leafRepackItems().

◆ GinPostingListSegmentMinSize

#define GinPostingListSegmentMinSize   128

Definition at line 36 of file gindatapage.c.

Referenced by leafRepackItems().

◆ GinPostingListSegmentTargetSize

#define GinPostingListSegmentTargetSize   256

Definition at line 35 of file gindatapage.c.

Referenced by addItemsToLeaf(), and leafRepackItems().

◆ MinTuplesPerSegment

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

Definition at line 43 of file gindatapage.c.

Referenced by dataBeginPlaceToPageLeaf().

Function Documentation

◆ addItemsToLeaf()

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

Definition at line 1435 of file gindatapage.c.

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

Referenced by dataBeginPlaceToPageLeaf().

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

◆ computeLeafRecompressWALData()

static void computeLeafRecompressWALData ( disassembledLeaf leaf)
static

Definition at line 866 of file gindatapage.c.

References leafSegmentInfo::action, generate_unaccent_rules::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().

867 {
868  int nmodified = 0;
869  char *walbufbegin;
870  char *walbufend;
871  dlist_iter iter;
872  int segno;
873  ginxlogRecompressDataLeaf *recompress_xlog;
874 
875  /* Count the modified segments */
876  dlist_foreach(iter, &leaf->segments)
877  {
879  iter.cur);
880 
881  if (seginfo->action != GIN_SEGMENT_UNMODIFIED)
882  nmodified++;
883  }
884 
885  walbufbegin =
887  BLCKSZ + /* max size needed to hold the segment data */
888  nmodified * 2 /* (segno + action) per action */
889  );
890  walbufend = walbufbegin;
891 
892  recompress_xlog = (ginxlogRecompressDataLeaf *) walbufend;
893  walbufend += sizeof(ginxlogRecompressDataLeaf);
894 
895  recompress_xlog->nactions = nmodified;
896 
897  segno = 0;
898  dlist_foreach(iter, &leaf->segments)
899  {
901  iter.cur);
902  int segsize = 0;
903  int datalen;
904  uint8 action = seginfo->action;
905 
906  if (action == GIN_SEGMENT_UNMODIFIED)
907  {
908  segno++;
909  continue;
910  }
911 
912  if (action != GIN_SEGMENT_DELETE)
913  segsize = SizeOfGinPostingList(seginfo->seg);
914 
915  /*
916  * If storing the uncompressed list of added item pointers would take
917  * more space than storing the compressed segment as is, do that
918  * instead.
919  */
920  if (action == GIN_SEGMENT_ADDITEMS &&
921  seginfo->nmodifieditems * sizeof(ItemPointerData) > segsize)
922  {
923  action = GIN_SEGMENT_REPLACE;
924  }
925 
926  *((uint8 *) (walbufend++)) = segno;
927  *(walbufend++) = action;
928 
929  switch (action)
930  {
931  case GIN_SEGMENT_DELETE:
932  datalen = 0;
933  break;
934 
936  datalen = seginfo->nmodifieditems * sizeof(ItemPointerData);
937  memcpy(walbufend, &seginfo->nmodifieditems, sizeof(uint16));
938  memcpy(walbufend + sizeof(uint16), seginfo->modifieditems, datalen);
939  datalen += sizeof(uint16);
940  break;
941 
942  case GIN_SEGMENT_INSERT:
943  case GIN_SEGMENT_REPLACE:
944  datalen = SHORTALIGN(segsize);
945  memcpy(walbufend, seginfo->seg, segsize);
946  break;
947 
948  default:
949  elog(ERROR, "unexpected GIN leaf action %d", action);
950  }
951  walbufend += datalen;
952 
953  if (action != GIN_SEGMENT_INSERT)
954  segno++;
955  }
956 
957  /* Pass back the constructed info via *leaf */
958  leaf->walinfo = walbufbegin;
959  leaf->walinfolen = walbufend - walbufbegin;
960 }
GinPostingList * seg
Definition: gindatapage.c:100
#define dlist_foreach(iter, lhead)
Definition: ilist.h:507
unsigned char uint8
Definition: c.h:356
#define GIN_SEGMENT_INSERT
Definition: ginxlog.h:93
dlist_head segments
Definition: gindatapage.c:50
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
unsigned short uint16
Definition: c.h:357
#define GIN_SEGMENT_REPLACE
Definition: ginxlog.h:94
#define ERROR
Definition: elog.h:43
ItemPointerData * modifieditems
Definition: gindatapage.c:90
#define GIN_SEGMENT_ADDITEMS
Definition: ginxlog.h:95
#define GIN_SEGMENT_DELETE
Definition: ginxlog.h:92
dlist_node * cur
Definition: ilist.h:161
struct ItemPointerData ItemPointerData
void * palloc(Size size)
Definition: mcxt.c:924
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:343
#define elog(elevel,...)
Definition: elog.h:226
#define GIN_SEGMENT_UNMODIFIED
Definition: ginxlog.h:91
#define SHORTALIGN(LEN)
Definition: c.h:681
uint16 nmodifieditems
Definition: gindatapage.c:91

◆ createPostingTree()

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

Definition at line 1766 of file gindatapage.c.

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

Referenced by addItemPointersToLeafTuple(), and buildFreshLeafTuple().

1768 {
1769  BlockNumber blkno;
1770  Buffer buffer;
1771  Page tmppage;
1772  Page page;
1773  Pointer ptr;
1774  int nrootitems;
1775  int rootsize;
1776  bool is_build = (buildStats != NULL);
1777 
1778  /* Construct the new root page in memory first. */
1779  tmppage = (Page) palloc(BLCKSZ);
1780  GinInitPage(tmppage, GIN_DATA | GIN_LEAF | GIN_COMPRESSED, BLCKSZ);
1781  GinPageGetOpaque(tmppage)->rightlink = InvalidBlockNumber;
1782 
1783  /*
1784  * Write as many of the items to the root page as fit. In segments of max
1785  * GinPostingListSegmentMaxSize bytes each.
1786  */
1787  nrootitems = 0;
1788  rootsize = 0;
1789  ptr = (Pointer) GinDataLeafPageGetPostingList(tmppage);
1790  while (nrootitems < nitems)
1791  {
1792  GinPostingList *segment;
1793  int npacked;
1794  int segsize;
1795 
1796  segment = ginCompressPostingList(&items[nrootitems],
1797  nitems - nrootitems,
1799  &npacked);
1800  segsize = SizeOfGinPostingList(segment);
1801  if (rootsize + segsize > GinDataPageMaxDataSize)
1802  break;
1803 
1804  memcpy(ptr, segment, segsize);
1805  ptr += segsize;
1806  rootsize += segsize;
1807  nrootitems += npacked;
1808  pfree(segment);
1809  }
1810  GinDataPageSetDataSize(tmppage, rootsize);
1811 
1812  /*
1813  * All set. Get a new physical page, and copy the in-memory page to it.
1814  */
1815  buffer = GinNewBuffer(index);
1816  page = BufferGetPage(buffer);
1817  blkno = BufferGetBlockNumber(buffer);
1818 
1819  /*
1820  * Copy any predicate locks from the entry tree leaf (containing posting
1821  * list) to the posting tree.
1822  */
1823  PredicateLockPageSplit(index, BufferGetBlockNumber(entrybuffer), blkno);
1824 
1826 
1827  PageRestoreTempPage(tmppage, page);
1828  MarkBufferDirty(buffer);
1829 
1830  if (RelationNeedsWAL(index) && !is_build)
1831  {
1832  XLogRecPtr recptr;
1834 
1835  data.size = rootsize;
1836 
1837  XLogBeginInsert();
1838  XLogRegisterData((char *) &data, sizeof(ginxlogCreatePostingTree));
1839 
1841  rootsize);
1843 
1844  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_PTREE);
1845  PageSetLSN(page, recptr);
1846  }
1847 
1848  UnlockReleaseBuffer(buffer);
1849 
1850  END_CRIT_SECTION();
1851 
1852  /* During index build, count the newly-added data page */
1853  if (buildStats)
1854  buildStats->nDataPages++;
1855 
1856  elog(DEBUG2, "created GIN posting tree with %d items", nrootitems);
1857 
1858  /*
1859  * Add any remaining TIDs to the newly-created posting tree.
1860  */
1861  if (nitems > nrootitems)
1862  {
1863  ginInsertItemPointers(index, blkno,
1864  items + nrootitems,
1865  nitems - nrootitems,
1866  buildStats);
1867  }
1868 
1869  return blkno;
1870 }
GinPostingList * ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:292
#define GinPostingListSegmentMaxSize
Definition: gindatapage.c:34
void ginInsertItemPointers(Relation index, BlockNumber rootBlkno, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gindatapage.c:1899
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:410
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:338
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
#define REGBUF_WILL_INIT
Definition: xloginsert.h:33
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
#define GIN_COMPRESSED
Definition: ginblock.h:48
#define GIN_DATA
Definition: ginblock.h:40
#define GinDataPageSetDataSize(page, size)
Definition: ginblock.h:310
void pfree(void *pointer)
Definition: mcxt.c:1031
char * Pointer
Definition: c.h:335
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3376
#define XLOG_GIN_CREATE_PTREE
Definition: ginxlog.h:19
#define DEBUG2
Definition: elog.h:24
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:279
BlockNumber nDataPages
Definition: gin.h:46
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define InvalidBlockNumber
Definition: block.h:33
#define RelationNeedsWAL(relation)
Definition: rel.h:518
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2613
#define GinDataPageMaxDataSize
Definition: ginblock.h:320
void * palloc(Size size)
Definition: mcxt.c:924
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:343
#define elog(elevel,...)
Definition: elog.h:226
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3118
Pointer Page
Definition: bufpage.h:78
#define GIN_LEAF
Definition: ginblock.h:41

◆ 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 1192 of file gindatapage.c.

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

Referenced by ginPrepareDataScan().

1196 {
1197  Page page = BufferGetPage(buf);
1198 
1199  Assert(GinPageIsData(page));
1200 
1201  if (GinPageIsLeaf(page))
1202  return dataBeginPlaceToPageLeaf(btree, buf, stack, insertdata,
1203  ptp_workspace,
1204  newlpage, newrpage);
1205  else
1206  return dataBeginPlaceToPageInternal(btree, buf, stack,
1207  insertdata, updateblkno,
1208  ptp_workspace,
1209  newlpage, newrpage);
1210 }
static GinPlaceToPageRC dataBeginPlaceToPageInternal(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, void **ptp_workspace, Page *newlpage, Page *newrpage)
Definition: gindatapage.c:1113
static char * buf
Definition: pg_test_fsync.c:68
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
static GinPlaceToPageRC dataBeginPlaceToPageLeaf(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, void **ptp_workspace, Page *newlpage, Page *newrpage)
Definition: gindatapage.c:445
#define GinPageIsData(page)
Definition: ginblock.h:115
#define Assert(condition)
Definition: c.h:732
Pointer Page
Definition: bufpage.h:78

◆ 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 1113 of file gindatapage.c.

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

Referenced by dataBeginPlaceToPage().

1117 {
1118  Page page = BufferGetPage(buf);
1119 
1120  /* If it doesn't fit, deal with split case */
1121  if (GinNonLeafDataPageGetFreeSpace(page) < sizeof(PostingItem))
1122  {
1123  dataSplitPageInternal(btree, buf, stack, insertdata, updateblkno,
1124  newlpage, newrpage);
1125  return GPTP_SPLIT;
1126  }
1127 
1128  /* Else, we're ready to proceed with insertion */
1129  return GPTP_INSERT;
1130 }
static void dataSplitPageInternal(GinBtree btree, Buffer origbuf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, Page *newlpage, Page *newrpage)
Definition: gindatapage.c:1243
static char * buf
Definition: pg_test_fsync.c:68
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define GinNonLeafDataPageGetFreeSpace(page)
Definition: ginblock.h:316
Pointer Page
Definition: bufpage.h:78

◆ dataBeginPlaceToPageLeaf()

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

Definition at line 445 of file gindatapage.c.

References leafSegmentInfo::action, addItemsToLeaf(), Assert, 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().

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

◆ dataExecPlaceToPage()

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

Definition at line 1222 of file gindatapage.c.

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

Referenced by ginPrepareDataScan().

1225 {
1226  Page page = BufferGetPage(buf);
1227 
1228  if (GinPageIsLeaf(page))
1229  dataExecPlaceToPageLeaf(btree, buf, stack, insertdata,
1230  ptp_workspace);
1231  else
1232  dataExecPlaceToPageInternal(btree, buf, stack, insertdata,
1233  updateblkno, ptp_workspace);
1234 }
static void dataExecPlaceToPageInternal(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, void *ptp_workspace)
Definition: gindatapage.c:1139
static void dataExecPlaceToPageLeaf(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, void *ptp_workspace)
Definition: gindatapage.c:713
static char * buf
Definition: pg_test_fsync.c:68
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
Pointer Page
Definition: bufpage.h:78

◆ dataExecPlaceToPageInternal()

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

Definition at line 1139 of file gindatapage.c.

References BufferGetPage, GinDataPageAddPostingItem(), GinDataPageGetPostingItem, GinBtreeData::index, GinBtreeData::isBuild, ginxlogInsertDataInternal::newitem, GinBtreeStack::off, ginxlogInsertDataInternal::offset, PostingItemSetBlockNumber, RelationNeedsWAL, and XLogRegisterBufData().

Referenced by dataExecPlaceToPage().

1142 {
1143  Page page = BufferGetPage(buf);
1144  OffsetNumber off = stack->off;
1145  PostingItem *pitem;
1146 
1147  /* Update existing downlink to point to next page (on internal page) */
1148  pitem = GinDataPageGetPostingItem(page, off);
1149  PostingItemSetBlockNumber(pitem, updateblkno);
1150 
1151  /* Add new item */
1152  pitem = (PostingItem *) insertdata;
1153  GinDataPageAddPostingItem(page, pitem, off);
1154 
1155  if (RelationNeedsWAL(btree->index) && !btree->isBuild)
1156  {
1157  /*
1158  * This must be static, because it has to survive until XLogInsert,
1159  * and we can't palloc here. Ugly, but the XLogInsert infrastructure
1160  * isn't reentrant anyway.
1161  */
1162  static ginxlogInsertDataInternal data;
1163 
1164  data.offset = off;
1165  data.newitem = *pitem;
1166 
1167  XLogRegisterBufData(0, (char *) &data,
1168  sizeof(ginxlogInsertDataInternal));
1169  }
1170 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
#define PostingItemSetBlockNumber(pointer, blockNumber)
Definition: ginblock.h:193
OffsetNumber off
Definition: gin_private.h:126
OffsetNumber offset
Definition: ginxlog.h:99
uint16 OffsetNumber
Definition: off.h:24
void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset)
Definition: gindatapage.c:377
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:299
static char * buf
Definition: pg_test_fsync.c:68
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
Relation index
Definition: gin_private.h:160
#define RelationNeedsWAL(relation)
Definition: rel.h:518
Pointer Page
Definition: bufpage.h:78

◆ dataExecPlaceToPageLeaf()

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

Definition at line 713 of file gindatapage.c.

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

Referenced by dataExecPlaceToPage().

715 {
716  disassembledLeaf *leaf = (disassembledLeaf *) ptp_workspace;
717 
718  /* Apply changes to page */
720 
721  /* If needed, register WAL data built by computeLeafRecompressWALData */
722  if (RelationNeedsWAL(btree->index) && !btree->isBuild)
723  {
724  XLogRegisterBufData(0, leaf->walinfo, leaf->walinfolen);
725  }
726 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
static char * buf
Definition: pg_test_fsync.c:68
static void dataPlaceToPageLeafRecompress(Buffer buf, disassembledLeaf *leaf)
Definition: gindatapage.c:972
Relation index
Definition: gin_private.h:160
#define RelationNeedsWAL(relation)
Definition: rel.h:518

◆ dataFindChildPtr()

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

Definition at line 316 of file gindatapage.c.

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

Referenced by ginPrepareDataScan().

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

◆ dataGetLeftMostPage()

static BlockNumber dataGetLeftMostPage ( GinBtree  btree,
Page  page 
)
static

Definition at line 361 of file gindatapage.c.

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

Referenced by ginPrepareDataScan().

362 {
363  PostingItem *pitem;
364 
365  Assert(!GinPageIsLeaf(page));
366  Assert(GinPageIsData(page));
367  Assert(GinPageGetOpaque(page)->maxoff >= FirstOffsetNumber);
368 
370  return PostingItemGetBlockNumber(pitem);
371 }
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:299
#define FirstOffsetNumber
Definition: off.h:27
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
#define GinPageIsData(page)
Definition: ginblock.h:115
#define PostingItemGetBlockNumber(pointer)
Definition: ginblock.h:190
#define Assert(condition)
Definition: c.h:732

◆ dataIsMoveRight()

static bool dataIsMoveRight ( GinBtree  btree,
Page  page 
)
static

Definition at line 234 of file gindatapage.c.

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

Referenced by ginPrepareDataScan().

235 {
237 
238  if (GinPageRightMost(page))
239  return false;
240 
241  return (ginCompareItemPointers(&btree->itemptr, iptr) > 0) ? true : false;
242 }
#define true
Definition: c.h:312
#define GinPageRightMost(page)
Definition: ginblock.h:129
static int ginCompareItemPointers(ItemPointer a, ItemPointer b)
Definition: gin_private.h:461
#define GinDataPageGetRightBound(page)
Definition: ginblock.h:289
ItemPointerData itemptr
Definition: gin_private.h:172

◆ dataLeafPageGetUncompressed()

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

Definition at line 211 of file gindatapage.c.

References Assert, GinDataPageGetData, GinPageGetOpaque, and GinPageIsCompressed.

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

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:296
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
#define GinPageIsCompressed(page)
Definition: ginblock.h:121
ItemPointerData * ItemPointer
Definition: itemptr.h:49
#define Assert(condition)
Definition: c.h:732

◆ dataLocateItem()

static BlockNumber dataLocateItem ( GinBtree  btree,
GinBtreeStack stack 
)
static

Definition at line 249 of file gindatapage.c.

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().

250 {
251  OffsetNumber low,
252  high,
253  maxoff;
254  PostingItem *pitem = NULL;
255  int result;
256  Page page = BufferGetPage(stack->buffer);
257 
258  Assert(!GinPageIsLeaf(page));
259  Assert(GinPageIsData(page));
260 
261  if (btree->fullScan)
262  {
263  stack->off = FirstOffsetNumber;
264  stack->predictNumber *= GinPageGetOpaque(page)->maxoff;
265  return btree->getLeftMostChild(btree, page);
266  }
267 
268  low = FirstOffsetNumber;
269  maxoff = high = GinPageGetOpaque(page)->maxoff;
270  Assert(high >= low);
271 
272  high++;
273 
274  while (high > low)
275  {
276  OffsetNumber mid = low + ((high - low) / 2);
277 
278  pitem = GinDataPageGetPostingItem(page, mid);
279 
280  if (mid == maxoff)
281  {
282  /*
283  * Right infinity, page already correctly chosen with a help of
284  * dataIsMoveRight
285  */
286  result = -1;
287  }
288  else
289  {
290  pitem = GinDataPageGetPostingItem(page, mid);
291  result = ginCompareItemPointers(&btree->itemptr, &(pitem->key));
292  }
293 
294  if (result == 0)
295  {
296  stack->off = mid;
297  return PostingItemGetBlockNumber(pitem);
298  }
299  else if (result > 0)
300  low = mid + 1;
301  else
302  high = mid;
303  }
304 
305  Assert(high >= FirstOffsetNumber && high <= maxoff);
306 
307  stack->off = high;
308  pitem = GinDataPageGetPostingItem(page, high);
309  return PostingItemGetBlockNumber(pitem);
310 }
OffsetNumber off
Definition: gin_private.h:126
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
uint16 OffsetNumber
Definition: off.h:24
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:299
#define FirstOffsetNumber
Definition: off.h:27
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:147
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
ItemPointerData key
Definition: ginblock.h:187
#define GinPageIsData(page)
Definition: ginblock.h:115
#define PostingItemGetBlockNumber(pointer)
Definition: ginblock.h:190
#define Assert(condition)
Definition: c.h:732
static int ginCompareItemPointers(ItemPointer a, ItemPointer b)
Definition: gin_private.h:461
uint32 predictNumber
Definition: gin_private.h:129
ItemPointerData itemptr
Definition: gin_private.h:172
Pointer Page
Definition: bufpage.h:78

◆ dataPlaceToPageLeafRecompress()

static void dataPlaceToPageLeafRecompress ( Buffer  buf,
disassembledLeaf leaf 
)
static

Definition at line 972 of file gindatapage.c.

References leafSegmentInfo::action, Assert, 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().

973 {
974  Page page = BufferGetPage(buf);
975  char *ptr;
976  int newsize;
977  bool modified = false;
978  dlist_iter iter;
979  int segsize;
980 
981  /*
982  * If the page was in pre-9.4 format before, convert the header, and force
983  * all segments to be copied to the page whether they were modified or
984  * not.
985  */
986  if (!GinPageIsCompressed(page))
987  {
988  Assert(leaf->oldformat);
989  GinPageSetCompressed(page);
990  GinPageGetOpaque(page)->maxoff = InvalidOffsetNumber;
991  modified = true;
992  }
993 
994  ptr = (char *) GinDataLeafPageGetPostingList(page);
995  newsize = 0;
996  dlist_foreach(iter, &leaf->segments)
997  {
998  leafSegmentInfo *seginfo = dlist_container(leafSegmentInfo, node, iter.cur);
999 
1000  if (seginfo->action != GIN_SEGMENT_UNMODIFIED)
1001  modified = true;
1002 
1003  if (seginfo->action != GIN_SEGMENT_DELETE)
1004  {
1005  segsize = SizeOfGinPostingList(seginfo->seg);
1006 
1007  if (modified)
1008  memcpy(ptr, seginfo->seg, segsize);
1009 
1010  ptr += segsize;
1011  newsize += segsize;
1012  }
1013  }
1014 
1015  Assert(newsize <= GinDataPageMaxDataSize);
1016  GinDataPageSetDataSize(page, newsize);
1017 }
GinPostingList * seg
Definition: gindatapage.c:100
#define dlist_foreach(iter, lhead)
Definition: ilist.h:507
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
#define GinPageIsCompressed(page)
Definition: ginblock.h:121
dlist_head segments
Definition: gindatapage.c:50
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
#define GinDataPageSetDataSize(page, size)
Definition: ginblock.h:310
#define GinPageSetCompressed(page)
Definition: ginblock.h:122
static char * buf
Definition: pg_test_fsync.c:68
#define GIN_SEGMENT_DELETE
Definition: ginxlog.h:92
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:279
dlist_node * cur
Definition: ilist.h:161
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:732
#define GinDataPageMaxDataSize
Definition: ginblock.h:320
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:343
#define GIN_SEGMENT_UNMODIFIED
Definition: ginxlog.h:91
Pointer Page
Definition: bufpage.h:78

◆ dataPlaceToPageLeafSplit()

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

Definition at line 1028 of file gindatapage.c.

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().

1031 {
1032  char *ptr;
1033  int segsize;
1034  int lsize;
1035  int rsize;
1036  dlist_node *node;
1037  dlist_node *firstright;
1038  leafSegmentInfo *seginfo;
1039 
1040  /* Initialize temporary pages to hold the new left and right pages */
1041  GinInitPage(lpage, GIN_DATA | GIN_LEAF | GIN_COMPRESSED, BLCKSZ);
1042  GinInitPage(rpage, GIN_DATA | GIN_LEAF | GIN_COMPRESSED, BLCKSZ);
1043 
1044  /*
1045  * Copy the segments that go to the left page.
1046  *
1047  * XXX: We should skip copying the unmodified part of the left page, like
1048  * we do when recompressing.
1049  */
1050  lsize = 0;
1051  ptr = (char *) GinDataLeafPageGetPostingList(lpage);
1052  firstright = dlist_next_node(&leaf->segments, leaf->lastleft);
1053  for (node = dlist_head_node(&leaf->segments);
1054  node != firstright;
1055  node = dlist_next_node(&leaf->segments, node))
1056  {
1057  seginfo = dlist_container(leafSegmentInfo, node, node);
1058 
1059  if (seginfo->action != GIN_SEGMENT_DELETE)
1060  {
1061  segsize = SizeOfGinPostingList(seginfo->seg);
1062  memcpy(ptr, seginfo->seg, segsize);
1063  ptr += segsize;
1064  lsize += segsize;
1065  }
1066  }
1067  Assert(lsize == leaf->lsize);
1068  GinDataPageSetDataSize(lpage, lsize);
1069  *GinDataPageGetRightBound(lpage) = lbound;
1070 
1071  /* Copy the segments that go to the right page */
1072  ptr = (char *) GinDataLeafPageGetPostingList(rpage);
1073  rsize = 0;
1074  for (node = firstright;
1075  ;
1076  node = dlist_next_node(&leaf->segments, node))
1077  {
1078  seginfo = dlist_container(leafSegmentInfo, node, node);
1079 
1080  if (seginfo->action != GIN_SEGMENT_DELETE)
1081  {
1082  segsize = SizeOfGinPostingList(seginfo->seg);
1083  memcpy(ptr, seginfo->seg, segsize);
1084  ptr += segsize;
1085  rsize += segsize;
1086  }
1087 
1088  if (!dlist_has_next(&leaf->segments, node))
1089  break;
1090  }
1091  Assert(rsize == leaf->rsize);
1092  GinDataPageSetDataSize(rpage, rsize);
1093  *GinDataPageGetRightBound(rpage) = rbound;
1094 }
GinPostingList * seg
Definition: gindatapage.c:100
dlist_node * lastleft
Definition: gindatapage.c:56
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:338
#define GIN_COMPRESSED
Definition: ginblock.h:48
#define GIN_DATA
Definition: ginblock.h:40
dlist_head segments
Definition: gindatapage.c:50
static dlist_node * dlist_next_node(dlist_head *head, dlist_node *node)
Definition: ilist.h:421
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
#define GinDataPageSetDataSize(page, size)
Definition: ginblock.h:310
#define GIN_SEGMENT_DELETE
Definition: ginxlog.h:92
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:279
static bool dlist_has_next(dlist_head *head, dlist_node *node)
Definition: ilist.h:402
static dlist_node * dlist_head_node(dlist_head *head)
Definition: ilist.h:449
#define Assert(condition)
Definition: c.h:732
#define GinDataPageGetRightBound(page)
Definition: ginblock.h:289
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:343
#define GIN_LEAF
Definition: ginblock.h:41

◆ dataPrepareDownlink()

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

Definition at line 1324 of file gindatapage.c.

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

Referenced by ginPrepareDataScan().

1325 {
1326  PostingItem *pitem = palloc(sizeof(PostingItem));
1327  Page lpage = BufferGetPage(lbuf);
1328 
1330  pitem->key = *GinDataPageGetRightBound(lpage);
1331 
1332  return pitem;
1333 }
#define PostingItemSetBlockNumber(pointer, blockNumber)
Definition: ginblock.h:193
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
ItemPointerData key
Definition: ginblock.h:187
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2613
#define GinDataPageGetRightBound(page)
Definition: ginblock.h:289
void * palloc(Size size)
Definition: mcxt.c:924
Pointer Page
Definition: bufpage.h:78

◆ dataSplitPageInternal()

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

Definition at line 1243 of file gindatapage.c.

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

Referenced by dataBeginPlaceToPageInternal().

1247 {
1248  Page oldpage = BufferGetPage(origbuf);
1249  OffsetNumber off = stack->off;
1250  int nitems = GinPageGetOpaque(oldpage)->maxoff;
1251  int nleftitems;
1252  int nrightitems;
1253  Size pageSize = PageGetPageSize(oldpage);
1254  ItemPointerData oldbound = *GinDataPageGetRightBound(oldpage);
1255  ItemPointer bound;
1256  Page lpage;
1257  Page rpage;
1259  PostingItem allitems[(BLCKSZ / sizeof(PostingItem)) + 1];
1260 
1261  lpage = PageGetTempPage(oldpage);
1262  rpage = PageGetTempPage(oldpage);
1263  GinInitPage(lpage, GinPageGetOpaque(oldpage)->flags, pageSize);
1264  GinInitPage(rpage, GinPageGetOpaque(oldpage)->flags, pageSize);
1265 
1266  /*
1267  * First construct a new list of PostingItems, which includes all the old
1268  * items, and the new item.
1269  */
1270  memcpy(allitems, GinDataPageGetPostingItem(oldpage, FirstOffsetNumber),
1271  (off - 1) * sizeof(PostingItem));
1272 
1273  allitems[off - 1] = *((PostingItem *) insertdata);
1274  memcpy(&allitems[off], GinDataPageGetPostingItem(oldpage, off),
1275  (nitems - (off - 1)) * sizeof(PostingItem));
1276  nitems++;
1277 
1278  /* Update existing downlink to point to next page */
1279  PostingItemSetBlockNumber(&allitems[off], updateblkno);
1280 
1281  /*
1282  * When creating a new index, fit as many tuples as possible on the left
1283  * page, on the assumption that the table is scanned from beginning to
1284  * end. This packs the index as tight as possible.
1285  */
1286  if (btree->isBuild && GinPageRightMost(oldpage))
1288  else
1289  separator = nitems / 2;
1290  nleftitems = separator;
1291  nrightitems = nitems - separator;
1292 
1294  allitems,
1295  nleftitems * sizeof(PostingItem));
1296  GinPageGetOpaque(lpage)->maxoff = nleftitems;
1298  &allitems[separator],
1299  nrightitems * sizeof(PostingItem));
1300  GinPageGetOpaque(rpage)->maxoff = nrightitems;
1301 
1302  /*
1303  * Also set pd_lower for both pages, like GinDataPageAddPostingItem does.
1304  */
1305  GinDataPageSetDataSize(lpage, nleftitems * sizeof(PostingItem));
1306  GinDataPageSetDataSize(rpage, nrightitems * sizeof(PostingItem));
1307 
1308  /* set up right bound for left page */
1309  bound = GinDataPageGetRightBound(lpage);
1310  *bound = GinDataPageGetPostingItem(lpage, nleftitems)->key;
1311 
1312  /* set up right bound for right page */
1313  *GinDataPageGetRightBound(rpage) = oldbound;
1314 
1315  /* return temp pages to caller */
1316  *newlpage = lpage;
1317  *newrpage = rpage;
1318 }
#define PostingItemSetBlockNumber(pointer, blockNumber)
Definition: ginblock.h:193
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:338
OffsetNumber off
Definition: gin_private.h:126
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
uint16 OffsetNumber
Definition: off.h:24
#define GinDataPageSetDataSize(page, size)
Definition: ginblock.h:310
#define GinPageRightMost(page)
Definition: ginblock.h:129
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:299
#define FirstOffsetNumber
Definition: off.h:27
#define PageGetPageSize(page)
Definition: bufpage.h:268
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
Page PageGetTempPage(Page page)
Definition: bufpage.c:351
size_t Size
Definition: c.h:466
#define GinDataPageGetRightBound(page)
Definition: ginblock.h:289
#define GinNonLeafDataPageGetFreeSpace(page)
Definition: ginblock.h:316
Pointer Page
Definition: bufpage.h:78

◆ disassembleLeaf()

static disassembledLeaf * disassembleLeaf ( Page  page)
static

Definition at line 1361 of file gindatapage.c.

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().

1362 {
1363  disassembledLeaf *leaf;
1364  GinPostingList *seg;
1365  Pointer segbegin;
1366  Pointer segend;
1367 
1368  leaf = palloc0(sizeof(disassembledLeaf));
1369  dlist_init(&leaf->segments);
1370 
1371  if (GinPageIsCompressed(page))
1372  {
1373  /*
1374  * Create a leafSegmentInfo entry for each segment.
1375  */
1376  seg = GinDataLeafPageGetPostingList(page);
1377  segbegin = (Pointer) seg;
1378  segend = segbegin + GinDataLeafPageGetPostingListSize(page);
1379  while ((Pointer) seg < segend)
1380  {
1381  leafSegmentInfo *seginfo = palloc(sizeof(leafSegmentInfo));
1382 
1383  seginfo->action = GIN_SEGMENT_UNMODIFIED;
1384  seginfo->seg = seg;
1385  seginfo->items = NULL;
1386  seginfo->nitems = 0;
1387  dlist_push_tail(&leaf->segments, &seginfo->node);
1388 
1389  seg = GinNextPostingListSegment(seg);
1390  }
1391  leaf->oldformat = false;
1392  }
1393  else
1394  {
1395  /*
1396  * A pre-9.4 format uncompressed page is represented by a single
1397  * segment, with an array of items. The corner case is uncompressed
1398  * page containing no items, which is represented as no segments.
1399  */
1400  ItemPointer uncompressed;
1401  int nuncompressed;
1402  leafSegmentInfo *seginfo;
1403 
1404  uncompressed = dataLeafPageGetUncompressed(page, &nuncompressed);
1405 
1406  if (nuncompressed > 0)
1407  {
1408  seginfo = palloc(sizeof(leafSegmentInfo));
1409 
1410  seginfo->action = GIN_SEGMENT_REPLACE;
1411  seginfo->seg = NULL;
1412  seginfo->items = palloc(nuncompressed * sizeof(ItemPointerData));
1413  memcpy(seginfo->items, uncompressed, nuncompressed * sizeof(ItemPointerData));
1414  seginfo->nitems = nuncompressed;
1415 
1416  dlist_push_tail(&leaf->segments, &seginfo->node);
1417  }
1418 
1419  leaf->oldformat = true;
1420  }
1421 
1422  return leaf;
1423 }
GinPostingList * seg
Definition: gindatapage.c:100
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:317
#define GinPageIsCompressed(page)
Definition: ginblock.h:121
dlist_head segments
Definition: gindatapage.c:50
char * Pointer
Definition: c.h:335
#define GIN_SEGMENT_REPLACE
Definition: ginxlog.h:94
#define GinNextPostingListSegment(cur)
Definition: ginblock.h:344
#define GinDataLeafPageGetPostingListSize(page)
Definition: ginblock.h:281
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:279
void * palloc0(Size size)
Definition: mcxt.c:955
static void dlist_init(dlist_head *head)
Definition: ilist.h:278
dlist_node node
Definition: gindatapage.c:72
void * palloc(Size size)
Definition: mcxt.c:924
ItemPointer items
Definition: gindatapage.c:101
#define GIN_SEGMENT_UNMODIFIED
Definition: ginxlog.h:91
static ItemPointer dataLeafPageGetUncompressed(Page page, int *nitems)
Definition: gindatapage.c:211

◆ ginDataFillRoot()

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

Definition at line 1340 of file gindatapage.c.

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

Referenced by ginPrepareDataScan().

1341 {
1342  PostingItem li,
1343  ri;
1344 
1345  li.key = *GinDataPageGetRightBound(lpage);
1346  PostingItemSetBlockNumber(&li, lblkno);
1348 
1349  ri.key = *GinDataPageGetRightBound(rpage);
1350  PostingItemSetBlockNumber(&ri, rblkno);
1352 }
#define PostingItemSetBlockNumber(pointer, blockNumber)
Definition: ginblock.h:193
void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset)
Definition: gindatapage.c:377
ItemPointerData key
Definition: ginblock.h:187
#define InvalidOffsetNumber
Definition: off.h:26
#define GinDataPageGetRightBound(page)
Definition: ginblock.h:289

◆ GinDataLeafPageGetItems()

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

Definition at line 135 of file gindatapage.c.

References dataLeafPageGetUncompressed(), GinPostingList::first, ginCompareItemPointers(), GinDataLeafPageGetPostingList, GinDataLeafPageGetPostingListSize, GinNextPostingListSegment, GinPageIsCompressed, ginPostingListDecodeAllSegments(), ItemPointerIsValid, next, and palloc().

Referenced by entryLoadMoreItems(), and startScanEntry().

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  {
149  next = GinNextPostingListSegment(seg);
150  while ((Pointer) next < endptr &&
151  ginCompareItemPointers(&next->first, &advancePast) <= 0)
152  {
153  seg = next;
154  next = GinNextPostingListSegment(seg);
155  }
156  len = endptr - (Pointer) seg;
157  }
158 
159  if (len > 0)
160  result = ginPostingListDecodeAllSegments(seg, len, nitems);
161  else
162  {
163  result = NULL;
164  *nitems = 0;
165  }
166  }
167  else
168  {
169  ItemPointer tmp = dataLeafPageGetUncompressed(page, nitems);
170 
171  result = palloc((*nitems) * sizeof(ItemPointerData));
172  memcpy(result, tmp, (*nitems) * sizeof(ItemPointerData));
173  }
174 
175  return result;
176 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
static int32 next
Definition: blutils.c:213
#define GinPageIsCompressed(page)
Definition: ginblock.h:121
ItemPointerData first
Definition: ginblock.h:338
char * Pointer
Definition: c.h:335
#define GinNextPostingListSegment(cur)
Definition: ginblock.h:344
#define GinDataLeafPageGetPostingListSize(page)
Definition: ginblock.h:281
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:279
size_t Size
Definition: c.h:466
static int ginCompareItemPointers(ItemPointer a, ItemPointer b)
Definition: gin_private.h:461
void * palloc(Size size)
Definition: mcxt.c:924
ItemPointer ginPostingListDecodeAllSegments(GinPostingList *segment, int len, int *ndecoded_out)
static ItemPointer dataLeafPageGetUncompressed(Page page, int *nitems)
Definition: gindatapage.c:211

◆ GinDataLeafPageGetItemsToTbm()

int GinDataLeafPageGetItemsToTbm ( Page  page,
TIDBitmap tbm 
)

Definition at line 182 of file gindatapage.c.

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

Referenced by scanPostingTree().

183 {
184  ItemPointer uncompressed;
185  int nitems;
186 
187  if (GinPageIsCompressed(page))
188  {
191 
192  nitems = ginPostingListDecodeAllSegmentsToTbm(segment, len, tbm);
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:376
#define GinPageIsCompressed(page)
Definition: ginblock.h:121
#define GinDataLeafPageGetPostingListSize(page)
Definition: ginblock.h:281
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:279
size_t Size
Definition: c.h:466
static ItemPointer dataLeafPageGetUncompressed(Page page, int *nitems)
Definition: gindatapage.c:211

◆ GinDataPageAddPostingItem()

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

Definition at line 377 of file gindatapage.c.

References Assert, GinDataPageGetPostingItem, GinDataPageSetDataSize, GinPageGetOpaque, GinPageIsLeaf, InvalidBlockNumber, InvalidOffsetNumber, memmove, and PostingItemGetBlockNumber.

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

378 {
379  OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
380  char *ptr;
381 
383  Assert(!GinPageIsLeaf(page));
384 
385  if (offset == InvalidOffsetNumber)
386  {
387  ptr = (char *) GinDataPageGetPostingItem(page, maxoff + 1);
388  }
389  else
390  {
391  ptr = (char *) GinDataPageGetPostingItem(page, offset);
392  if (offset != maxoff + 1)
393  memmove(ptr + sizeof(PostingItem),
394  ptr,
395  (maxoff - offset + 1) * sizeof(PostingItem));
396  }
397  memcpy(ptr, data, sizeof(PostingItem));
398 
399  maxoff++;
400  GinPageGetOpaque(page)->maxoff = maxoff;
401 
402  /*
403  * Also set pd_lower to the end of the posting items, to follow the
404  * "standard" page layout, so that we can squeeze out the unused space
405  * from full-page images.
406  */
407  GinDataPageSetDataSize(page, maxoff * sizeof(PostingItem));
408 }
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
uint16 OffsetNumber
Definition: off.h:24
#define GinDataPageSetDataSize(page, size)
Definition: ginblock.h:310
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:299
#define memmove(d, s, c)
Definition: c.h:1238
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
#define InvalidOffsetNumber
Definition: off.h:26
#define PostingItemGetBlockNumber(pointer)
Definition: ginblock.h:190
#define Assert(condition)
Definition: c.h:732
#define InvalidBlockNumber
Definition: block.h:33

◆ ginInsertItemPointers()

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

Definition at line 1899 of file gindatapage.c.

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

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

1902 {
1903  GinBtreeData btree;
1904  GinBtreeDataLeafInsertData insertdata;
1905  GinBtreeStack *stack;
1906 
1907  ginPrepareDataScan(&btree, index, rootBlkno);
1908  btree.isBuild = (buildStats != NULL);
1909  insertdata.items = items;
1910  insertdata.nitem = nitem;
1911  insertdata.curitem = 0;
1912 
1913  while (insertdata.curitem < insertdata.nitem)
1914  {
1915  /* search for the leaf page where the first item should go to */
1916  btree.itemptr = insertdata.items[insertdata.curitem];
1917  stack = ginFindLeafPage(&btree, false, true, NULL);
1918 
1919  ginInsertValue(&btree, stack, &insertdata, buildStats);
1920  }
1921 }
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, bool rootConflictCheck, Snapshot snapshot)
Definition: ginbtree.c:80
static void ginPrepareDataScan(GinBtree btree, Relation index, BlockNumber rootBlkno)
Definition: gindatapage.c:1873
ItemPointerData * items
Definition: gin_private.h:188
void ginInsertValue(GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
Definition: ginbtree.c:784
ItemPointerData itemptr
Definition: gin_private.h:172

◆ GinPageDeletePostingItem()

void GinPageDeletePostingItem ( Page  page,
OffsetNumber  offset 
)

Definition at line 414 of file gindatapage.c.

References Assert, FirstOffsetNumber, GinDataPageGetPostingItem, GinDataPageSetDataSize, GinPageGetOpaque, GinPageIsLeaf, and memmove.

Referenced by ginDeletePage(), and ginRedoDeletePage().

415 {
416  OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
417 
418  Assert(!GinPageIsLeaf(page));
419  Assert(offset >= FirstOffsetNumber && offset <= maxoff);
420 
421  if (offset != maxoff)
422  memmove(GinDataPageGetPostingItem(page, offset),
423  GinDataPageGetPostingItem(page, offset + 1),
424  sizeof(PostingItem) * (maxoff - offset));
425 
426  maxoff--;
427  GinPageGetOpaque(page)->maxoff = maxoff;
428 
429  GinDataPageSetDataSize(page, maxoff * sizeof(PostingItem));
430 }
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
uint16 OffsetNumber
Definition: off.h:24
#define GinDataPageSetDataSize(page, size)
Definition: ginblock.h:310
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:299
#define memmove(d, s, c)
Definition: c.h:1238
#define FirstOffsetNumber
Definition: off.h:27
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
#define Assert(condition)
Definition: c.h:732

◆ ginPrepareDataScan()

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

Definition at line 1873 of file gindatapage.c.

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().

1874 {
1875  memset(btree, 0, sizeof(GinBtreeData));
1876 
1877  btree->index = index;
1878  btree->rootBlkno = rootBlkno;
1879 
1880  btree->findChildPage = dataLocateItem;
1882  btree->isMoveRight = dataIsMoveRight;
1883  btree->findItem = NULL;
1884  btree->findChildPtr = dataFindChildPtr;
1887  btree->fillRoot = ginDataFillRoot;
1889 
1890  btree->isData = true;
1891  btree->fullScan = false;
1892  btree->isBuild = false;
1893 }
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
Definition: gin_private.h:156
bool(* isMoveRight)(GinBtree, Page)
Definition: gin_private.h:148
static BlockNumber dataLocateItem(GinBtree btree, GinBtreeStack *stack)
Definition: gindatapage.c:249
BlockNumber rootBlkno
Definition: gin_private.h:161
bool(* findItem)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:149
static GinPlaceToPageRC dataBeginPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, void **ptp_workspace, Page *newlpage, Page *newrpage)
Definition: gindatapage.c:1192
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
Definition: gin_private.h:153
static bool dataIsMoveRight(GinBtree btree, Page page)
Definition: gindatapage.c:234
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
Definition: gin_private.h:154
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:146
static OffsetNumber dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
Definition: gindatapage.c:316
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:147
Relation index
Definition: gin_private.h:160
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:155
void ginDataFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
Definition: gindatapage.c:1340
static void * dataPrepareDownlink(GinBtree btree, Buffer lbuf)
Definition: gindatapage.c:1324
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:152
static void dataExecPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, void *ptp_workspace)
Definition: gindatapage.c:1222
static BlockNumber dataGetLeftMostPage(GinBtree btree, Page page)
Definition: gindatapage.c:361

◆ ginScanBeginPostingTree()

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

Definition at line 1927 of file gindatapage.c.

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

Referenced by scanPostingTree(), and startScanEntry().

1929 {
1930  GinBtreeStack *stack;
1931 
1932  ginPrepareDataScan(btree, index, rootBlkno);
1933 
1934  btree->fullScan = true;
1935 
1936  stack = ginFindLeafPage(btree, true, false, snapshot);
1937 
1938  return stack;
1939 }
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, bool rootConflictCheck, Snapshot snapshot)
Definition: ginbtree.c:80
static void ginPrepareDataScan(GinBtree btree, Relation index, BlockNumber rootBlkno)
Definition: gindatapage.c:1873

◆ ginVacuumPostingTreeLeaf()

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

Definition at line 732 of file gindatapage.c.

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().

733 {
734  Page page = BufferGetPage(buffer);
735  disassembledLeaf *leaf;
736  bool removedsomething = false;
737  dlist_iter iter;
738 
739  leaf = disassembleLeaf(page);
740 
741  /* Vacuum each segment. */
742  dlist_foreach(iter, &leaf->segments)
743  {
744  leafSegmentInfo *seginfo = dlist_container(leafSegmentInfo, node, iter.cur);
745  int oldsegsize;
746  ItemPointer cleaned;
747  int ncleaned;
748 
749  if (!seginfo->items)
750  seginfo->items = ginPostingListDecode(seginfo->seg,
751  &seginfo->nitems);
752  if (seginfo->seg)
753  oldsegsize = SizeOfGinPostingList(seginfo->seg);
754  else
755  oldsegsize = GinDataPageMaxDataSize;
756 
757  cleaned = ginVacuumItemPointers(gvs,
758  seginfo->items,
759  seginfo->nitems,
760  &ncleaned);
761  pfree(seginfo->items);
762  seginfo->items = NULL;
763  seginfo->nitems = 0;
764  if (cleaned)
765  {
766  if (ncleaned > 0)
767  {
768  int npacked;
769 
770  seginfo->seg = ginCompressPostingList(cleaned,
771  ncleaned,
772  oldsegsize,
773  &npacked);
774  /* Removing an item never increases the size of the segment */
775  if (npacked != ncleaned)
776  elog(ERROR, "could not fit vacuumed posting list");
777  seginfo->action = GIN_SEGMENT_REPLACE;
778  }
779  else
780  {
781  seginfo->seg = NULL;
782  seginfo->items = NULL;
783  seginfo->action = GIN_SEGMENT_DELETE;
784  }
785  seginfo->nitems = ncleaned;
786 
787  removedsomething = true;
788  }
789  }
790 
791  /*
792  * If we removed any items, reconstruct the page from the pieces.
793  *
794  * We don't try to re-encode the segments here, even though some of them
795  * might be really small now that we've removed some items from them. It
796  * seems like a waste of effort, as there isn't really any benefit from
797  * larger segments per se; larger segments only help to pack more items in
798  * the same space. We might as well delay doing that until the next
799  * insertion, which will need to re-encode at least part of the page
800  * anyway.
801  *
802  * Also note if the page was in uncompressed, pre-9.4 format before, it is
803  * now represented as one huge segment that contains all the items. It
804  * might make sense to split that, to speed up random access, but we don't
805  * bother. You'll have to REINDEX anyway if you want the full gain of the
806  * new tighter index format.
807  */
808  if (removedsomething)
809  {
810  bool modified;
811 
812  /*
813  * Make sure we have a palloc'd copy of all segments, after the first
814  * segment that is modified. (dataPlaceToPageLeafRecompress requires
815  * this).
816  */
817  modified = false;
818  dlist_foreach(iter, &leaf->segments)
819  {
821  iter.cur);
822 
823  if (seginfo->action != GIN_SEGMENT_UNMODIFIED)
824  modified = true;
825  if (modified && seginfo->action != GIN_SEGMENT_DELETE)
826  {
827  int segsize = SizeOfGinPostingList(seginfo->seg);
828  GinPostingList *tmp = (GinPostingList *) palloc(segsize);
829 
830  memcpy(tmp, seginfo->seg, segsize);
831  seginfo->seg = tmp;
832  }
833  }
834 
835  if (RelationNeedsWAL(indexrel))
837 
838  /* Apply changes to page */
840 
841  dataPlaceToPageLeafRecompress(buffer, leaf);
842 
843  MarkBufferDirty(buffer);
844 
845  if (RelationNeedsWAL(indexrel))
846  {
847  XLogRecPtr recptr;
848 
849  XLogBeginInsert();
851  XLogRegisterBufData(0, leaf->walinfo, leaf->walinfolen);
852  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_VACUUM_DATA_LEAF_PAGE);
853  PageSetLSN(page, recptr);
854  }
855 
857  }
858 }
GinPostingList * seg
Definition: gindatapage.c:100
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
GinPostingList * ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded)
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define dlist_foreach(iter, lhead)
Definition: ilist.h:507
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
ItemPointer ginVacuumItemPointers(GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining)
Definition: ginvacuum.c:48
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
dlist_head segments
Definition: gindatapage.c:50
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
void pfree(void *pointer)
Definition: mcxt.c:1031
#define GIN_SEGMENT_REPLACE
Definition: ginxlog.h:94
#define ERROR
Definition: elog.h:43
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define GIN_SEGMENT_DELETE
Definition: ginxlog.h:92
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define XLOG_GIN_VACUUM_DATA_LEAF_PAGE
Definition: ginxlog.h:141
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
static void dataPlaceToPageLeafRecompress(Buffer buf, disassembledLeaf *leaf)
Definition: gindatapage.c:972
dlist_node * cur
Definition: ilist.h:161
static void computeLeafRecompressWALData(disassembledLeaf *leaf)
Definition: gindatapage.c:866
uint64 XLogRecPtr
Definition: xlogdefs.h:21
static disassembledLeaf * disassembleLeaf(Page page)
Definition: gindatapage.c:1361
#define RelationNeedsWAL(relation)
Definition: rel.h:518
#define GinDataPageMaxDataSize
Definition: ginblock.h:320
void * palloc(Size size)
Definition: mcxt.c:924
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:343
#define elog(elevel,...)
Definition: elog.h:226
ItemPointer items
Definition: gindatapage.c:101
#define GIN_SEGMENT_UNMODIFIED
Definition: ginxlog.h:91
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
Pointer Page
Definition: bufpage.h:78

◆ leafRepackItems()

static bool leafRepackItems ( disassembledLeaf leaf,
ItemPointer  remaining 
)
static

Definition at line 1562 of file gindatapage.c.

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(), disassembledLeaf::rsize, leafSegmentInfo::seg, disassembledLeaf::segments, and SizeOfGinPostingList.

Referenced by dataBeginPlaceToPageLeaf().

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