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:224
struct cursor * cur
Definition: ecpg.c:29
static int ginCompareItemPointers(ItemPointer a, ItemPointer b)
Definition: gin_private.h:496
#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
Assert(PointerIsAligned(start, uint64))
#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
void * palloc(Size size)
Definition: mcxt.c:1317
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
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 */
927 seginfo->nmodifieditems * sizeof(ItemPointerData) > segsize)
928 {
930 }
931
932 *((uint8 *) (walbufend++)) = segno;
933 *(walbufend++) = action;
934
935 switch (action)
936 {
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
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
960 segno++;
961 }
962
963 /* Pass back the constructed info via *leaf */
964 leaf->walinfo = walbufbegin;
965 leaf->walinfolen = walbufend - walbufbegin;
966}
uint8_t uint8
Definition: c.h:500
#define SHORTALIGN(LEN)
Definition: c.h:778
uint16_t uint16
Definition: c.h:501
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#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 */
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
1848
1850 rootsize);
1852
1853 recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_PTREE);
1854 PageSetLSN(page, recptr);
1855 }
1856
1857 UnlockReleaseBuffer(buffer);
1858
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:3795
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4934
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2596
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:401
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:413
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:391
PageData * Page
Definition: bufpage.h:82
char * Pointer
Definition: c.h:493
#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:343
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:305
#define XLOG_GIN_CREATE_PTREE
Definition: ginxlog.h:19
#define nitems(x)
Definition: indent.h:31
void pfree(void *pointer)
Definition: mcxt.c:1524
#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:3134
#define RelationNeedsWAL(relation)
Definition: rel.h:636
BlockNumber nDataPages
Definition: gin.h:60
Definition: type.h:96
static ItemArray items
Definition: test_tidstore.c:48
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogRegisterData(const void *data, uint32 len)
Definition: xloginsert.c:364
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:242
void XLogBeginInsert(void)
Definition: xloginsert.c:149
#define REGBUF_WILL_INIT
Definition: xloginsert.h:34

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, items, 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:72

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:147
@ GPTP_SPLIT
Definition: gin_private.h:148
#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:975
size_t Size
Definition: c.h:576
@ GPTP_NO_WORK
Definition: gin_private.h:146
#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 bool dlist_has_prev(const dlist_head *head, const dlist_node *node)
Definition: ilist.h:513
static dlist_node * dlist_prev_node(dlist_head *head, dlist_node *node)
Definition: ilist.h:547
static dlist_node * dlist_tail_node(dlist_head *head)
Definition: ilist.h:582
int remaining
Definition: informix.c:692
int i
Definition: isn.c:74
int32 ItemPointerCompare(ItemPointer arg1, ItemPointer arg2)
Definition: itemptr.c:51
static bool ItemPointerIsValid(const ItemPointerData *pointer)
Definition: itemptr.h:83
Relation index
Definition: gin_private.h:168
dlist_node * lastleft
Definition: gindatapage.c:56

References leafSegmentInfo::action, addItemsToLeaf(), Assert(), buf, BufferGetBlockNumber(), BufferGetPage(), computeLeafRecompressWALData(), 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, items, disassembledLeaf::lastleft, leafRepackItems(), disassembledLeaf::lsize, Min, MinTuplesPerSegment, 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
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:134
void XLogRegisterBufData(uint8 block_id, const void *data, uint32 len)
Definition: xloginsert.c:405
#define REGBUF_STANDARD
Definition: xloginsert.h:35

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{
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

◆ 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:180

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{
214
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 */
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, items, 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:155
uint32 predictNumber
Definition: gin_private.h:137
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);
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(const PageData *page)
Definition: bufpage.c:354
static Size PageGetPageSize(const PageData *page)
Definition: bufpage.h:277

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 */
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:1347

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 
)

◆ 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:366

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
ItemPointerData * items
Definition: gin_private.h:196

References GinBtreeDataLeafInsertData::curitem, ginFindLeafPage(), ginInsertValue(), ginPrepareDataScan(), GinBtreeData::isBuild, GinBtreeData::itemptr, GinBtreeDataLeafInsertData::items, 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
1892 btree->findItem = NULL;
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:154
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
Definition: gin_private.h:162
bool(* findItem)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:157
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:163
bool(* isMoveRight)(GinBtree, Page)
Definition: gin_private.h:156
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
Definition: gin_private.h:161
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:160
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
Definition: gin_private.h:164
BlockNumber rootBlkno
Definition: gin_private.h:169

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
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:47
#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().