PostgreSQL Source Code  git master
gin_private.h File Reference
#include "access/amapi.h"
#include "access/gin.h"
#include "access/ginblock.h"
#include "access/itup.h"
#include "fmgr.h"
#include "storage/bufmgr.h"
#include "lib/rbtree.h"
Include dependency graph for gin_private.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  GinOptions
 
struct  GinState
 
struct  GinBtreeStack
 
struct  GinBtreeData
 
struct  GinBtreeEntryInsertData
 
struct  GinBtreeDataLeafInsertData
 
struct  GinScanKeyData
 
struct  GinScanEntryData
 
struct  GinScanOpaqueData
 
struct  GinEntryAccumulator
 
struct  BuildAccumulator
 
struct  GinTupleCollector
 

Macros

#define GIN_DEFAULT_USE_FASTUPDATE   true
 
#define GinGetUseFastUpdate(relation)
 
#define GinGetPendingListCleanupSize(relation)
 
#define GIN_UNLOCK   BUFFER_LOCK_UNLOCK
 
#define GIN_SHARE   BUFFER_LOCK_SHARE
 
#define GIN_EXCLUSIVE   BUFFER_LOCK_EXCLUSIVE
 

Typedefs

typedef struct GinOptions GinOptions
 
typedef struct GinState GinState
 
typedef struct GinBtreeStack GinBtreeStack
 
typedef struct GinBtreeDataGinBtree
 
typedef struct GinBtreeData GinBtreeData
 
typedef struct GinVacuumState GinVacuumState
 
typedef struct GinScanKeyDataGinScanKey
 
typedef struct GinScanEntryDataGinScanEntry
 
typedef struct GinScanKeyData GinScanKeyData
 
typedef struct GinScanEntryData GinScanEntryData
 
typedef struct GinScanOpaqueData GinScanOpaqueData
 
typedef GinScanOpaqueDataGinScanOpaque
 
typedef struct GinEntryAccumulator GinEntryAccumulator
 
typedef struct GinTupleCollector GinTupleCollector
 

Enumerations

enum  GinPlaceToPageRC { GPTP_NO_WORK, GPTP_INSERT, GPTP_SPLIT }
 

Functions

byteaginoptions (Datum reloptions, bool validate)
 
void initGinState (GinState *state, Relation index)
 
Buffer GinNewBuffer (Relation index)
 
void GinInitBuffer (Buffer b, uint32 f)
 
void GinInitPage (Page page, uint32 f, Size pageSize)
 
void GinInitMetabuffer (Buffer b)
 
int ginCompareEntries (GinState *ginstate, OffsetNumber attnum, Datum a, GinNullCategory categorya, Datum b, GinNullCategory categoryb)
 
int ginCompareAttEntries (GinState *ginstate, OffsetNumber attnuma, Datum a, GinNullCategory categorya, OffsetNumber attnumb, Datum b, GinNullCategory categoryb)
 
DatumginExtractEntries (GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, int32 *nentries, GinNullCategory **categories)
 
OffsetNumber gintuple_get_attrnum (GinState *ginstate, IndexTuple tuple)
 
Datum gintuple_get_key (GinState *ginstate, IndexTuple tuple, GinNullCategory *category)
 
IndexBuildResultginbuild (Relation heap, Relation index, struct IndexInfo *indexInfo)
 
void ginbuildempty (Relation index)
 
bool gininsert (Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, struct IndexInfo *indexInfo)
 
void ginEntryInsert (GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
 
GinBtreeStackginFindLeafPage (GinBtree btree, bool searchMode, Snapshot snapshot)
 
Buffer ginStepRight (Buffer buffer, Relation index, int lockmode)
 
void freeGinBtreeStack (GinBtreeStack *stack)
 
void ginInsertValue (GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
 
IndexTuple GinFormTuple (GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, Pointer data, Size dataSize, int nipd, bool errorTooBig)
 
void ginPrepareEntryScan (GinBtree btree, OffsetNumber attnum, Datum key, GinNullCategory category, GinState *ginstate)
 
void ginEntryFillRoot (GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
 
ItemPointer ginReadTuple (GinState *ginstate, OffsetNumber attnum, IndexTuple itup, int *nitems)
 
ItemPointer GinDataLeafPageGetItems (Page page, int *nitems, ItemPointerData advancePast)
 
int GinDataLeafPageGetItemsToTbm (Page page, TIDBitmap *tbm)
 
BlockNumber createPostingTree (Relation index, ItemPointerData *items, uint32 nitems, GinStatsData *buildStats, Buffer entrybuffer)
 
void GinDataPageAddPostingItem (Page page, PostingItem *data, OffsetNumber offset)
 
void GinPageDeletePostingItem (Page page, OffsetNumber offset)
 
void ginInsertItemPointers (Relation index, BlockNumber rootBlkno, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
 
GinBtreeStackginScanBeginPostingTree (GinBtree btree, Relation index, BlockNumber rootBlkno, Snapshot snapshot)
 
void ginDataFillRoot (GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
 
void ginVacuumPostingTreeLeaf (Relation rel, Buffer buf, GinVacuumState *gvs)
 
IndexScanDesc ginbeginscan (Relation rel, int nkeys, int norderbys)
 
void ginendscan (IndexScanDesc scan)
 
void ginrescan (IndexScanDesc scan, ScanKey key, int nscankeys, ScanKey orderbys, int norderbys)
 
void ginNewScanKey (IndexScanDesc scan)
 
void ginFreeScanKeys (GinScanOpaque so)
 
int64 gingetbitmap (IndexScanDesc scan, TIDBitmap *tbm)
 
void ginInitConsistentFunction (GinState *ginstate, GinScanKey key)
 
IndexBulkDeleteResultginbulkdelete (IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
 
IndexBulkDeleteResultginvacuumcleanup (IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
 
ItemPointer ginVacuumItemPointers (GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining)
 
bool ginvalidate (Oid opclassoid)
 
void ginInitBA (BuildAccumulator *accum)
 
void ginInsertBAEntries (BuildAccumulator *accum, ItemPointer heapptr, OffsetNumber attnum, Datum *entries, GinNullCategory *categories, int32 nentries)
 
void ginBeginBAScan (BuildAccumulator *accum)
 
ItemPointerDataginGetBAEntry (BuildAccumulator *accum, OffsetNumber *attnum, Datum *key, GinNullCategory *category, uint32 *n)
 
void ginHeapTupleFastInsert (GinState *ginstate, GinTupleCollector *collector)
 
void ginHeapTupleFastCollect (GinState *ginstate, GinTupleCollector *collector, OffsetNumber attnum, Datum value, bool isNull, ItemPointer ht_ctid)
 
void ginInsertCleanup (GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
 
GinPostingListginCompressPostingList (const ItemPointer ptrs, int nptrs, int maxsize, int *nwritten)
 
int ginPostingListDecodeAllSegmentsToTbm (GinPostingList *ptr, int totalsize, TIDBitmap *tbm)
 
ItemPointer ginPostingListDecodeAllSegments (GinPostingList *ptr, int len, int *ndecoded)
 
ItemPointer ginPostingListDecode (GinPostingList *ptr, int *ndecoded)
 
ItemPointer ginMergeItemPointers (ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb, int *nmerged)
 
static int ginCompareItemPointers (ItemPointer a, ItemPointer b)
 
int ginTraverseLock (Buffer buffer, bool searchMode)
 

Macro Definition Documentation

◆ GIN_DEFAULT_USE_FASTUPDATE

#define GIN_DEFAULT_USE_FASTUPDATE   true

Definition at line 31 of file gin_private.h.

◆ GIN_EXCLUSIVE

◆ GIN_SHARE

◆ GIN_UNLOCK

◆ GinGetPendingListCleanupSize

#define GinGetPendingListCleanupSize (   relation)
Value:
((relation)->rd_options && \
((GinOptions *) (relation)->rd_options)->pendingListCleanupSize != -1 ? \
((GinOptions *) (relation)->rd_options)->pendingListCleanupSize : \
int gin_pending_list_limit
Definition: ginfast.c:38

Definition at line 35 of file gin_private.h.

Referenced by ginHeapTupleFastInsert().

◆ GinGetUseFastUpdate

#define GinGetUseFastUpdate (   relation)
Value:
((relation)->rd_options ? \
((GinOptions *) (relation)->rd_options)->useFastUpdate : GIN_DEFAULT_USE_FASTUPDATE)
#define GIN_DEFAULT_USE_FASTUPDATE
Definition: gin_private.h:31

Definition at line 32 of file gin_private.h.

Referenced by gininsert().

Typedef Documentation

◆ GinBtree

Definition at line 133 of file gin_private.h.

◆ GinBtreeData

◆ GinBtreeStack

◆ GinEntryAccumulator

◆ GinOptions

◆ GinScanEntry

Definition at line 257 of file gin_private.h.

◆ GinScanEntryData

◆ GinScanKey

Definition at line 255 of file gin_private.h.

◆ GinScanKeyData

◆ GinScanOpaque

◆ GinScanOpaqueData

◆ GinState

◆ GinTupleCollector

◆ GinVacuumState

Definition at line 234 of file gin_private.h.

Enumeration Type Documentation

◆ GinPlaceToPageRC

Enumerator
GPTP_NO_WORK 
GPTP_INSERT 
GPTP_SPLIT 

Definition at line 136 of file gin_private.h.

Function Documentation

◆ createPostingTree()

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

Definition at line 1762 of file gindatapage.c.

References buffer, 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().

1764 {
1765  BlockNumber blkno;
1766  Buffer buffer;
1767  Page tmppage;
1768  Page page;
1769  Pointer ptr;
1770  int nrootitems;
1771  int rootsize;
1772 
1773  /* Construct the new root page in memory first. */
1774  tmppage = (Page) palloc(BLCKSZ);
1775  GinInitPage(tmppage, GIN_DATA | GIN_LEAF | GIN_COMPRESSED, BLCKSZ);
1776  GinPageGetOpaque(tmppage)->rightlink = InvalidBlockNumber;
1777 
1778  /*
1779  * Write as many of the items to the root page as fit. In segments of max
1780  * GinPostingListSegmentMaxSize bytes each.
1781  */
1782  nrootitems = 0;
1783  rootsize = 0;
1784  ptr = (Pointer) GinDataLeafPageGetPostingList(tmppage);
1785  while (nrootitems < nitems)
1786  {
1787  GinPostingList *segment;
1788  int npacked;
1789  int segsize;
1790 
1791  segment = ginCompressPostingList(&items[nrootitems],
1792  nitems - nrootitems,
1794  &npacked);
1795  segsize = SizeOfGinPostingList(segment);
1796  if (rootsize + segsize > GinDataPageMaxDataSize)
1797  break;
1798 
1799  memcpy(ptr, segment, segsize);
1800  ptr += segsize;
1801  rootsize += segsize;
1802  nrootitems += npacked;
1803  pfree(segment);
1804  }
1805  GinDataPageSetDataSize(tmppage, rootsize);
1806 
1807  /*
1808  * All set. Get a new physical page, and copy the in-memory page to it.
1809  */
1810  buffer = GinNewBuffer(index);
1811  page = BufferGetPage(buffer);
1812  blkno = BufferGetBlockNumber(buffer);
1813 
1814  /*
1815  * Copy any predicate locks from the entry tree leaf (containing posting
1816  * list) to the posting tree.
1817  */
1818  PredicateLockPageSplit(index, BufferGetBlockNumber(entrybuffer), blkno);
1819 
1821 
1822  PageRestoreTempPage(tmppage, page);
1823  MarkBufferDirty(buffer);
1824 
1825  if (RelationNeedsWAL(index))
1826  {
1827  XLogRecPtr recptr;
1829 
1830  data.size = rootsize;
1831 
1832  XLogBeginInsert();
1833  XLogRegisterData((char *) &data, sizeof(ginxlogCreatePostingTree));
1834 
1836  rootsize);
1838 
1839  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_PTREE);
1840  PageSetLSN(page, recptr);
1841  }
1842 
1843  UnlockReleaseBuffer(buffer);
1844 
1845  END_CRIT_SECTION();
1846 
1847  /* During index build, count the newly-added data page */
1848  if (buildStats)
1849  buildStats->nDataPages++;
1850 
1851  elog(DEBUG2, "created GIN posting tree with %d items", nrootitems);
1852 
1853  /*
1854  * Add any remaining TIDs to the newly-created posting tree.
1855  */
1856  if (nitems > nrootitems)
1857  {
1858  ginInsertItemPointers(index, blkno,
1859  items + nrootitems,
1860  nitems - nrootitems,
1861  buildStats);
1862  }
1863 
1864  return blkno;
1865 }
GinPostingList * ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:291
#define GinPostingListSegmentMaxSize
Definition: gindatapage.c:34
void ginInsertItemPointers(Relation index, BlockNumber rootBlkno, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gindatapage.c:1894
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:407
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:342
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
#define REGBUF_WILL_INIT
Definition: xloginsert.h:32
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
#define GIN_COMPRESSED
Definition: ginblock.h:47
#define GIN_DATA
Definition: ginblock.h:39
#define GinDataPageSetDataSize(page, size)
Definition: ginblock.h:303
void pfree(void *pointer)
Definition: mcxt.c:1031
char * Pointer
Definition: c.h:302
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define XLOG_GIN_CREATE_PTREE
Definition: ginxlog.h:21
#define DEBUG2
Definition: elog.h:24
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:272
BlockNumber nDataPages
Definition: gin.h:46
uint64 XLogRecPtr
Definition: xlogdefs.h:21
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#define InvalidBlockNumber
Definition: block.h:33
#define RelationNeedsWAL(relation)
Definition: rel.h:510
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define GinDataPageMaxDataSize
Definition: ginblock.h:313
void * palloc(Size size)
Definition: mcxt.c:924
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:336
#define elog
Definition: elog.h:219
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
int Buffer
Definition: buf.h:23
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3065
Pointer Page
Definition: bufpage.h:74
#define GIN_LEAF
Definition: ginblock.h:40

◆ freeGinBtreeStack()

void freeGinBtreeStack ( GinBtreeStack stack)

Definition at line 197 of file ginbtree.c.

References GinBtreeStack::buffer, InvalidBuffer, GinBtreeStack::parent, pfree(), and ReleaseBuffer().

Referenced by entryLoadMoreItems(), ginEntryInsert(), ginFinishSplit(), ginInsertValue(), scanPostingTree(), and startScanEntry().

198 {
199  while (stack)
200  {
201  GinBtreeStack *tmp = stack->parent;
202 
203  if (stack->buffer != InvalidBuffer)
204  ReleaseBuffer(stack->buffer);
205 
206  pfree(stack);
207  stack = tmp;
208  }
209 }
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
void pfree(void *pointer)
Definition: mcxt.c:1031
struct GinBtreeStack * parent
Definition: gin_private.h:130

◆ ginBeginBAScan()

void ginBeginBAScan ( BuildAccumulator accum)

Definition at line 257 of file ginbulk.c.

References LeftRightWalk, rb_begin_iterate(), BuildAccumulator::tree, and BuildAccumulator::tree_walk.

Referenced by ginbuild(), ginBuildCallback(), and ginInsertCleanup().

258 {
259  rb_begin_iterate(accum->tree, LeftRightWalk, &accum->tree_walk);
260 }
void rb_begin_iterate(RBTree *rb, RBOrderControl ctrl, RBTreeIterator *iter)
Definition: rbtree.c:737
RBTreeIterator tree_walk
Definition: gin_private.h:411

◆ ginbeginscan()

IndexScanDesc ginbeginscan ( Relation  rel,
int  nkeys,
int  norderbys 
)

Definition at line 25 of file ginscan.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, CurrentMemoryContext, GinScanOpaqueData::ginstate, IndexScanDescData::indexRelation, initGinState(), GinScanOpaqueData::keyCtx, GinScanOpaqueData::keys, GinScanOpaqueData::nkeys, IndexScanDescData::opaque, palloc(), RelationGetIndexScan(), and GinScanOpaqueData::tempCtx.

Referenced by ginhandler().

26 {
27  IndexScanDesc scan;
28  GinScanOpaque so;
29 
30  /* no order by operators allowed */
31  Assert(norderbys == 0);
32 
33  scan = RelationGetIndexScan(rel, nkeys, norderbys);
34 
35  /* allocate private workspace */
36  so = (GinScanOpaque) palloc(sizeof(GinScanOpaqueData));
37  so->keys = NULL;
38  so->nkeys = 0;
40  "Gin scan temporary context",
43  "Gin scan key context",
45  initGinState(&so->ginstate, scan->indexRelation);
46 
47  scan->opaque = so;
48 
49  return scan;
50 }
Relation indexRelation
Definition: relscan.h:91
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:363
MemoryContext keyCtx
Definition: gin_private.h:358
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:88
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
GinScanKey keys
Definition: gin_private.h:351
MemoryContext tempCtx
Definition: gin_private.h:348
#define Assert(condition)
Definition: c.h:699
void * palloc(Size size)
Definition: mcxt.c:924
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:78

◆ ginbuild()

IndexBuildResult* ginbuild ( Relation  heap,
Relation  index,
struct IndexInfo indexInfo 
)

Definition at line 315 of file gininsert.c.

References GinBuildState::accum, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, attnum, BufferGetPage, GinBuildState::buildStats, CHECK_FOR_INTERRUPTS, CurrentMemoryContext, elog, END_CRIT_SECTION, ERROR, GinBuildState::funcCtx, GIN_LEAF, ginBeginBAScan(), ginBuildCallback(), ginEntryInsert(), ginGetBAEntry(), ginInitBA(), GinInitBuffer(), GinInitMetabuffer(), GinNewBuffer(), GinBuildState::ginstate, BuildAccumulator::ginstate, ginUpdateStats(), IndexBuildResult::heap_tuples, IndexBuildResult::index_tuples, IndexBuildHeapScan(), GinBuildState::indtuples, initGinState(), sort-test::list, MarkBufferDirty(), MemoryContextDelete(), MemoryContextSwitchTo(), GinStatsData::nEntryPages, PageSetLSN, palloc(), REGBUF_STANDARD, REGBUF_WILL_INIT, RelationGetNumberOfBlocks, RelationGetRelationName, RelationNeedsWAL, reltuples, START_CRIT_SECTION, GinBuildState::tmpCtx, UnlockReleaseBuffer(), XLOG_GIN_CREATE_INDEX, XLogBeginInsert(), XLogInsert(), and XLogRegisterBuffer().

Referenced by ginhandler().

316 {
317  IndexBuildResult *result;
318  double reltuples;
319  GinBuildState buildstate;
320  Buffer RootBuffer,
321  MetaBuffer;
323  Datum key;
324  GinNullCategory category;
325  uint32 nlist;
326  MemoryContext oldCtx;
328 
329  if (RelationGetNumberOfBlocks(index) != 0)
330  elog(ERROR, "index \"%s\" already contains data",
331  RelationGetRelationName(index));
332 
333  initGinState(&buildstate.ginstate, index);
334  buildstate.indtuples = 0;
335  memset(&buildstate.buildStats, 0, sizeof(GinStatsData));
336 
337  /* initialize the meta page */
338  MetaBuffer = GinNewBuffer(index);
339 
340  /* initialize the root page */
341  RootBuffer = GinNewBuffer(index);
342 
344  GinInitMetabuffer(MetaBuffer);
345  MarkBufferDirty(MetaBuffer);
346  GinInitBuffer(RootBuffer, GIN_LEAF);
347  MarkBufferDirty(RootBuffer);
348 
349  if (RelationNeedsWAL(index))
350  {
351  XLogRecPtr recptr;
352  Page page;
353 
354  XLogBeginInsert();
356  XLogRegisterBuffer(1, RootBuffer, REGBUF_WILL_INIT);
357 
358  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_INDEX);
359 
360  page = BufferGetPage(RootBuffer);
361  PageSetLSN(page, recptr);
362 
363  page = BufferGetPage(MetaBuffer);
364  PageSetLSN(page, recptr);
365  }
366 
367  UnlockReleaseBuffer(MetaBuffer);
368  UnlockReleaseBuffer(RootBuffer);
370 
371  /* count the root as first entry page */
372  buildstate.buildStats.nEntryPages++;
373 
374  /*
375  * create a temporary memory context that is used to hold data not yet
376  * dumped out to the index
377  */
379  "Gin build temporary context",
381 
382  /*
383  * create a temporary memory context that is used for calling
384  * ginExtractEntries(), and can be reset after each tuple
385  */
387  "Gin build temporary context for user-defined function",
389 
390  buildstate.accum.ginstate = &buildstate.ginstate;
391  ginInitBA(&buildstate.accum);
392 
393  /*
394  * Do the heap scan. We disallow sync scan here because dataPlaceToPage
395  * prefers to receive tuples in TID order.
396  */
397  reltuples = IndexBuildHeapScan(heap, index, indexInfo, false,
398  ginBuildCallback, (void *) &buildstate, NULL);
399 
400  /* dump remaining entries to the index */
401  oldCtx = MemoryContextSwitchTo(buildstate.tmpCtx);
402  ginBeginBAScan(&buildstate.accum);
403  while ((list = ginGetBAEntry(&buildstate.accum,
404  &attnum, &key, &category, &nlist)) != NULL)
405  {
406  /* there could be many entries, so be willing to abort here */
408  ginEntryInsert(&buildstate.ginstate, attnum, key, category,
409  list, nlist, &buildstate.buildStats);
410  }
411  MemoryContextSwitchTo(oldCtx);
412 
413  MemoryContextDelete(buildstate.funcCtx);
414  MemoryContextDelete(buildstate.tmpCtx);
415 
416  /*
417  * Update metapage stats
418  */
420  ginUpdateStats(index, &buildstate.buildStats);
421 
422  /*
423  * Return statistics
424  */
425  result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
426 
427  result->heap_tuples = reltuples;
428  result->index_tuples = buildstate.indtuples;
429 
430  return result;
431 }
BlockNumber nEntryPages
Definition: gin.h:45
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:291
void GinInitMetabuffer(Buffer b)
Definition: ginutil.c:361
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
GinStatsData buildStats
Definition: gininsert.c:34
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define REGBUF_WILL_INIT
Definition: xloginsert.h:32
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
double indtuples
Definition: gininsert.c:33
static void ginBuildCallback(Relation index, HeapTuple htup, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition: gininsert.c:274
uint16 OffsetNumber
Definition: off.h:24
GinState ginstate
Definition: gininsert.c:32
void ginEntryInsert(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gininsert.c:179
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ERROR
Definition: elog.h:43
signed char GinNullCategory
Definition: ginblock.h:200
double IndexBuildHeapScan(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool allow_sync, IndexBuildCallback callback, void *callback_state, HeapScanDesc scan)
Definition: index.c:2418
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
void ginUpdateStats(Relation index, const GinStatsData *stats)
Definition: ginutil.c:669
BuildAccumulator accum
Definition: gininsert.c:37
#define REGBUF_STANDARD
Definition: xloginsert.h:34
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:88
#define RelationGetRelationName(relation)
Definition: rel.h:441
unsigned int uint32
Definition: c.h:325
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
GinState * ginstate
Definition: gin_private.h:406
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define XLOG_GIN_CREATE_INDEX
Definition: ginxlog.h:19
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
uintptr_t Datum
Definition: postgres.h:367
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
int16 attnum
Definition: pg_attribute.h:79
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void GinInitBuffer(Buffer b, uint32 f)
Definition: ginutil.c:355
BlockNumber nTotalPages
Definition: gin.h:44
ItemPointerData * ginGetBAEntry(BuildAccumulator *accum, OffsetNumber *attnum, Datum *key, GinNullCategory *category, uint32 *n)
Definition: ginbulk.c:268
#define RelationNeedsWAL(relation)
Definition: rel.h:510
void ginBeginBAScan(BuildAccumulator *accum)
Definition: ginbulk.c:257
void * palloc(Size size)
Definition: mcxt.c:924
MemoryContext tmpCtx
Definition: gininsert.c:35
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define elog
Definition: elog.h:219
MemoryContext funcCtx
Definition: gininsert.c:36
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
int Buffer
Definition: buf.h:23
float4 reltuples
Definition: pg_class.h:44
Pointer Page
Definition: bufpage.h:74
double index_tuples
Definition: genam.h:33
double heap_tuples
Definition: genam.h:32
void ginInitBA(BuildAccumulator *accum)
Definition: ginbulk.c:109
#define GIN_LEAF
Definition: ginblock.h:40

◆ ginbuildempty()

void ginbuildempty ( Relation  index)

Definition at line 437 of file gininsert.c.

References BUFFER_LOCK_EXCLUSIVE, END_CRIT_SECTION, GIN_LEAF, GinInitBuffer(), GinInitMetabuffer(), INIT_FORKNUM, LockBuffer(), log_newpage_buffer(), MarkBufferDirty(), P_NEW, RBM_NORMAL, ReadBufferExtended(), START_CRIT_SECTION, and UnlockReleaseBuffer().

Referenced by ginhandler().

438 {
439  Buffer RootBuffer,
440  MetaBuffer;
441 
442  /* An empty GIN index has two pages. */
443  MetaBuffer =
445  LockBuffer(MetaBuffer, BUFFER_LOCK_EXCLUSIVE);
446  RootBuffer =
448  LockBuffer(RootBuffer, BUFFER_LOCK_EXCLUSIVE);
449 
450  /* Initialize and xlog metabuffer and root buffer. */
452  GinInitMetabuffer(MetaBuffer);
453  MarkBufferDirty(MetaBuffer);
454  log_newpage_buffer(MetaBuffer, true);
455  GinInitBuffer(RootBuffer, GIN_LEAF);
456  MarkBufferDirty(RootBuffer);
457  log_newpage_buffer(RootBuffer, false);
459 
460  /* Unlock and release the buffers. */
461  UnlockReleaseBuffer(MetaBuffer);
462  UnlockReleaseBuffer(RootBuffer);
463 }
void GinInitMetabuffer(Buffer b)
Definition: ginutil.c:361
XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std)
Definition: xloginsert.c:1009
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:640
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
#define P_NEW
Definition: bufmgr.h:82
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:89
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
void GinInitBuffer(Buffer b, uint32 f)
Definition: ginutil.c:355
int Buffer
Definition: buf.h:23
#define GIN_LEAF
Definition: ginblock.h:40

◆ ginbulkdelete()

IndexBulkDeleteResult* ginbulkdelete ( IndexVacuumInfo info,
IndexBulkDeleteResult stats,
IndexBulkDeleteCallback  callback,
void *  callback_state 
)

Definition at line 551 of file ginvacuum.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, DataPageDeleteStack::blkno, buffer, BufferGetPage, GinVacuumState::callback, GinVacuumState::callback_state, CurrentMemoryContext, END_CRIT_SECTION, FirstOffsetNumber, GIN_EXCLUSIVE, GIN_ROOT_BLKNO, GIN_SHARE, GIN_UNLOCK, GinGetDownlink, ginInsertCleanup(), GinPageGetOpaque, GinPageIsData, GinPageIsLeaf, GinVacuumState::ginstate, ginVacuumEntryPage(), ginVacuumPostingTree(), i, GinVacuumState::index, IndexVacuumInfo::index, initGinState(), InvalidBlockNumber, IsAutoVacuumWorkerProcess(), LockBuffer(), MAIN_FORKNUM, MarkBufferDirty(), MemoryContextDelete(), IndexBulkDeleteResult::num_index_tuples, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageRestoreTempPage(), palloc0(), RBM_NORMAL, ReadBufferExtended(), GinVacuumState::result, START_CRIT_SECTION, GinVacuumState::strategy, IndexVacuumInfo::strategy, GinVacuumState::tmpCxt, UnlockReleaseBuffer(), vacuum_delay_point(), and xlogVacuumPage().

Referenced by ginhandler().

553 {
554  Relation index = info->index;
555  BlockNumber blkno = GIN_ROOT_BLKNO;
556  GinVacuumState gvs;
557  Buffer buffer;
558  BlockNumber rootOfPostingTree[BLCKSZ / (sizeof(IndexTupleData) + sizeof(ItemId))];
559  uint32 nRoot;
560 
562  "Gin vacuum temporary context",
564  gvs.index = index;
565  gvs.callback = callback;
566  gvs.callback_state = callback_state;
567  gvs.strategy = info->strategy;
568  initGinState(&gvs.ginstate, index);
569 
570  /* first time through? */
571  if (stats == NULL)
572  {
573  /* Yes, so initialize stats to zeroes */
575 
576  /*
577  * and cleanup any pending inserts
578  */
580  false, true, stats);
581  }
582 
583  /* we'll re-count the tuples each time */
584  stats->num_index_tuples = 0;
585  gvs.result = stats;
586 
587  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
588  RBM_NORMAL, info->strategy);
589 
590  /* find leaf page */
591  for (;;)
592  {
593  Page page = BufferGetPage(buffer);
594  IndexTuple itup;
595 
596  LockBuffer(buffer, GIN_SHARE);
597 
598  Assert(!GinPageIsData(page));
599 
600  if (GinPageIsLeaf(page))
601  {
602  LockBuffer(buffer, GIN_UNLOCK);
603  LockBuffer(buffer, GIN_EXCLUSIVE);
604 
605  if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page))
606  {
607  LockBuffer(buffer, GIN_UNLOCK);
608  continue; /* check it one more */
609  }
610  break;
611  }
612 
614 
615  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber));
616  blkno = GinGetDownlink(itup);
617  Assert(blkno != InvalidBlockNumber);
618 
619  UnlockReleaseBuffer(buffer);
620  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
621  RBM_NORMAL, info->strategy);
622  }
623 
624  /* right now we found leftmost page in entry's BTree */
625 
626  for (;;)
627  {
628  Page page = BufferGetPage(buffer);
629  Page resPage;
630  uint32 i;
631 
632  Assert(!GinPageIsData(page));
633 
634  resPage = ginVacuumEntryPage(&gvs, buffer, rootOfPostingTree, &nRoot);
635 
636  blkno = GinPageGetOpaque(page)->rightlink;
637 
638  if (resPage)
639  {
641  PageRestoreTempPage(resPage, page);
642  MarkBufferDirty(buffer);
643  xlogVacuumPage(gvs.index, buffer);
644  UnlockReleaseBuffer(buffer);
646  }
647  else
648  {
649  UnlockReleaseBuffer(buffer);
650  }
651 
653 
654  for (i = 0; i < nRoot; i++)
655  {
656  ginVacuumPostingTree(&gvs, rootOfPostingTree[i]);
658  }
659 
660  if (blkno == InvalidBlockNumber) /* rightmost page */
661  break;
662 
663  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
664  RBM_NORMAL, info->strategy);
665  LockBuffer(buffer, GIN_EXCLUSIVE);
666  }
667 
669 
670  return gvs.result;
671 }
#define GIN_UNLOCK
Definition: gin_private.h:43
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:407
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
Relation index
Definition: ginvacuum.c:30
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:640
BufferAccessStrategy strategy
Definition: ginvacuum.c:35
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
BufferAccessStrategy strategy
Definition: genam.h:51
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
Relation index
Definition: genam.h:46
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
IndexBulkDeleteResult * result
Definition: ginvacuum.c:31
Definition: type.h:89
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
static void xlogVacuumPage(Relation index, Buffer buffer)
Definition: ginvacuum.c:90
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:48
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
static Page ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
Definition: ginvacuum.c:442
IndexBulkDeleteCallback callback
Definition: ginvacuum.c:32
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:88
unsigned int uint32
Definition: c.h:325
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
void * callback_state
Definition: ginvacuum.c:33
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3295
#define GIN_SHARE
Definition: gin_private.h:44
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
void * palloc0(Size size)
Definition: mcxt.c:955
struct IndexTupleData IndexTupleData
#define GIN_EXCLUSIVE
Definition: gin_private.h:45
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define GinGetDownlink(itup)
Definition: ginblock.h:251
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition: ginfast.c:762
#define GinPageIsData(page)
Definition: ginblock.h:114
#define Assert(condition)
Definition: c.h:699
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#define InvalidBlockNumber
Definition: block.h:33
int i
static void ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
Definition: ginvacuum.c:431
void vacuum_delay_point(void)
Definition: vacuum.c:1672
MemoryContext tmpCxt
Definition: ginvacuum.c:36
double num_index_tuples
Definition: genam.h:76
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:336
#define GIN_ROOT_BLKNO
Definition: ginblock.h:51
Pointer Page
Definition: bufpage.h:74
GinState ginstate
Definition: ginvacuum.c:34

◆ ginCompareAttEntries()

int ginCompareAttEntries ( GinState ginstate,
OffsetNumber  attnuma,
Datum  a,
GinNullCategory  categorya,
OffsetNumber  attnumb,
Datum  b,
GinNullCategory  categoryb 
)

Definition at line 415 of file ginutil.c.

References ginCompareEntries().

Referenced by cmpEntryAccumulator(), entryIsMoveRight(), entryLocateEntry(), and entryLocateLeafEntry().

418 {
419  /* attribute number is the first sort key */
420  if (attnuma != attnumb)
421  return (attnuma < attnumb) ? -1 : 1;
422 
423  return ginCompareEntries(ginstate, attnuma, a, categorya, b, categoryb);
424 }
int ginCompareEntries(GinState *ginstate, OffsetNumber attnum, Datum a, GinNullCategory categorya, Datum b, GinNullCategory categoryb)
Definition: ginutil.c:393

◆ ginCompareEntries()

int ginCompareEntries ( GinState ginstate,
OffsetNumber  attnum,
Datum  a,
GinNullCategory  categorya,
Datum  b,
GinNullCategory  categoryb 
)

Definition at line 393 of file ginutil.c.

References GinState::compareFn, DatumGetInt32, FunctionCall2Coll(), GIN_CAT_NORM_KEY, and GinState::supportCollation.

Referenced by collectMatchBitmap(), collectMatchesForHeapRow(), ginCompareAttEntries(), and ginFillScanEntry().

396 {
397  /* if not of same null category, sort by that first */
398  if (categorya != categoryb)
399  return (categorya < categoryb) ? -1 : 1;
400 
401  /* all null items in same category are equal */
402  if (categorya != GIN_CAT_NORM_KEY)
403  return 0;
404 
405  /* both not null, so safe to call the compareFn */
406  return DatumGetInt32(FunctionCall2Coll(&ginstate->compareFn[attnum - 1],
407  ginstate->supportCollation[attnum - 1],
408  a, b));
409 }
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gin_private.h:82
#define DatumGetInt32(X)
Definition: postgres.h:457
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1133
#define GIN_CAT_NORM_KEY
Definition: ginblock.h:202
int16 attnum
Definition: pg_attribute.h:79
FmgrInfo compareFn[INDEX_MAX_KEYS]
Definition: gin_private.h:73

◆ ginCompareItemPointers()

static int ginCompareItemPointers ( ItemPointer  a,
ItemPointer  b 
)
inlinestatic

Definition at line 460 of file gin_private.h.

References buffer, GinItemPointerGetBlockNumber, GinItemPointerGetOffsetNumber, and ginTraverseLock().

Referenced by addItemsToLeaf(), dataBeginPlaceToPageLeaf(), dataIsMoveRight(), dataLocateItem(), entryGetItem(), entryLoadMoreItems(), ginCombineData(), GinDataLeafPageGetItems(), ginMergeItemPointers(), ginPostingListDecodeAllSegments(), keyGetItem(), qsortCompareItemPointers(), and scanGetItem().

461 {
462  uint64 ia = (uint64) GinItemPointerGetBlockNumber(a) << 32 | GinItemPointerGetOffsetNumber(a);
463  uint64 ib = (uint64) GinItemPointerGetBlockNumber(b) << 32 | GinItemPointerGetOffsetNumber(b);
464 
465  if (ia == ib)
466  return 0;
467  else if (ia > ib)
468  return 1;
469  else
470  return -1;
471 }
#define GinItemPointerGetOffsetNumber(pointer)
Definition: ginblock.h:137
#define GinItemPointerGetBlockNumber(pointer)
Definition: ginblock.h:134

◆ ginCompressPostingList()

GinPostingList* ginCompressPostingList ( const ItemPointer  ptrs,
int  nptrs,
int  maxsize,
int *  nwritten 
)

Definition at line 180 of file ginpostinglist.c.

References Assert, buf, GinPostingList::bytes, encode_varbyte(), GinPostingList::first, ginPostingListDecode(), i, itemptr_to_uint64(), GinPostingList::nbytes, offsetof, palloc(), pfree(), SHORTALIGN, SHORTALIGN_DOWN, SizeOfGinPostingList, and val.

Referenced by addItemPointersToLeafTuple(), buildFreshLeafTuple(), createPostingTree(), ginRedoRecompress(), ginVacuumEntryPage(), ginVacuumPostingTreeLeaf(), and leafRepackItems().

182 {
183  uint64 prev;
184  int totalpacked = 0;
185  int maxbytes;
186  GinPostingList *result;
187  unsigned char *ptr;
188  unsigned char *endptr;
189 
190  maxsize = SHORTALIGN_DOWN(maxsize);
191 
192  result = palloc(maxsize);
193 
194  maxbytes = maxsize - offsetof(GinPostingList, bytes);
195  Assert(maxbytes > 0);
196 
197  /* Store the first special item */
198  result->first = ipd[0];
199 
200  prev = itemptr_to_uint64(&result->first);
201 
202  ptr = result->bytes;
203  endptr = result->bytes + maxbytes;
204  for (totalpacked = 1; totalpacked < nipd; totalpacked++)
205  {
206  uint64 val = itemptr_to_uint64(&ipd[totalpacked]);
207  uint64 delta = val - prev;
208 
209  Assert(val > prev);
210 
211  if (endptr - ptr >= 6)
212  encode_varbyte(delta, &ptr);
213  else
214  {
215  /*
216  * There are less than 6 bytes left. Have to check if the next
217  * item fits in that space before writing it out.
218  */
219  unsigned char buf[6];
220  unsigned char *p = buf;
221 
222  encode_varbyte(delta, &p);
223  if (p - buf > (endptr - ptr))
224  break; /* output is full */
225 
226  memcpy(ptr, buf, p - buf);
227  ptr += (p - buf);
228  }
229  prev = val;
230  }
231  result->nbytes = ptr - result->bytes;
232 
233  /*
234  * If we wrote an odd number of bytes, zero out the padding byte at the
235  * end.
236  */
237  if (result->nbytes != SHORTALIGN(result->nbytes))
238  result->bytes[result->nbytes] = 0;
239 
240  if (nwritten)
241  *nwritten = totalpacked;
242 
243  Assert(SizeOfGinPostingList(result) <= maxsize);
244 
245  /*
246  * Check that the encoded segment decodes back to the original items.
247  */
248 #if defined (CHECK_ENCODING_ROUNDTRIP)
249  {
250  int ndecoded;
251  ItemPointer tmp = ginPostingListDecode(result, &ndecoded);
252  int i;
253 
254  Assert(ndecoded == totalpacked);
255  for (i = 0; i < ndecoded; i++)
256  Assert(memcmp(&tmp[i], &ipd[i], sizeof(ItemPointerData)) == 0);
257  pfree(tmp);
258  }
259 #endif
260 
261  return result;
262 }
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded)
#define SHORTALIGN_DOWN(LEN)
Definition: c.h:660
ItemPointerData first
Definition: ginblock.h:331
void pfree(void *pointer)
Definition: mcxt.c:1031
unsigned char bytes[FLEXIBLE_ARRAY_MEMBER]
Definition: ginblock.h:333
static char * buf
Definition: pg_test_fsync.c:67
uint16 nbytes
Definition: ginblock.h:332
#define Assert(condition)
Definition: c.h:699
static uint64 itemptr_to_uint64(const ItemPointer iptr)
static void encode_varbyte(uint64 val, unsigned char **ptr)
void * palloc(Size size)
Definition: mcxt.c:924
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:336
int i
#define SHORTALIGN(LEN)
Definition: c.h:648
long val
Definition: informix.c:689
#define offsetof(type, field)
Definition: c.h:622

◆ 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:186
void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset)
Definition: gindatapage.c:377
ItemPointerData key
Definition: ginblock.h:180
#define InvalidOffsetNumber
Definition: off.h:26
#define GinDataPageGetRightBound(page)
Definition: ginblock.h:282

◆ 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:211
#define GinPageIsCompressed(page)
Definition: ginblock.h:120
ItemPointerData first
Definition: ginblock.h:331
char * Pointer
Definition: c.h:302
#define GinNextPostingListSegment(cur)
Definition: ginblock.h:337
#define GinDataLeafPageGetPostingListSize(page)
Definition: ginblock.h:274
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:272
size_t Size
Definition: c.h:433
static int ginCompareItemPointers(ItemPointer a, ItemPointer b)
Definition: gin_private.h:460
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:120
#define GinDataLeafPageGetPostingListSize(page)
Definition: ginblock.h:274
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:272
size_t Size
Definition: c.h:433
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:109
uint16 OffsetNumber
Definition: off.h:24
#define GinDataPageSetDataSize(page, size)
Definition: ginblock.h:303
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:292
#define memmove(d, s, c)
Definition: c.h:1135
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define InvalidOffsetNumber
Definition: off.h:26
#define PostingItemGetBlockNumber(pointer)
Definition: ginblock.h:183
#define Assert(condition)
Definition: c.h:699
#define InvalidBlockNumber
Definition: block.h:33

◆ ginendscan()

void ginendscan ( IndexScanDesc  scan)

Definition at line 429 of file ginscan.c.

References ginFreeScanKeys(), GinScanOpaqueData::keyCtx, MemoryContextDelete(), IndexScanDescData::opaque, pfree(), and GinScanOpaqueData::tempCtx.

Referenced by ginhandler().

430 {
431  GinScanOpaque so = (GinScanOpaque) scan->opaque;
432 
433  ginFreeScanKeys(so);
434 
437 
438  pfree(so);
439 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
void pfree(void *pointer)
Definition: mcxt.c:1031
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:363
MemoryContext keyCtx
Definition: gin_private.h:358
MemoryContext tempCtx
Definition: gin_private.h:348
void ginFreeScanKeys(GinScanOpaque so)
Definition: ginscan.c:232

◆ ginEntryFillRoot()

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

Definition at line 721 of file ginentrypage.c.

References elog, ERROR, getRightMostTuple(), GinFormInteriorTuple(), IndexTupleSize, InvalidOffsetNumber, PageAddItem, and pfree().

Referenced by ginPrepareEntryScan().

724 {
725  IndexTuple itup;
726 
727  itup = GinFormInteriorTuple(getRightMostTuple(lpage), lpage, lblkno);
728  if (PageAddItem(root, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
729  elog(ERROR, "failed to add item to index root page");
730  pfree(itup);
731 
732  itup = GinFormInteriorTuple(getRightMostTuple(rpage), rpage, rblkno);
733  if (PageAddItem(root, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
734  elog(ERROR, "failed to add item to index root page");
735  pfree(itup);
736 }
Pointer Item
Definition: item.h:17
static IndexTuple getRightMostTuple(Page page)
Definition: ginentrypage.c:236
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:412
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ERROR
Definition: elog.h:43
static IndexTuple GinFormInteriorTuple(IndexTuple itup, Page page, BlockNumber childblk)
Definition: ginentrypage.c:202
#define InvalidOffsetNumber
Definition: off.h:26
#define elog
Definition: elog.h:219
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ ginEntryInsert()

void ginEntryInsert ( GinState ginstate,
OffsetNumber  attnum,
Datum  key,
GinNullCategory  category,
ItemPointerData items,
uint32  nitem,
GinStatsData buildStats 
)

Definition at line 179 of file gininsert.c.

References addItemPointersToLeafTuple(), GinBtreeStack::buffer, BufferGetPage, buildFreshLeafTuple(), CheckForSerializableConflictIn(), GinBtreeEntryInsertData::entry, GinBtreeData::findItem, freeGinBtreeStack(), GIN_UNLOCK, ginFindLeafPage(), GinGetPostingTree, ginInsertItemPointers(), ginInsertValue(), GinIsPostingTree, ginPrepareEntryScan(), GinState::index, GinBtreeEntryInsertData::isDelete, LockBuffer(), GinStatsData::nEntries, GinBtreeStack::off, PageGetItem, PageGetItemId, and pfree().

Referenced by ginbuild(), ginBuildCallback(), ginHeapTupleInsert(), and ginInsertCleanup().

183 {
184  GinBtreeData btree;
185  GinBtreeEntryInsertData insertdata;
186  GinBtreeStack *stack;
187  IndexTuple itup;
188  Page page;
189 
190  insertdata.isDelete = false;
191 
192  /* During index build, count the to-be-inserted entry */
193  if (buildStats)
194  buildStats->nEntries++;
195 
196  ginPrepareEntryScan(&btree, attnum, key, category, ginstate);
197 
198  stack = ginFindLeafPage(&btree, false, NULL);
199  page = BufferGetPage(stack->buffer);
200 
201  if (btree.findItem(&btree, stack))
202  {
203  /* found pre-existing entry */
204  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off));
205 
206  if (GinIsPostingTree(itup))
207  {
208  /* add entries to existing posting tree */
209  BlockNumber rootPostingTree = GinGetPostingTree(itup);
210 
211  /* release all stack */
212  LockBuffer(stack->buffer, GIN_UNLOCK);
213  freeGinBtreeStack(stack);
214 
215  /* insert into posting tree */
216  ginInsertItemPointers(ginstate->index, rootPostingTree,
217  items, nitem,
218  buildStats);
219  return;
220  }
221 
222  CheckForSerializableConflictIn(ginstate->index, NULL, stack->buffer);
223  /* modify an existing leaf entry */
224  itup = addItemPointersToLeafTuple(ginstate, itup,
225  items, nitem, buildStats, stack->buffer);
226 
227  insertdata.isDelete = true;
228  }
229  else
230  {
231  CheckForSerializableConflictIn(ginstate->index, NULL, stack->buffer);
232  /* no match, so construct a new leaf entry */
233  itup = buildFreshLeafTuple(ginstate, attnum, key, category,
234  items, nitem, buildStats, stack->buffer);
235  }
236 
237  /* Insert the new or modified leaf tuple */
238  insertdata.entry = itup;
239  ginInsertValue(&btree, stack, &insertdata, buildStats);
240  pfree(itup);
241 }
#define GIN_UNLOCK
Definition: gin_private.h:43
void ginInsertItemPointers(Relation index, BlockNumber rootBlkno, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gindatapage.c:1894
Relation index
Definition: gin_private.h:53
OffsetNumber off
Definition: gin_private.h:126
int64 nEntries
Definition: gin.h:47
uint32 BlockNumber
Definition: block.h:31
void CheckForSerializableConflictIn(Relation relation, HeapTuple tuple, Buffer buffer)
Definition: predicate.c:4280
static IndexTuple addItemPointersToLeafTuple(GinState *ginstate, IndexTuple old, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats, Buffer buffer)
Definition: gininsert.c:49
bool(* findItem)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:149
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, Snapshot snapshot)
Definition: ginbtree.c:77
void pfree(void *pointer)
Definition: mcxt.c:1031
IndexTupleData * IndexTuple
Definition: itup.h:53
static IndexTuple buildFreshLeafTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats, Buffer buffer)
Definition: gininsert.c:129
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum, Datum key, GinNullCategory category, GinState *ginstate)
Definition: ginentrypage.c:745
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
void ginInsertValue(GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
Definition: ginbtree.c:780
int16 attnum
Definition: pg_attribute.h:79
#define GinGetPostingTree(itup)
Definition: ginblock.h:227
#define GinIsPostingTree(itup)
Definition: ginblock.h:225
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:197
#define PageGetItem(page, itemId)
Definition: bufpage.h:336
Pointer Page
Definition: bufpage.h:74

◆ ginExtractEntries()

Datum* ginExtractEntries ( GinState ginstate,
OffsetNumber  attnum,
Datum  value,
bool  isNull,
int32 nentries,
GinNullCategory **  categories 
)

Definition at line 488 of file ginutil.c.

References arg, cmpEntriesArg::cmpDatumFunc, cmpEntries(), cmpEntriesArg::collation, GinState::compareFn, keyEntryData::datum, DatumGetPointer, GinState::extractValueFn, FunctionCall3Coll(), GIN_CAT_EMPTY_ITEM, GIN_CAT_NORM_KEY, GIN_CAT_NULL_ITEM, GIN_CAT_NULL_KEY, cmpEntriesArg::haveDups, i, keyEntryData::isnull, palloc(), palloc0(), pfree(), PointerGetDatum, qsort_arg(), and GinState::supportCollation.

Referenced by ginHeapTupleBulkInsert(), ginHeapTupleFastCollect(), and ginHeapTupleInsert().

491 {
492  Datum *entries;
493  bool *nullFlags;
494  int32 i;
495 
496  /*
497  * We don't call the extractValueFn on a null item. Instead generate a
498  * placeholder.
499  */
500  if (isNull)
501  {
502  *nentries = 1;
503  entries = (Datum *) palloc(sizeof(Datum));
504  entries[0] = (Datum) 0;
505  *categories = (GinNullCategory *) palloc(sizeof(GinNullCategory));
506  (*categories)[0] = GIN_CAT_NULL_ITEM;
507  return entries;
508  }
509 
510  /* OK, call the opclass's extractValueFn */
511  nullFlags = NULL; /* in case extractValue doesn't set it */
512  entries = (Datum *)
514  ginstate->supportCollation[attnum - 1],
515  value,
516  PointerGetDatum(nentries),
517  PointerGetDatum(&nullFlags)));
518 
519  /*
520  * Generate a placeholder if the item contained no keys.
521  */
522  if (entries == NULL || *nentries <= 0)
523  {
524  *nentries = 1;
525  entries = (Datum *) palloc(sizeof(Datum));
526  entries[0] = (Datum) 0;
527  *categories = (GinNullCategory *) palloc(sizeof(GinNullCategory));
528  (*categories)[0] = GIN_CAT_EMPTY_ITEM;
529  return entries;
530  }
531 
532  /*
533  * If the extractValueFn didn't create a nullFlags array, create one,
534  * assuming that everything's non-null.
535  */
536  if (nullFlags == NULL)
537  nullFlags = (bool *) palloc0(*nentries * sizeof(bool));
538 
539  /*
540  * If there's more than one key, sort and unique-ify.
541  *
542  * XXX Using qsort here is notationally painful, and the overhead is
543  * pretty bad too. For small numbers of keys it'd likely be better to use
544  * a simple insertion sort.
545  */
546  if (*nentries > 1)
547  {
548  keyEntryData *keydata;
550 
551  keydata = (keyEntryData *) palloc(*nentries * sizeof(keyEntryData));
552  for (i = 0; i < *nentries; i++)
553  {
554  keydata[i].datum = entries[i];
555  keydata[i].isnull = nullFlags[i];
556  }
557 
558  arg.cmpDatumFunc = &ginstate->compareFn[attnum - 1];
559  arg.collation = ginstate->supportCollation[attnum - 1];
560  arg.haveDups = false;
561  qsort_arg(keydata, *nentries, sizeof(keyEntryData),
562  cmpEntries, (void *) &arg);
563 
564  if (arg.haveDups)
565  {
566  /* there are duplicates, must get rid of 'em */
567  int32 j;
568 
569  entries[0] = keydata[0].datum;
570  nullFlags[0] = keydata[0].isnull;
571  j = 1;
572  for (i = 1; i < *nentries; i++)
573  {
574  if (cmpEntries(&keydata[i - 1], &keydata[i], &arg) != 0)
575  {
576  entries[j] = keydata[i].datum;
577  nullFlags[j] = keydata[i].isnull;
578  j++;
579  }
580  }
581  *nentries = j;
582  }
583  else
584  {
585  /* easy, no duplicates */
586  for (i = 0; i < *nentries; i++)
587  {
588  entries[i] = keydata[i].datum;
589  nullFlags[i] = keydata[i].isnull;
590  }
591  }
592 
593  pfree(keydata);
594  }
595 
596  /*
597  * Create GinNullCategory representation from nullFlags.
598  */
599  *categories = (GinNullCategory *) palloc0(*nentries * sizeof(GinNullCategory));
600  for (i = 0; i < *nentries; i++)
601  (*categories)[i] = (nullFlags[i] ? GIN_CAT_NULL_KEY : GIN_CAT_NORM_KEY);
602 
603  return entries;
604 }
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gin_private.h:82
FmgrInfo * cmpDatumFunc
Definition: ginutil.c:442
bool isnull
Definition: ginutil.c:437
#define PointerGetDatum(X)
Definition: postgres.h:541
FmgrInfo extractValueFn[INDEX_MAX_KEYS]
Definition: gin_private.h:74
Datum datum
Definition: ginutil.c:436
signed int int32
Definition: c.h:313
void pfree(void *pointer)
Definition: mcxt.c:1031
signed char GinNullCategory
Definition: ginblock.h:200
bool haveDups
Definition: ginutil.c:444
#define GIN_CAT_NORM_KEY
Definition: ginblock.h:202
void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
Definition: qsort_arg.c:113
#define GIN_CAT_NULL_KEY
Definition: ginblock.h:203
void * palloc0(Size size)
Definition: mcxt.c:955
uintptr_t Datum
Definition: postgres.h:367
#define GIN_CAT_NULL_ITEM
Definition: ginblock.h:205
static struct @131 value
int16 attnum
Definition: pg_attribute.h:79
Datum FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition: fmgr.c:1155
Oid collation
Definition: ginutil.c:443
#define DatumGetPointer(X)
Definition: postgres.h:534
void * palloc(Size size)
Definition: mcxt.c:924
int i
void * arg
#define GIN_CAT_EMPTY_ITEM
Definition: ginblock.h:204
static int cmpEntries(const void *a, const void *b, void *arg)
Definition: ginutil.c:448
FmgrInfo compareFn[INDEX_MAX_KEYS]
Definition: gin_private.h:73

◆ ginFindLeafPage()

GinBtreeStack* ginFindLeafPage ( GinBtree  btree,
bool  searchMode,
Snapshot  snapshot 
)

Definition at line 77 of file ginbtree.c.

References Assert, GinBtreeStack::blkno, GinBtreeStack::buffer, BufferGetPage, CheckForSerializableConflictIn(), GinBtreeData::findChildPage, GinBtreeData::fullScan, GIN_UNLOCK, ginFinishSplit(), GinPageGetOpaque, GinPageIsIncompleteSplit, GinPageIsLeaf, ginStepRight(), ginTraverseLock(), GinBtreeData::index, InvalidBlockNumber, InvalidOffsetNumber, GinBtreeData::isMoveRight, LockBuffer(), GinBtreeStack::off, palloc(), GinBtreeStack::parent, GinBtreeStack::predictNumber, ReadBuffer(), ReleaseAndReadBuffer(), GinBtreeData::rootBlkno, and TestForOldSnapshot().

Referenced by entryLoadMoreItems(), ginEntryInsert(), ginInsertItemPointers(), ginScanBeginPostingTree(), and startScanEntry().

78 {
79  GinBtreeStack *stack;
80 
81  stack = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
82  stack->blkno = btree->rootBlkno;
83  stack->buffer = ReadBuffer(btree->index, btree->rootBlkno);
84  stack->parent = NULL;
85  stack->predictNumber = 1;
86 
87  if (!searchMode)
88  CheckForSerializableConflictIn(btree->index, NULL, stack->buffer);
89 
90  for (;;)
91  {
92  Page page;
93  BlockNumber child;
94  int access;
95 
96  stack->off = InvalidOffsetNumber;
97 
98  page = BufferGetPage(stack->buffer);
99  TestForOldSnapshot(snapshot, btree->index, page);
100 
101  access = ginTraverseLock(stack->buffer, searchMode);
102 
103  /*
104  * If we're going to modify the tree, finish any incomplete splits we
105  * encounter on the way.
106  */
107  if (!searchMode && GinPageIsIncompleteSplit(page))
108  ginFinishSplit(btree, stack, false, NULL);
109 
110  /*
111  * ok, page is correctly locked, we should check to move right ..,
112  * root never has a right link, so small optimization
113  */
114  while (btree->fullScan == false && stack->blkno != btree->rootBlkno &&
115  btree->isMoveRight(btree, page))
116  {
117  BlockNumber rightlink = GinPageGetOpaque(page)->rightlink;
118 
119  if (rightlink == InvalidBlockNumber)
120  /* rightmost page */
121  break;
122 
123  stack->buffer = ginStepRight(stack->buffer, btree->index, access);
124  stack->blkno = rightlink;
125  page = BufferGetPage(stack->buffer);
126  TestForOldSnapshot(snapshot, btree->index, page);
127 
128  if (!searchMode && GinPageIsIncompleteSplit(page))
129  ginFinishSplit(btree, stack, false, NULL);
130  }
131 
132  if (GinPageIsLeaf(page)) /* we found, return locked page */
133  return stack;
134 
135  /* now we have correct buffer, try to find child */
136  child = btree->findChildPage(btree, stack);
137 
138  LockBuffer(stack->buffer, GIN_UNLOCK);
139  Assert(child != InvalidBlockNumber);
140  Assert(stack->blkno != child);
141 
142  if (searchMode)
143  {
144  /* in search mode we may forget path to leaf */
145  stack->blkno = child;
146  stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno);
147  }
148  else
149  {
150  GinBtreeStack *ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
151 
152  ptr->parent = stack;
153  stack = ptr;
154  stack->blkno = child;
155  stack->buffer = ReadBuffer(btree->index, stack->blkno);
156  stack->predictNumber = 1;
157  }
158  }
159 }
#define GIN_UNLOCK
Definition: gin_private.h:43
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:265
OffsetNumber off
Definition: gin_private.h:126
#define GinPageIsIncompleteSplit(page)
Definition: ginblock.h:126
bool(* isMoveRight)(GinBtree, Page)
Definition: gin_private.h:148
static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack, GinStatsData *buildStats)
Definition: ginbtree.c:671
BlockNumber rootBlkno
Definition: gin_private.h:161
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
void CheckForSerializableConflictIn(Relation relation, HeapTuple tuple, Buffer buffer)
Definition: predicate.c:4280
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:146
Buffer ginStepRight(Buffer buffer, Relation index, int lockmode)
Definition: ginbtree.c:169
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
struct GinBtreeStack * parent
Definition: gin_private.h:130
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
Relation index
Definition: gin_private.h:160
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:699
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define InvalidBlockNumber
Definition: block.h:33
Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, BlockNumber blockNum)
Definition: bufmgr.c:1513
BlockNumber blkno
Definition: gin_private.h:124
uint32 predictNumber
Definition: gin_private.h:129
void * palloc(Size size)
Definition: mcxt.c:924
Pointer Page
Definition: bufpage.h:74
int ginTraverseLock(Buffer buffer, bool searchMode)
Definition: ginbtree.c:36

◆ GinFormTuple()

IndexTuple GinFormTuple ( GinState ginstate,
OffsetNumber  attnum,
Datum  key,
GinNullCategory  category,
Pointer  data,
Size  dataSize,
int  nipd,
bool  errorTooBig 
)

Definition at line 45 of file ginentrypage.c.

References Assert, ereport, errcode(), errmsg(), ERROR, GIN_CAT_NORM_KEY, GinCategoryOffset, GinGetPosting, GinMaxItemSize, GinSetNPosting, GinSetNullCategory, GinSetPostingOffset, GinState::index, index_form_tuple(), INDEX_SIZE_MASK, IndexTupleHasNulls, IndexTupleSize, Max, MAXALIGN, GinState::oneCol, pfree(), RelationGetRelationName, repalloc(), SHORTALIGN, IndexTupleData::t_info, GinState::tupdesc, and UInt16GetDatum.

Referenced by addItemPointersToLeafTuple(), buildFreshLeafTuple(), ginHeapTupleFastCollect(), and ginVacuumEntryPage().

49 {
50  Datum datums[2];
51  bool isnull[2];
52  IndexTuple itup;
53  uint32 newsize;
54 
55  /* Build the basic tuple: optional column number, plus key datum */
56  if (ginstate->oneCol)
57  {
58  datums[0] = key;
59  isnull[0] = (category != GIN_CAT_NORM_KEY);
60  }
61  else
62  {
63  datums[0] = UInt16GetDatum(attnum);
64  isnull[0] = false;
65  datums[1] = key;
66  isnull[1] = (category != GIN_CAT_NORM_KEY);
67  }
68 
69  itup = index_form_tuple(ginstate->tupdesc[attnum - 1], datums, isnull);
70 
71  /*
72  * Determine and store offset to the posting list, making sure there is
73  * room for the category byte if needed.
74  *
75  * Note: because index_form_tuple MAXALIGNs the tuple size, there may well
76  * be some wasted pad space. Is it worth recomputing the data length to
77  * prevent that? That would also allow us to Assert that the real data
78  * doesn't overlap the GinNullCategory byte, which this code currently
79  * takes on faith.
80  */
81  newsize = IndexTupleSize(itup);
82 
83  if (IndexTupleHasNulls(itup))
84  {
85  uint32 minsize;
86 
87  Assert(category != GIN_CAT_NORM_KEY);
88  minsize = GinCategoryOffset(itup, ginstate) + sizeof(GinNullCategory);
89  newsize = Max(newsize, minsize);
90  }
91 
92  newsize = SHORTALIGN(newsize);
93 
94  GinSetPostingOffset(itup, newsize);
95  GinSetNPosting(itup, nipd);
96 
97  /*
98  * Add space needed for posting list, if any. Then check that the tuple
99  * won't be too big to store.
100  */
101  newsize += dataSize;
102 
103  newsize = MAXALIGN(newsize);
104 
105  if (newsize > GinMaxItemSize)
106  {
107  if (errorTooBig)
108  ereport(ERROR,
109  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
110  errmsg("index row size %zu exceeds maximum %zu for index \"%s\"",
111  (Size) newsize, (Size) GinMaxItemSize,
112  RelationGetRelationName(ginstate->index))));
113  pfree(itup);
114  return NULL;
115  }
116 
117  /*
118  * Resize tuple if needed
119  */
120  if (newsize != IndexTupleSize(itup))
121  {
122  itup = repalloc(itup, newsize);
123 
124  /*
125  * PostgreSQL 9.3 and earlier did not clear this new space, so we
126  * might find uninitialized padding when reading tuples from disk.
127  */
128  memset((char *) itup + IndexTupleSize(itup),
129  0, newsize - IndexTupleSize(itup));
130  /* set new size in tuple header */
131  itup->t_info &= ~INDEX_SIZE_MASK;
132  itup->t_info |= newsize;
133  }
134 
135  /*
136  * Copy in the posting list, if provided
137  */
138  if (data)
139  {
140  char *ptr = GinGetPosting(itup);
141 
142  memcpy(ptr, data, dataSize);
143  }
144 
145  /*
146  * Insert category byte, if needed
147  */
148  if (category != GIN_CAT_NORM_KEY)
149  {
150  Assert(IndexTupleHasNulls(itup));
151  GinSetNullCategory(itup, ginstate, category);
152  }
153  return itup;
154 }
#define GinSetNPosting(itup, n)
Definition: ginblock.h:223
Relation index
Definition: gin_private.h:53
#define INDEX_SIZE_MASK
Definition: itup.h:65
int errcode(int sqlerrcode)
Definition: elog.c:575
#define IndexTupleHasNulls(itup)
Definition: itup.h:72
#define GinGetPosting(itup)
Definition: ginblock.h:232
IndexTuple index_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: indextuple.c:40
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ERROR
Definition: elog.h:43
signed char GinNullCategory
Definition: ginblock.h:200
#define GinSetPostingOffset(itup, n)
Definition: ginblock.h:231
#define GIN_CAT_NORM_KEY
Definition: ginblock.h:202
#define RelationGetRelationName(relation)
Definition: rel.h:441
unsigned int uint32
Definition: c.h:325
#define ereport(elevel, rest)
Definition: elog.h:122
uintptr_t Datum
Definition: postgres.h:367
TupleDesc tupdesc[INDEX_MAX_KEYS]
Definition: gin_private.h:68
int16 attnum
Definition: pg_attribute.h:79
#define Max(x, y)
Definition: c.h:851
#define Assert(condition)
Definition: c.h:699
#define GinSetNullCategory(itup, ginstate, c)
Definition: ginblock.h:216
size_t Size
Definition: c.h:433
#define MAXALIGN(LEN)
Definition: c.h:652
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1044
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define GinMaxItemSize
Definition: ginblock.h:242
unsigned short t_info
Definition: itup.h:49
#define SHORTALIGN(LEN)
Definition: c.h:648
bool oneCol
Definition: gin_private.h:54
#define GinCategoryOffset(itup, ginstate)
Definition: ginblock.h:211
#define UInt16GetDatum(X)
Definition: postgres.h:450
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ ginFreeScanKeys()

void ginFreeScanKeys ( GinScanOpaque  so)

Definition at line 232 of file ginscan.c.

References GinScanEntryData::buffer, GinScanOpaqueData::entries, i, InvalidBuffer, GinScanOpaqueData::keyCtx, GinScanOpaqueData::keys, GinScanEntryData::list, GinScanEntryData::matchBitmap, GinScanEntryData::matchIterator, MemoryContextResetAndDeleteChildren, GinScanOpaqueData::nkeys, pfree(), ReleaseBuffer(), tbm_end_iterate(), tbm_free(), and GinScanOpaqueData::totalentries.

Referenced by ginendscan(), gingetbitmap(), and ginrescan().

233 {
234  uint32 i;
235 
236  if (so->keys == NULL)
237  return;
238 
239  for (i = 0; i < so->totalentries; i++)
240  {
241  GinScanEntry entry = so->entries[i];
242 
243  if (entry->buffer != InvalidBuffer)
244  ReleaseBuffer(entry->buffer);
245  if (entry->list)
246  pfree(entry->list);
247  if (entry->matchIterator)
249  if (entry->matchBitmap)
250  tbm_free(entry->matchBitmap);
251  }
252 
254 
255  so->keys = NULL;
256  so->nkeys = 0;
257  so->entries = NULL;
258  so->totalentries = 0;
259 }
void tbm_end_iterate(TBMIterator *iterator)
Definition: tidbitmap.c:1145
TBMIterator * matchIterator
Definition: gin_private.h:332
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
ItemPointerData * list
Definition: gin_private.h:336
void pfree(void *pointer)
Definition: mcxt.c:1031
void tbm_free(TIDBitmap *tbm)
Definition: tidbitmap.c:321
MemoryContext keyCtx
Definition: gin_private.h:358
unsigned int uint32
Definition: c.h:325
TIDBitmap * matchBitmap
Definition: gin_private.h:331
GinScanKey keys
Definition: gin_private.h:351
#define MemoryContextResetAndDeleteChildren(ctx)
Definition: memutils.h:67
GinScanEntry * entries
Definition: gin_private.h:354
int i

◆ ginGetBAEntry()

ItemPointerData* ginGetBAEntry ( BuildAccumulator accum,
OffsetNumber attnum,
Datum key,
GinNullCategory category,
uint32 n 
)

Definition at line 268 of file ginbulk.c.

References Assert, GinEntryAccumulator::attnum, GinEntryAccumulator::category, GinEntryAccumulator::count, GinEntryAccumulator::key, sort-test::list, GinEntryAccumulator::list, qsort, qsortCompareItemPointers(), rb_iterate(), GinEntryAccumulator::shouldSort, and BuildAccumulator::tree_walk.

Referenced by ginbuild(), ginBuildCallback(), and ginInsertCleanup().

271 {
272  GinEntryAccumulator *entry;
274 
275  entry = (GinEntryAccumulator *) rb_iterate(&accum->tree_walk);
276 
277  if (entry == NULL)
278  return NULL; /* no more entries */
279 
280  *attnum = entry->attnum;
281  *key = entry->key;
282  *category = entry->category;
283  list = entry->list;
284  *n = entry->count;
285 
286  Assert(list != NULL && entry->count > 0);
287 
288  if (entry->shouldSort && entry->count > 1)
289  qsort(list, entry->count, sizeof(ItemPointerData),
291 
292  return list;
293 }
OffsetNumber attnum
Definition: gin_private.h:397
RBNode * rb_iterate(RBTreeIterator *iter)
Definition: rbtree.c:761
GinNullCategory category
Definition: gin_private.h:396
int16 attnum
Definition: pg_attribute.h:79
#define Assert(condition)
Definition: c.h:699
static int qsortCompareItemPointers(const void *a, const void *b)
Definition: ginbulk.c:246
RBTreeIterator tree_walk
Definition: gin_private.h:411
#define qsort(a, b, c, d)
Definition: port.h:421
ItemPointerData * list
Definition: gin_private.h:399

◆ gingetbitmap()

int64 gingetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

Definition at line 1849 of file ginget.c.

References CHECK_FOR_INTERRUPTS, ginFreeScanKeys(), GinIsVoidRes, ginNewScanKey(), ItemPointerGetBlockNumber, ItemPointerIsLossyPage, ItemPointerSetMin, IndexScanDescData::opaque, scanGetItem(), scanPendingInsert(), startScan(), tbm_add_page(), and tbm_add_tuples().

Referenced by ginhandler().

1850 {
1851  GinScanOpaque so = (GinScanOpaque) scan->opaque;
1852  int64 ntids;
1853  ItemPointerData iptr;
1854  bool recheck;
1855 
1856  /*
1857  * Set up the scan keys, and check for unsatisfiable query.
1858  */
1859  ginFreeScanKeys(so); /* there should be no keys yet, but just to be
1860  * sure */
1861  ginNewScanKey(scan);
1862 
1863  if (GinIsVoidRes(scan))
1864  return 0;
1865 
1866  ntids = 0;
1867 
1868  /*
1869  * First, scan the pending list and collect any matching entries into the
1870  * bitmap. After we scan a pending item, some other backend could post it
1871  * into the main index, and so we might visit it a second time during the
1872  * main scan. This is okay because we'll just re-set the same bit in the
1873  * bitmap. (The possibility of duplicate visits is a major reason why GIN
1874  * can't support the amgettuple API, however.) Note that it would not do
1875  * to scan the main index before the pending list, since concurrent
1876  * cleanup could then make us miss entries entirely.
1877  */
1878  scanPendingInsert(scan, tbm, &ntids);
1879 
1880  /*
1881  * Now scan the main index.
1882  */
1883  startScan(scan);
1884 
1885  ItemPointerSetMin(&iptr);
1886 
1887  for (;;)
1888  {
1890 
1891  if (!scanGetItem(scan, iptr, &iptr, &recheck))
1892  break;
1893 
1894  if (ItemPointerIsLossyPage(&iptr))
1896  else
1897  tbm_add_tuples(tbm, &iptr, 1, recheck);
1898  ntids++;
1899  }
1900 
1901  return ntids;
1902 }
static void scanPendingInsert(IndexScanDesc scan, TIDBitmap *tbm, int64 *ntids)
Definition: ginget.c:1754
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:376
#define ItemPointerIsLossyPage(p)
Definition: ginblock.h:169
static void startScan(IndexScanDesc scan)
Definition: ginget.c:584
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:363
#define ItemPointerSetMin(p)
Definition: ginblock.h:157
static bool scanGetItem(IndexScanDesc scan, ItemPointerData advancePast, ItemPointerData *item, bool *recheck)
Definition: ginget.c:1233
void ginNewScanKey(IndexScanDesc scan)
Definition: ginscan.c:262
#define GinIsVoidRes(s)
Definition: ginget.c:1846
void tbm_add_page(TIDBitmap *tbm, BlockNumber pageno)
Definition: tidbitmap.c:442
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
void ginFreeScanKeys(GinScanOpaque so)
Definition: ginscan.c:232

◆ ginHeapTupleFastCollect()

void ginHeapTupleFastCollect ( GinState ginstate,
GinTupleCollector collector,
OffsetNumber  attnum,
Datum  value,
bool  isNull,
ItemPointer  ht_ctid 
)

Definition at line 478 of file ginfast.c.

References KeyArray::categories, ginExtractEntries(), GinFormTuple(), i, IndexTupleSize, GinTupleCollector::lentuples, tupleDesc::natts, GinTupleCollector::ntuples, GinState::origTupdesc, palloc(), repalloc(), GinTupleCollector::sumsize, IndexTupleData::t_tid, and GinTupleCollector::tuples.

Referenced by gininsert().

482 {
483  Datum *entries;
484  GinNullCategory *categories;
485  int32 i,
486  nentries;
487 
488  /*
489  * Extract the key values that need to be inserted in the index
490  */
491  entries = ginExtractEntries(ginstate, attnum, value, isNull,
492  &nentries, &categories);
493 
494  /*
495  * Allocate/reallocate memory for storing collected tuples
496  */
497  if (collector->tuples == NULL)
498  {
499  collector->lentuples = nentries * ginstate->origTupdesc->natts;
500  collector->tuples = (IndexTuple *) palloc(sizeof(IndexTuple) * collector->lentuples);
501  }
502 
503  while (collector->ntuples + nentries > collector->lentuples)
504  {
505  collector->lentuples *= 2;
506  collector->tuples = (IndexTuple *) repalloc(collector->tuples,
507  sizeof(IndexTuple) * collector->lentuples);
508  }
509 
510  /*
511  * Build an index tuple for each key value, and add to array. In pending
512  * tuples we just stick the heap TID into t_tid.
513  */
514  for (i = 0; i < nentries; i++)
515  {
516  IndexTuple itup;
517 
518  itup = GinFormTuple(ginstate, attnum, entries[i], categories[i],
519  NULL, 0, 0, true);
520  itup->t_tid = *ht_ctid;
521  collector->tuples[collector->ntuples++] = itup;
522  collector->sumsize += IndexTupleSize(itup);
523  }
524 }
ItemPointerData t_tid
Definition: itup.h:37
int natts
Definition: tupdesc.h:82
signed int int32
Definition: c.h:313
signed char GinNullCategory
Definition: ginblock.h:200
IndexTuple * tuples
Definition: gin_private.h:428
uintptr_t Datum
Definition: postgres.h:367
static struct @131 value
int16 attnum
Definition: pg_attribute.h:79
IndexTuple GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, Pointer data, Size dataSize, int nipd, bool errorTooBig)
Definition: ginentrypage.c:45
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1044
void * palloc(Size size)
Definition: mcxt.c:924
int i
TupleDesc origTupdesc
Definition: gin_private.h:67
Datum * ginExtractEntries(GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, int32 *nentries, GinNullCategory **categories)
Definition: ginutil.c:488
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ ginHeapTupleFastInsert()

void ginHeapTupleFastInsert ( GinState ginstate,
GinTupleCollector collector 
)

Definition at line 223 of file ginfast.c.

References Assert, buffer, BufferGetPage, CheckForSerializableConflictIn(), elog, END_CRIT_SECTION, ERROR, FirstOffsetNumber, GIN_EXCLUSIVE, GIN_METAPAGE_BLKNO, GIN_PAGE_FREESIZE, GIN_UNLOCK, GinGetPendingListCleanupSize, ginInsertCleanup(), GinListPageSize, GinPageGetMeta, GinPageGetOpaque, GinMetaPageData::head, i, GinState::index, IndexTupleSize, InvalidBlockNumber, InvalidBuffer, InvalidOffsetNumber, LockBuffer(), makeSublist(), MarkBufferDirty(), ginxlogUpdateMeta::metadata, ginxlogUpdateMeta::newRightlink, ginxlogUpdateMeta::node, GinMetaPageData::nPendingHeapTuples, GinMetaPageData::nPendingPages, ginxlogUpdateMeta::ntuples, GinTupleCollector::ntuples, OffsetNumberNext, PageAddItem, PageGetExactFreeSpace(), PageGetMaxOffsetNumber, PageIsEmpty, PageSetLSN, palloc(), ginxlogUpdateMeta::prevTail, RelationData::rd_node, ReadBuffer(), REGBUF_STANDARD, REGBUF_WILL_INIT, RelationGetRelationName, RelationNeedsWAL, START_CRIT_SECTION, GinTupleCollector::sumsize, GinMetaPageData::tail, GinMetaPageData::tailFreeSize, GinTupleCollector::tuples, UnlockReleaseBuffer(), XLOG_GIN_UPDATE_META_PAGE, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by gininsert().

224 {
225  Relation index = ginstate->index;
226  Buffer metabuffer;
227  Page metapage;
228  GinMetaPageData *metadata = NULL;
230  Page page = NULL;
231  ginxlogUpdateMeta data;
232  bool separateList = false;
233  bool needCleanup = false;
234  int cleanupSize;
235  bool needWal;
236 
237  if (collector->ntuples == 0)
238  return;
239 
240  needWal = RelationNeedsWAL(index);
241 
242  data.node = index->rd_node;
243  data.ntuples = 0;
245 
246  metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
247  metapage = BufferGetPage(metabuffer);
248 
249  /*
250  * An insertion to the pending list could logically belong anywhere in
251  * the tree, so it conflicts with all serializable scans. All scans
252  * acquire a predicate lock on the metabuffer to represent that.
253  */
254  CheckForSerializableConflictIn(index, NULL, metabuffer);
255 
256  if (collector->sumsize + collector->ntuples * sizeof(ItemIdData) > GinListPageSize)
257  {
258  /*
259  * Total size is greater than one page => make sublist
260  */
261  separateList = true;
262  }
263  else
264  {
265  LockBuffer(metabuffer, GIN_EXCLUSIVE);
266  metadata = GinPageGetMeta(metapage);
267 
268  if (metadata->head == InvalidBlockNumber ||
269  collector->sumsize + collector->ntuples * sizeof(ItemIdData) > metadata->tailFreeSize)
270  {
271  /*
272  * Pending list is empty or total size is greater than freespace
273  * on tail page => make sublist
274  *
275  * We unlock metabuffer to keep high concurrency
276  */
277  separateList = true;
278  LockBuffer(metabuffer, GIN_UNLOCK);
279  }
280  }
281 
282  if (separateList)
283  {
284  /*
285  * We should make sublist separately and append it to the tail
286  */
287  GinMetaPageData sublist;
288 
289  memset(&sublist, 0, sizeof(GinMetaPageData));
290  makeSublist(index, collector->tuples, collector->ntuples, &sublist);
291 
292  if (needWal)
293  XLogBeginInsert();
294 
295  /*
296  * metapage was unlocked, see above
297  */
298  LockBuffer(metabuffer, GIN_EXCLUSIVE);
299  metadata = GinPageGetMeta(metapage);
300 
301  if (metadata->head == InvalidBlockNumber)
302  {
303  /*
304  * Main list is empty, so just insert sublist as main list
305  */
307 
308  metadata->head = sublist.head;
309  metadata->tail = sublist.tail;
310  metadata->tailFreeSize = sublist.tailFreeSize;
311 
312  metadata->nPendingPages = sublist.nPendingPages;
313  metadata->nPendingHeapTuples = sublist.nPendingHeapTuples;
314  }
315  else
316  {
317  /*
318  * Merge lists
319  */
320  data.prevTail = metadata->tail;
321  data.newRightlink = sublist.head;
322 
323  buffer = ReadBuffer(index, metadata->tail);
324  LockBuffer(buffer, GIN_EXCLUSIVE);
325  page = BufferGetPage(buffer);
326 
327  Assert(GinPageGetOpaque(page)->rightlink == InvalidBlockNumber);
328 
330 
331  GinPageGetOpaque(page)->rightlink = sublist.head;
332 
333  MarkBufferDirty(buffer);
334 
335  metadata->tail = sublist.tail;
336  metadata->tailFreeSize = sublist.tailFreeSize;
337 
338  metadata->nPendingPages += sublist.nPendingPages;
339  metadata->nPendingHeapTuples += sublist.nPendingHeapTuples;
340 
341  if (needWal)
343  }
344  }
345  else
346  {
347  /*
348  * Insert into tail page. Metapage is already locked
349  */
350  OffsetNumber l,
351  off;
352  int i,
353  tupsize;
354  char *ptr;
355  char *collectordata;
356 
357  buffer = ReadBuffer(index, metadata->tail);
358  LockBuffer(buffer, GIN_EXCLUSIVE);
359  page = BufferGetPage(buffer);
360 
361  off = (PageIsEmpty(page)) ? FirstOffsetNumber :
363 
364  collectordata = ptr = (char *) palloc(collector->sumsize);
365 
366  data.ntuples = collector->ntuples;
367 
368  if (needWal)
369  XLogBeginInsert();
370 
372 
373  /*
374  * Increase counter of heap tuples
375  */
376  Assert(GinPageGetOpaque(page)->maxoff <= metadata->nPendingHeapTuples);
377  GinPageGetOpaque(page)->maxoff++;
378  metadata->nPendingHeapTuples++;
379 
380  for (i = 0; i < collector->ntuples; i++)
381  {
382  tupsize = IndexTupleSize(collector->tuples[i]);
383  l = PageAddItem(page, (Item) collector->tuples[i], tupsize, off, false, false);
384 
385  if (l == InvalidOffsetNumber)
386  elog(ERROR, "failed to add item to index page in \"%s\"",
387  RelationGetRelationName(index));
388 
389  memcpy(ptr, collector->tuples[i], tupsize);
390  ptr += tupsize;
391 
392  off++;
393  }
394 
395  Assert((ptr - collectordata) <= collector->sumsize);
396  if (needWal)
397  {
399  XLogRegisterBufData(1, collectordata, collector->sumsize);
400  }
401 
402  metadata->tailFreeSize = PageGetExactFreeSpace(page);
403 
404  MarkBufferDirty(buffer);
405  }
406 
407  /*
408  * Set pd_lower just past the end of the metadata. This is essential,
409  * because without doing so, metadata will be lost if xlog.c compresses
410  * the page. (We must do this here because pre-v11 versions of PG did not
411  * set the metapage's pd_lower correctly, so a pg_upgraded index might
412  * contain the wrong value.)
413  */
414  ((PageHeader) metapage)->pd_lower =
415  ((char *) metadata + sizeof(GinMetaPageData)) - (char *) metapage;
416 
417  /*
418  * Write metabuffer, make xlog entry
419  */
420  MarkBufferDirty(metabuffer);
421 
422  if (needWal)
423  {
424  XLogRecPtr recptr;
425 
426  memcpy(&data.metadata, metadata, sizeof(GinMetaPageData));
427 
429  XLogRegisterData((char *) &data, sizeof(ginxlogUpdateMeta));
430 
431  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_UPDATE_META_PAGE);
432  PageSetLSN(metapage, recptr);
433 
434  if (buffer != InvalidBuffer)
435  {
436  PageSetLSN(page, recptr);
437  }
438  }
439 
440  if (buffer != InvalidBuffer)
441  UnlockReleaseBuffer(buffer);
442 
443  /*
444  * Force pending list cleanup when it becomes too long. And,
445  * ginInsertCleanup could take significant amount of time, so we prefer to
446  * call it when it can do all the work in a single collection cycle. In
447  * non-vacuum mode, it shouldn't require maintenance_work_mem, so fire it
448  * while pending list is still small enough to fit into
449  * gin_pending_list_limit.
450  *
451  * ginInsertCleanup() should not be called inside our CRIT_SECTION.
452  */
453  cleanupSize = GinGetPendingListCleanupSize(index);
454  if (metadata->nPendingPages * GIN_PAGE_FREESIZE > cleanupSize * 1024L)
455  needCleanup = true;
456 
457  UnlockReleaseBuffer(metabuffer);
458 
460 
461  /*
462  * Since it could contend with concurrent cleanup process we cleanup
463  * pending list not forcibly.
464  */
465  if (needCleanup)
466  ginInsertCleanup(ginstate, false, true, false, NULL);
467 }
BlockNumber prevTail
Definition: ginxlog.h:173
#define GIN_UNLOCK
Definition: gin_private.h:43
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
#define PageIsEmpty(page)
Definition: bufpage.h:218
RelFileNode node
Definition: ginxlog.h:171
Relation index
Definition: gin_private.h:53
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
#define GinListPageSize
Definition: ginblock.h:321
Pointer Item
Definition: item.h:17
#define InvalidBuffer
Definition: buf.h:25
#define REGBUF_WILL_INIT
Definition: xloginsert.h:32
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:412
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
#define GIN_METAPAGE_BLKNO
Definition: ginblock.h:50
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
void CheckForSerializableConflictIn(Relation relation, HeapTuple tuple, Buffer buffer)
Definition: predicate.c:4280
static void makeSublist(Relation index, IndexTuple *tuples, int32 ntuples, GinMetaPageData *res)
Definition: ginfast.c:149
uint16 OffsetNumber
Definition: off.h:24
Definition: type.h:89
int64 nPendingHeapTuples
Definition: ginblock.h:73
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ERROR
Definition: elog.h:43
#define XLOG_GIN_UPDATE_META_PAGE
Definition: ginxlog.h:163
BlockNumber head
Definition: ginblock.h:60
BlockNumber tail
Definition: ginblock.h:61
#define FirstOffsetNumber
Definition: off.h:27
#define REGBUF_STANDARD
Definition: xloginsert.h:34
#define GinGetPendingListCleanupSize(relation)
Definition: gin_private.h:35
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
BlockNumber newRightlink
Definition: ginxlog.h:174
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
IndexTuple * tuples
Definition: gin_private.h:428
#define GIN_EXCLUSIVE
Definition: gin_private.h:45
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define InvalidOffsetNumber
Definition: off.h:26
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition: ginfast.c:762
GinMetaPageData metadata
Definition: ginxlog.h:172
RelFileNode rd_node
Definition: rel.h:55
PageHeaderData * PageHeader
Definition: bufpage.h:162
uint32 tailFreeSize
Definition: ginblock.h:66
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:699
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define OffsetNumberNext(offsetNumber)
Definition: off.h:53
#define InvalidBlockNumber
Definition: block.h:33
#define RelationNeedsWAL(relation)
Definition: rel.h:510
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:629
void * palloc(Size size)
Definition: mcxt.c:924
int i
#define GIN_PAGE_FREESIZE
Definition: ginfast.c:40
#define GinPageGetMeta(p)
Definition: ginblock.h:103
#define elog
Definition: elog.h:219
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74
#define IndexTupleSize(itup)
Definition: itup.h:71
BlockNumber nPendingPages
Definition: ginblock.h:72

◆ ginInitBA()

void ginInitBA ( BuildAccumulator accum)

Definition at line 109 of file ginbulk.c.

References BuildAccumulator::allocatedMemory, cmpEntryAccumulator(), BuildAccumulator::eas_used, BuildAccumulator::entryallocator, ginAllocEntryAccumulator(), ginCombineData(), rb_create(), and BuildAccumulator::tree.

Referenced by ginbuild(), ginBuildCallback(), and ginInsertCleanup().

110 {
111  /* accum->ginstate is intentionally not set here */
112  accum->allocatedMemory = 0;
113  accum->entryallocator = NULL;
114  accum->eas_used = 0;
115  accum->tree = rb_create(sizeof(GinEntryAccumulator),
119  NULL, /* no freefunc needed */
120  (void *) accum);
121 }
GinEntryAccumulator * entryallocator
Definition: gin_private.h:408
static void ginCombineData(RBNode *existing, const RBNode *newdata, void *arg)
Definition: ginbulk.c:30
RBTree * rb_create(Size node_size, rb_comparator comparator, rb_combiner combiner, rb_allocfunc allocfunc, rb_freefunc freefunc, void *arg)
Definition: rbtree.c:99
static int cmpEntryAccumulator(const RBNode *a, const RBNode *b, void *arg)
Definition: ginbulk.c:72
static RBNode * ginAllocEntryAccumulator(void *arg)
Definition: ginbulk.c:85

◆ GinInitBuffer()

void GinInitBuffer ( Buffer  b,
uint32  f 
)

Definition at line 355 of file ginutil.c.

References BufferGetPage, BufferGetPageSize, and GinInitPage().

Referenced by ginbuild(), ginbuildempty(), ginRedoCreateIndex(), ginRedoCreatePTree(), ginRedoDeleteListPages(), ginRedoInsertListPage(), and writeListPage().

356 {
358 }
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:342
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:147

◆ ginInitConsistentFunction()

void ginInitConsistentFunction ( GinState ginstate,
GinScanKey  key 
)

Definition at line 225 of file ginlogic.c.

References GinScanKeyData::attnum, GinScanKeyData::boolConsistentFn, GinScanKeyData::collation, GinScanKeyData::consistentFmgrInfo, GinState::consistentFn, directBoolConsistentFn(), directTriConsistentFn(), FmgrInfo::fn_oid, GIN_SEARCH_MODE_EVERYTHING, OidIsValid, GinScanKeyData::searchMode, shimBoolConsistentFn(), shimTriConsistentFn(), GinState::supportCollation, GinScanKeyData::triConsistentFmgrInfo, GinState::triConsistentFn, GinScanKeyData::triConsistentFn, trueConsistentFn(), and trueTriConsistentFn().

Referenced by ginFillScanKey().

226 {
228  {
231  }
232  else
233  {
234  key->consistentFmgrInfo = &ginstate->consistentFn[key->attnum - 1];
235  key->triConsistentFmgrInfo = &ginstate->triConsistentFn[key->attnum - 1];
236  key->collation = ginstate->supportCollation[key->attnum - 1];
237 
238  if (OidIsValid(ginstate->consistentFn[key->attnum - 1].fn_oid))
240  else
242 
243  if (OidIsValid(ginstate->triConsistentFn[key->attnum - 1].fn_oid))
245  else
247  }
248 }
FmgrInfo * triConsistentFmgrInfo
Definition: gin_private.h:287
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gin_private.h:82
static GinTernaryValue directTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:95
static GinTernaryValue shimTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:154
#define GIN_SEARCH_MODE_EVERYTHING
Definition: gin.h:36
FmgrInfo consistentFn[INDEX_MAX_KEYS]
Definition: gin_private.h:76
FmgrInfo * consistentFmgrInfo
Definition: gin_private.h:286
#define OidIsValid(objectId)
Definition: c.h:605
OffsetNumber attnum
Definition: gin_private.h:298
static GinTernaryValue trueTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:62
bool(* boolConsistentFn)(GinScanKey key)
Definition: gin_private.h:284
Oid fn_oid
Definition: fmgr.h:59
GinTernaryValue(* triConsistentFn)(GinScanKey key)
Definition: gin_private.h:285
static bool directBoolConsistentFn(GinScanKey key)
Definition: ginlogic.c:71
static bool trueConsistentFn(GinScanKey key)
Definition: ginlogic.c:56
static bool shimBoolConsistentFn(GinScanKey key)
Definition: ginlogic.c:115
FmgrInfo triConsistentFn[INDEX_MAX_KEYS]
Definition: gin_private.h:77

◆ GinInitMetabuffer()

void GinInitMetabuffer ( Buffer  b)

Definition at line 361 of file ginutil.c.

References BufferGetPage, BufferGetPageSize, GIN_CURRENT_VERSION, GIN_META, GinInitPage(), GinPageGetMeta, GinMetaPageData::ginVersion, GinMetaPageData::head, InvalidBlockNumber, GinMetaPageData::nDataPages, GinMetaPageData::nEntries, GinMetaPageData::nEntryPages, GinMetaPageData::nPendingHeapTuples, GinMetaPageData::nPendingPages, GinMetaPageData::nTotalPages, GinMetaPageData::tail, and GinMetaPageData::tailFreeSize.

Referenced by ginbuild(), ginbuildempty(), ginRedoCreateIndex(), ginRedoDeleteListPages(), and ginRedoUpdateMetapage().

362 {
363  GinMetaPageData *metadata;
364  Page page = BufferGetPage(b);
365 
367 
368  metadata = GinPageGetMeta(page);
369 
370  metadata->head = metadata->tail = InvalidBlockNumber;
371  metadata->tailFreeSize = 0;
372  metadata->nPendingPages = 0;
373  metadata->nPendingHeapTuples = 0;
374  metadata->nTotalPages = 0;
375  metadata->nEntryPages = 0;
376  metadata->nDataPages = 0;
377  metadata->nEntries = 0;
378  metadata->ginVersion = GIN_CURRENT_VERSION;
379 
380  /*
381  * Set pd_lower just past the end of the metadata. This is essential,
382  * because without doing so, metadata will be lost if xlog.c compresses
383  * the page.
384  */
385  ((PageHeader) page)->pd_lower =
386  ((char *) metadata + sizeof(GinMetaPageData)) - (char *) page;
387 }
BlockNumber nEntryPages
Definition: ginblock.h:79
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:342
BlockNumber nTotalPages
Definition: ginblock.h:78
int64 nEntries
Definition: ginblock.h:81
int64 nPendingHeapTuples
Definition: ginblock.h:73
#define GIN_META
Definition: ginblock.h:42
BlockNumber head
Definition: ginblock.h:60
BlockNumber tail
Definition: ginblock.h:61
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:147
PageHeaderData * PageHeader
Definition: bufpage.h:162
uint32 tailFreeSize
Definition: ginblock.h:66
#define GIN_CURRENT_VERSION
Definition: ginblock.h:101
#define InvalidBlockNumber
Definition: block.h:33
int32 ginVersion
Definition: ginblock.h:98
BlockNumber nDataPages
Definition: ginblock.h:80
#define GinPageGetMeta(p)
Definition: ginblock.h:103
Pointer Page
Definition: bufpage.h:74
BlockNumber nPendingPages
Definition: ginblock.h:72

◆ GinInitPage()

void GinInitPage ( Page  page,
uint32  f,
Size  pageSize 
)

Definition at line 342 of file ginutil.c.

References GinPageOpaqueData::flags, GinPageGetOpaque, InvalidBlockNumber, PageInit(), and GinPageOpaqueData::rightlink.

Referenced by createPostingTree(), dataPlaceToPageLeafSplit(), dataSplitPageInternal(), entrySplitPage(), GinInitBuffer(), GinInitMetabuffer(), and ginPlaceToPage().

343 {
344  GinPageOpaque opaque;
345 
346  PageInit(page, pageSize, sizeof(GinPageOpaqueData));
347 
348  opaque = GinPageGetOpaque(page);
349  memset(opaque, 0, sizeof(GinPageOpaqueData));
350  opaque->flags = f;
351  opaque->rightlink = InvalidBlockNumber;
352 }
BlockNumber rightlink
Definition: ginblock.h:30
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
#define InvalidBlockNumber
Definition: block.h:33
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:41

◆ gininsert()

bool gininsert ( Relation  index,
Datum values,
bool isnull,
ItemPointer  ht_ctid,
Relation  heapRel,
IndexUniqueCheck  checkUnique,
struct IndexInfo indexInfo 
)

Definition at line 488 of file gininsert.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, CurrentMemoryContext, GinGetUseFastUpdate, ginHeapTupleFastCollect(), ginHeapTupleFastInsert(), ginHeapTupleInsert(), i, IndexInfo::ii_AmCache, IndexInfo::ii_Context, initGinState(), MemoryContextDelete(), MemoryContextSwitchTo(), tupleDesc::natts, GinState::origTupdesc, and palloc().

Referenced by ginhandler().

492 {
493  GinState *ginstate = (GinState *) indexInfo->ii_AmCache;
494  MemoryContext oldCtx;
495  MemoryContext insertCtx;
496  int i;
497 
498  /* Initialize GinState cache if first call in this statement */
499  if (ginstate == NULL)
500  {
501  oldCtx = MemoryContextSwitchTo(indexInfo->ii_Context);
502  ginstate = (GinState *) palloc(sizeof(GinState));
503  initGinState(ginstate, index);
504  indexInfo->ii_AmCache = (void *) ginstate;
505  MemoryContextSwitchTo(oldCtx);
506  }
507 
509  "Gin insert temporary context",
511 
512  oldCtx = MemoryContextSwitchTo(insertCtx);
513 
514  if (GinGetUseFastUpdate(index))
515  {
516  GinTupleCollector collector;
517 
518  memset(&collector, 0, sizeof(GinTupleCollector));
519 
520  for (i = 0; i < ginstate->origTupdesc->natts; i++)
521  ginHeapTupleFastCollect(ginstate, &collector,
522  (OffsetNumber) (i + 1),
523  values[i], isnull[i],
524  ht_ctid);
525 
526  ginHeapTupleFastInsert(ginstate, &collector);
527  }
528  else
529  {
530  for (i = 0; i < ginstate->origTupdesc->natts; i++)
531  ginHeapTupleInsert(ginstate, (OffsetNumber) (i + 1),
532  values[i], isnull[i],
533  ht_ctid);
534  }
535 
536  MemoryContextSwitchTo(oldCtx);
537  MemoryContextDelete(insertCtx);
538 
539  return false;
540 }
MemoryContext ii_Context
Definition: execnodes.h:171
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
void ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
Definition: ginfast.c:223
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void ginHeapTupleInsert(GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, ItemPointer item)
Definition: gininsert.c:470
int natts
Definition: tupdesc.h:82
uint16 OffsetNumber
Definition: off.h:24
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:88
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
void * ii_AmCache
Definition: execnodes.h:170
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
#define GinGetUseFastUpdate(relation)
Definition: gin_private.h:32
static Datum values[MAXATTR]
Definition: bootstrap.c:164
void * palloc(Size size)
Definition: mcxt.c:924
int i
void ginHeapTupleFastCollect(GinState *ginstate, GinTupleCollector *collector, OffsetNumber attnum, Datum value, bool isNull, ItemPointer ht_ctid)
Definition: ginfast.c:478
TupleDesc origTupdesc
Definition: gin_private.h:67

◆ ginInsertBAEntries()

void ginInsertBAEntries ( BuildAccumulator accum,
ItemPointer  heapptr,
OffsetNumber  attnum,
Datum entries,
GinNullCategory categories,
int32  nentries 
)

Definition at line 210 of file ginbulk.c.

References Assert, FirstOffsetNumber, ginInsertBAEntry(), i, and ItemPointerIsValid.

Referenced by ginHeapTupleBulkInsert(), and processPendingPage().

214 {
215  uint32 step = nentries;
216 
217  if (nentries <= 0)
218  return;
219 
221 
222  /*
223  * step will contain largest power of 2 and <= nentries
224  */
225  step |= (step >> 1);
226  step |= (step >> 2);
227  step |= (step >> 4);
228  step |= (step >> 8);
229  step |= (step >> 16);
230  step >>= 1;
231  step++;
232 
233  while (step > 0)
234  {
235  int i;
236 
237  for (i = step - 1; i < nentries && i >= 0; i += step << 1 /* *2 */ )
238  ginInsertBAEntry(accum, heapptr, attnum,
239  entries[i], categories[i]);
240 
241  step >>= 1; /* /2 */
242  }
243 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
static void ginInsertBAEntry(BuildAccumulator *accum, ItemPointer heapptr, OffsetNumber attnum, Datum key, GinNullCategory category)
Definition: ginbulk.c:148
#define FirstOffsetNumber
Definition: off.h:27
unsigned int uint32
Definition: c.h:325
int16 attnum
Definition: pg_attribute.h:79
#define Assert(condition)
Definition: c.h:699
int i

◆ ginInsertCleanup()

void ginInsertCleanup ( GinState ginstate,
bool  full_clean,
bool  fill_fsm,
bool  forceCleanup,
IndexBulkDeleteResult stats 
)

Definition at line 762 of file ginfast.c.

References BuildAccumulator::allocatedMemory, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, attnum, autovacuum_work_mem, buffer, BufferGetPage, ConditionalLockPage(), CurrentMemoryContext, ExclusiveLock, FirstOffsetNumber, GIN_EXCLUSIVE, GIN_METAPAGE_BLKNO, GIN_SHARE, GIN_UNLOCK, ginBeginBAScan(), ginEntryInsert(), ginGetBAEntry(), ginInitBA(), GinPageGetMeta, GinPageGetOpaque, GinPageHasFullRow, GinPageIsDeleted, BuildAccumulator::ginstate, GinMetaPageData::head, GinState::index, IndexFreeSpaceMapVacuum(), initKeyArray(), InvalidBlockNumber, IsAutoVacuumWorkerProcess(), sort-test::list, LockBuffer(), LockPage(), maintenance_work_mem, KeyArray::maxvalues, MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), opCtx, PageGetMaxOffsetNumber, processPendingPage(), ReadBuffer(), ReleaseBuffer(), shiftList(), GinMetaPageData::tail, UnlockPage(), UnlockReleaseBuffer(), vacuum_delay_point(), and work_mem.

Referenced by gin_clean_pending_list(), ginbulkdelete(), ginHeapTupleFastInsert(), and ginvacuumcleanup().

765 {
766  Relation index = ginstate->index;
767  Buffer metabuffer,
768  buffer;
769  Page metapage,
770  page;
771  GinMetaPageData *metadata;
773  oldCtx;
774  BuildAccumulator accum;
775  KeyArray datums;
776  BlockNumber blkno,
777  blknoFinish;
778  bool cleanupFinish = false;
779  bool fsm_vac = false;
780  Size workMemory;
781 
782  /*
783  * We would like to prevent concurrent cleanup process. For that we will
784  * lock metapage in exclusive mode using LockPage() call. Nobody other
785  * will use that lock for metapage, so we keep possibility of concurrent
786  * insertion into pending list
787  */
788 
789  if (forceCleanup)
790  {
791  /*
792  * We are called from [auto]vacuum/analyze or gin_clean_pending_list()
793  * and we would like to wait concurrent cleanup to finish.
794  */
796  workMemory =
799  }
800  else
801  {
802  /*
803  * We are called from regular insert and if we see concurrent cleanup
804  * just exit in hope that concurrent process will clean up pending
805  * list.
806  */
808  return;
809  workMemory = work_mem;
810  }
811 
812  metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
813  LockBuffer(metabuffer, GIN_SHARE);
814  metapage = BufferGetPage(metabuffer);
815  metadata = GinPageGetMeta(metapage);
816 
817  if (metadata->head == InvalidBlockNumber)
818  {
819  /* Nothing to do */
820  UnlockReleaseBuffer(metabuffer);
822  return;
823  }
824 
825  /*
826  * Remember a tail page to prevent infinite cleanup if other backends add
827  * new tuples faster than we can cleanup.
828  */
829  blknoFinish = metadata->tail;
830 
831  /*
832  * Read and lock head of pending list
833  */
834  blkno = metadata->head;
835  buffer = ReadBuffer(index, blkno);
836  LockBuffer(buffer, GIN_SHARE);
837  page = BufferGetPage(buffer);
838 
839  LockBuffer(metabuffer, GIN_UNLOCK);
840 
841  /*
842  * Initialize. All temporary space will be in opCtx
843  */
845  "GIN insert cleanup temporary context",
847 
848  oldCtx = MemoryContextSwitchTo(opCtx);
849 
850  initKeyArray(&datums, 128);
851  ginInitBA(&accum);
852  accum.ginstate = ginstate;
853 
854  /*
855  * At the top of this loop, we have pin and lock on the current page of
856  * the pending list. However, we'll release that before exiting the loop.
857  * Note we also have pin but not lock on the metapage.
858  */
859  for (;;)
860  {
861  Assert(!GinPageIsDeleted(page));
862 
863  /*
864  * Are we walk through the page which as we remember was a tail when
865  * we start our cleanup? But if caller asks us to clean up whole
866  * pending list then ignore old tail, we will work until list becomes
867  * empty.
868  */
869  if (blkno == blknoFinish && full_clean == false)
870  cleanupFinish = true;
871 
872  /*
873  * read page's datums into accum
874  */
875  processPendingPage(&accum, &datums, page, FirstOffsetNumber);
876 
878 
879  /*
880  * Is it time to flush memory to disk? Flush if we are at the end of
881  * the pending list, or if we have a full row and memory is getting
882  * full.
883  */
884  if (GinPageGetOpaque(page)->rightlink == InvalidBlockNumber ||
885  (GinPageHasFullRow(page) &&
886  (accum.allocatedMemory >= workMemory * 1024L)))
887  {
889  uint32 nlist;
890  Datum key;
891  GinNullCategory category;
892  OffsetNumber maxoff,
893  attnum;
894 
895  /*
896  * Unlock current page to increase performance. Changes of page
897  * will be checked later by comparing maxoff after completion of
898  * memory flush.
899  */
900  maxoff = PageGetMaxOffsetNumber(page);
901  LockBuffer(buffer, GIN_UNLOCK);
902 
903  /*
904  * Moving collected data into regular structure can take
905  * significant amount of time - so, run it without locking pending
906  * list.
907  */
908  ginBeginBAScan(&accum);
909  while ((list = ginGetBAEntry(&accum,
910  &attnum, &key, &category, &nlist)) != NULL)
911  {
912  ginEntryInsert(ginstate, attnum, key, category,
913  list, nlist, NULL);
915  }
916 
917  /*
918  * Lock the whole list to remove pages
919  */
920  LockBuffer(metabuffer, GIN_EXCLUSIVE);
921  LockBuffer(buffer, GIN_SHARE);
922 
923  Assert(!GinPageIsDeleted(page));
924 
925  /*
926  * While we left the page unlocked, more stuff might have gotten
927  * added to it. If so, process those entries immediately. There
928  * shouldn't be very many, so we don't worry about the fact that
929  * we're doing this with exclusive lock. Insertion algorithm
930  * guarantees that inserted row(s) will not continue on next page.
931  * NOTE: intentionally no vacuum_delay_point in this loop.
932  */
933  if (PageGetMaxOffsetNumber(page) != maxoff)
934  {
935  ginInitBA(&accum);
936  processPendingPage(&accum, &datums, page, maxoff + 1);
937 
938  ginBeginBAScan(&accum);
939  while ((list = ginGetBAEntry(&accum,
940  &attnum, &key, &category, &nlist)) != NULL)
941  ginEntryInsert(ginstate, attnum, key, category,
942  list, nlist, NULL);
943  }
944 
945  /*
946  * Remember next page - it will become the new list head
947  */
948  blkno = GinPageGetOpaque(page)->rightlink;
949  UnlockReleaseBuffer(buffer); /* shiftList will do exclusive
950  * locking */
951 
952  /*
953  * remove read pages from pending list, at this point all content
954  * of read pages is in regular structure
955  */
956  shiftList(index, metabuffer, blkno, fill_fsm, stats);
957 
958  /* At this point, some pending pages have been freed up */
959  fsm_vac = true;
960 
961  Assert(blkno == metadata->head);
962  LockBuffer(metabuffer, GIN_UNLOCK);
963 
964  /*
965  * if we removed the whole pending list or we cleanup tail (which
966  * we remembered on start our cleanup process) then just exit
967  */
968  if (blkno == InvalidBlockNumber || cleanupFinish)
969  break;
970 
971  /*
972  * release memory used so far and reinit state
973  */
974  MemoryContextReset(opCtx);
975  initKeyArray(&datums, datums.maxvalues);
976  ginInitBA(&accum);
977  }
978  else
979  {
980  blkno = GinPageGetOpaque(page)->rightlink;
981  UnlockReleaseBuffer(buffer);
982  }
983 
984  /*
985  * Read next page in pending list
986  */
988  buffer = ReadBuffer(index, blkno);
989  LockBuffer(buffer, GIN_SHARE);
990  page = BufferGetPage(buffer);
991  }
992 
994  ReleaseBuffer(metabuffer);
995 
996  /*
997  * As pending list pages can have a high churn rate, it is desirable to
998  * recycle them immediately to the FreeSpace Map when ordinary backends
999  * clean the list.
1000  */
1001  if (fsm_vac && fill_fsm)
1002  IndexFreeSpaceMapVacuum(index);
1003 
1004  /* Clean up temporary space */
1005  MemoryContextSwitchTo(oldCtx);
1006  MemoryContextDelete(opCtx);
1007 }
#define GinPageHasFullRow(page)
Definition: ginblock.h:118
int autovacuum_work_mem
Definition: autovacuum.c:115
#define GIN_UNLOCK
Definition: gin_private.h:43
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
Relation index
Definition: gin_private.h:53
#define ExclusiveLock
Definition: lockdefs.h:44
static MemoryContext opCtx
Definition: ginxlog.c:22
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
#define GIN_METAPAGE_BLKNO
Definition: ginblock.h:50
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
uint16 OffsetNumber
Definition: off.h:24
static void initKeyArray(KeyArray *keys, int32 maxvalues)
Definition: ginfast.c:654
Definition: type.h:89
void ginEntryInsert(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gininsert.c:179
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
signed char GinNullCategory
Definition: ginblock.h:200
BlockNumber head
Definition: ginblock.h:60
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
void LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
Definition: lmgr.c:400
BlockNumber tail
Definition: ginblock.h:61
#define FirstOffsetNumber
Definition: off.h:27
unsigned int uint32
Definition: c.h:325
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
GinState * ginstate
Definition: gin_private.h:406
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3295
#define GIN_SHARE
Definition: gin_private.h:44
int32 maxvalues
Definition: ginfast.c:48
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
static void processPendingPage(BuildAccumulator *accum, KeyArray *ka, Page page, OffsetNumber startoff)
Definition: ginfast.c:691
#define GinPageIsDeleted(page)
Definition: ginblock.h:123
uintptr_t Datum
Definition: postgres.h:367
#define GIN_EXCLUSIVE
Definition: gin_private.h:45
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
int work_mem
Definition: globals.c:122
int16 attnum
Definition: pg_attribute.h:79
int maintenance_work_mem
Definition: globals.c:123
#define Assert(condition)
Definition: c.h:699
static void shiftList(Relation index, Buffer metabuffer, BlockNumber newHead, bool fill_fsm, IndexBulkDeleteResult *stats)
Definition: ginfast.c:533
void IndexFreeSpaceMapVacuum(Relation rel)
Definition: indexfsm.c:71
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
size_t Size
Definition: c.h:433
#define InvalidBlockNumber
Definition: block.h:33
ItemPointerData * ginGetBAEntry(BuildAccumulator *accum, OffsetNumber *attnum, Datum *key, GinNullCategory *category, uint32 *n)
Definition: ginbulk.c:268
void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
Definition: lmgr.c:435
bool ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
Definition: lmgr.c:419
void ginBeginBAScan(BuildAccumulator *accum)
Definition: ginbulk.c:257
#define GinPageGetMeta(p)
Definition: ginblock.h:103
void vacuum_delay_point(void)
Definition: vacuum.c:1672
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74
void ginInitBA(BuildAccumulator *accum)
Definition: ginbulk.c:109

◆ ginInsertItemPointers()

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

Definition at line 1894 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().

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

◆ ginInsertValue()

void ginInsertValue ( GinBtree  btree,
GinBtreeStack stack,
void *  insertdata,
GinStatsData buildStats 
)

Definition at line 780 of file ginbtree.c.

References GinBtreeStack::buffer, BufferGetPage, freeGinBtreeStack(), GIN_UNLOCK, ginFinishSplit(), GinPageIsIncompleteSplit, ginPlaceToPage(), InvalidBlockNumber, InvalidBuffer, and LockBuffer().

Referenced by ginEntryInsert(), and ginInsertItemPointers().

782 {
783  bool done;
784 
785  /* If the leaf page was incompletely split, finish the split first */
787  ginFinishSplit(btree, stack, false, buildStats);
788 
789  done = ginPlaceToPage(btree, stack,
790  insertdata, InvalidBlockNumber,
791  InvalidBuffer, buildStats);
792  if (done)
793  {
794  LockBuffer(stack->buffer, GIN_UNLOCK);
795  freeGinBtreeStack(stack);
796  }
797  else
798  ginFinishSplit(btree, stack, true, buildStats);
799 }
#define GIN_UNLOCK
Definition: gin_private.h:43
#define GinPageIsIncompleteSplit(page)
Definition: ginblock.h:126
static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack, GinStatsData *buildStats)
Definition: ginbtree.c:671
#define InvalidBuffer
Definition: buf.h:25
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define InvalidBlockNumber
Definition: block.h:33
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:197
static bool ginPlaceToPage(GinBtree btree, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, Buffer childbuf, GinStatsData *buildStats)
Definition: ginbtree.c:333

◆ ginMergeItemPointers()

ItemPointer ginMergeItemPointers ( ItemPointerData a,
uint32  na,
ItemPointerData b,
uint32  nb,
int *  nmerged 
)

Definition at line 363 of file ginpostinglist.c.

References cmp(), ginCompareItemPointers(), and palloc().

Referenced by addItemPointersToLeafTuple(), addItemsToLeaf(), ginRedoRecompress(), and leafRepackItems().

366 {
367  ItemPointerData *dst;
368 
369  dst = (ItemPointer) palloc((na + nb) * sizeof(ItemPointerData));
370 
371  /*
372  * If the argument arrays don't overlap, we can just append them to each
373  * other.
374  */
375  if (na == 0 || nb == 0 || ginCompareItemPointers(&a[na - 1], &b[0]) < 0)
376  {
377  memcpy(dst, a, na * sizeof(ItemPointerData));
378  memcpy(&dst[na], b, nb * sizeof(ItemPointerData));
379  *nmerged = na + nb;
380  }
381  else if (ginCompareItemPointers(&b[nb - 1], &a[0]) < 0)
382  {
383  memcpy(dst, b, nb * sizeof(ItemPointerData));
384  memcpy(&dst[nb], a, na * sizeof(ItemPointerData));
385  *nmerged = na + nb;
386  }
387  else
388  {
389  ItemPointerData *dptr = dst;
390  ItemPointerData *aptr = a;
391  ItemPointerData *bptr = b;
392 
393  while (aptr - a < na && bptr - b < nb)
394  {
395  int cmp = ginCompareItemPointers(aptr, bptr);
396 
397  if (cmp > 0)
398  *dptr++ = *bptr++;
399  else if (cmp == 0)
400  {
401  /* only keep one copy of the identical items */
402  *dptr++ = *bptr++;
403  aptr++;
404  }
405  else
406  *dptr++ = *aptr++;
407  }
408 
409  while (aptr - a < na)
410  *dptr++ = *aptr++;
411 
412  while (bptr - b < nb)
413  *dptr++ = *bptr++;
414 
415  *nmerged = dptr - dst;
416  }
417 
418  return dst;
419 }
ItemPointerData * ItemPointer
Definition: itemptr.h:49
struct ItemPointerData ItemPointerData
static int ginCompareItemPointers(ItemPointer a, ItemPointer b)
Definition: gin_private.h:460
void * palloc(Size size)
Definition: mcxt.c:924
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:742

◆ GinNewBuffer()

Buffer GinNewBuffer ( Relation  index)

Definition at line 291 of file ginutil.c.

References buffer, BufferGetPage, ConditionalLockBuffer(), ExclusiveLock, GetFreeIndexPage(), GIN_EXCLUSIVE, GIN_UNLOCK, GinPageIsDeleted, InvalidBlockNumber, LockBuffer(), LockRelationForExtension(), P_NEW, PageIsNew, ReadBuffer(), RELATION_IS_LOCAL, ReleaseBuffer(), and UnlockRelationForExtension().

Referenced by createPostingTree(), ginbuild(), ginPlaceToPage(), and makeSublist().

292 {
293  Buffer buffer;
294  bool needLock;
295 
296  /* First, try to get a page from FSM */
297  for (;;)
298  {
299  BlockNumber blkno = GetFreeIndexPage(index);
300 
301  if (blkno == InvalidBlockNumber)
302  break;
303 
304  buffer = ReadBuffer(index, blkno);
305 
306  /*
307  * We have to guard against the possibility that someone else already
308  * recycled this page; the buffer may be locked if so.
309  */
310  if (ConditionalLockBuffer(buffer))
311  {
312  Page page = BufferGetPage(buffer);
313 
314  if (PageIsNew(page))
315  return buffer; /* OK to use, if never initialized */
316 
317  if (GinPageIsDeleted(page))
318  return buffer; /* OK to use */
319 
320  LockBuffer(buffer, GIN_UNLOCK);
321  }
322 
323  /* Can't use it, so release buffer and try again */
324  ReleaseBuffer(buffer);
325  }
326 
327  /* Must extend the file */
328  needLock = !RELATION_IS_LOCAL(index);
329  if (needLock)
331 
332  buffer = ReadBuffer(index, P_NEW);
333  LockBuffer(buffer, GIN_EXCLUSIVE);
334 
335  if (needLock)
337 
338  return buffer;
339 }
#define GIN_UNLOCK
Definition: gin_private.h:43
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:528
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define P_NEW
Definition: bufmgr.h:82
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3572
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:332
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:382
#define GinPageIsDeleted(page)
Definition: ginblock.h:123
#define GIN_EXCLUSIVE
Definition: gin_private.h:45
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define InvalidBlockNumber
Definition: block.h:33
#define PageIsNew(page)
Definition: bufpage.h:225
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

◆ ginNewScanKey()

void ginNewScanKey ( IndexScanDesc  scan)

Definition at line 262 of file ginscan.c.

References GinScanOpaqueData::allocentries, DatumGetPointer, GinScanOpaqueData::entries, ereport, errcode(), errhint(), errmsg(), ERROR, GinState::extractQueryFn, FirstOffsetNumber, FunctionCall7Coll(), GIN_CAT_NULL_KEY, GIN_SEARCH_MODE_ALL, GIN_SEARCH_MODE_DEFAULT, GIN_SEARCH_MODE_EVERYTHING, ginFillScanKey(), ginGetStats(), GinScanOpaqueData::ginstate, GinStatsData::ginVersion, i, IndexScanDescData::indexRelation, InvalidStrategy, GinScanOpaqueData::isVoidRes, GinScanOpaqueData::keyCtx, IndexScanDescData::keyData, GinScanOpaqueData::keys, Max, MemoryContextSwitchTo(), GinScanOpaqueData::nkeys, IndexScanDescData::numberOfKeys, IndexScanDescData::opaque, palloc(), palloc0(), pgstat_count_index_scan, PointerGetDatum, RelationGetRelationName, ScanKeyData::sk_argument, ScanKeyData::sk_attno, ScanKeyData::sk_flags, SK_ISNULL, ScanKeyData::sk_strategy, GinState::supportCollation, GinScanOpaqueData::totalentries, and UInt16GetDatum.

Referenced by gingetbitmap().

263 {
264  ScanKey scankey = scan->keyData;
265  GinScanOpaque so = (GinScanOpaque) scan->opaque;
266  int i;
267  bool hasNullQuery = false;
268  MemoryContext oldCtx;
269 
270  /*
271  * Allocate all the scan key information in the key context. (If
272  * extractQuery leaks anything there, it won't be reset until the end of
273  * scan or rescan, but that's OK.)
274  */
275  oldCtx = MemoryContextSwitchTo(so->keyCtx);
276 
277  /* if no scan keys provided, allocate extra EVERYTHING GinScanKey */
278  so->keys = (GinScanKey)
279  palloc(Max(scan->numberOfKeys, 1) * sizeof(GinScanKeyData));
280  so->nkeys = 0;
281 
282  /* initialize expansible array of GinScanEntry pointers */
283  so->totalentries = 0;
284  so->allocentries = 32;
285  so->entries = (GinScanEntry *)
286  palloc(so->allocentries * sizeof(GinScanEntry));
287 
288  so->isVoidRes = false;
289 
290  for (i = 0; i < scan->numberOfKeys; i++)
291  {
292  ScanKey skey = &scankey[i];
293  Datum *queryValues;
294  int32 nQueryValues = 0;
295  bool *partial_matches = NULL;
296  Pointer *extra_data = NULL;
297  bool *nullFlags = NULL;
298  GinNullCategory *categories;
299  int32 searchMode = GIN_SEARCH_MODE_DEFAULT;
300 
301  /*
302  * We assume that GIN-indexable operators are strict, so a null query
303  * argument means an unsatisfiable query.
304  */
305  if (skey->sk_flags & SK_ISNULL)
306  {
307  so->isVoidRes = true;
308  break;
309  }
310 
311  /* OK to call the extractQueryFn */
312  queryValues = (Datum *)
314  so->ginstate.supportCollation[skey->sk_attno - 1],
315  skey->sk_argument,
316  PointerGetDatum(&nQueryValues),
318  PointerGetDatum(&partial_matches),
319  PointerGetDatum(&extra_data),
320  PointerGetDatum(&nullFlags),
321  PointerGetDatum(&searchMode)));
322 
323  /*
324  * If bogus searchMode is returned, treat as GIN_SEARCH_MODE_ALL; note
325  * in particular we don't allow extractQueryFn to select
326  * GIN_SEARCH_MODE_EVERYTHING.
327  */
328  if (searchMode < GIN_SEARCH_MODE_DEFAULT ||
329  searchMode > GIN_SEARCH_MODE_ALL)
330  searchMode = GIN_SEARCH_MODE_ALL;
331 
332  /* Non-default modes require the index to have placeholders */
333  if (searchMode != GIN_SEARCH_MODE_DEFAULT)
334  hasNullQuery = true;
335 
336  /*
337  * In default mode, no keys means an unsatisfiable query.
338  */
339  if (queryValues == NULL || nQueryValues <= 0)
340  {
341  if (searchMode == GIN_SEARCH_MODE_DEFAULT)
342  {
343  so->isVoidRes = true;
344  break;
345  }
346  nQueryValues = 0; /* ensure sane value */
347  }
348 
349  /*
350  * Create GinNullCategory representation. If the extractQueryFn
351  * didn't create a nullFlags array, we assume everything is non-null.
352  * While at it, detect whether any null keys are present.
353  */
354  categories = (GinNullCategory *) palloc0(nQueryValues * sizeof(GinNullCategory));
355  if (nullFlags)
356  {
357  int32 j;
358 
359  for (j = 0; j < nQueryValues; j++)
360  {
361  if (nullFlags[j])
362  {
363  categories[j] = GIN_CAT_NULL_KEY;
364  hasNullQuery = true;
365  }
366  }
367  }
368 
369  ginFillScanKey(so, skey->sk_attno,
370  skey->sk_strategy, searchMode,
371  skey->sk_argument, nQueryValues,
372  queryValues, categories,
373  partial_matches, extra_data);
374  }
375 
376  /*
377  * If there are no regular scan keys, generate an EVERYTHING scankey to
378  * drive a full-index scan.
379  */
380  if (so->nkeys == 0 && !so->isVoidRes)
381  {
382  hasNullQuery = true;
385  (Datum) 0, 0,
386  NULL, NULL, NULL, NULL);
387  }
388 
389  /*
390  * If the index is version 0, it may be missing null and placeholder
391  * entries, which would render searches for nulls and full-index scans
392  * unreliable. Throw an error if so.
393  */
394  if (hasNullQuery && !so->isVoidRes)
395  {
396  GinStatsData ginStats;
397 
398  ginGetStats(scan->indexRelation, &ginStats);
399  if (ginStats.ginVersion < 1)
400  ereport(ERROR,
401  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
402  errmsg("old GIN indexes do not support whole-index scans nor searches for nulls"),
403  errhint("To fix this, do REINDEX INDEX \"%s\".",
405  }
406 
407  MemoryContextSwitchTo(oldCtx);
408 
410 }
#define InvalidStrategy
Definition: stratnum.h:24
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gin_private.h:82
int errhint(const char *fmt,...)
Definition: elog.c:987
#define PointerGetDatum(X)
Definition: postgres.h:541
#define GIN_SEARCH_MODE_EVERYTHING
Definition: gin.h:36
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:575
signed int int32
Definition: c.h:313
Relation indexRelation
Definition: relscan.h:91
#define GIN_SEARCH_MODE_ALL
Definition: gin.h:35
char * Pointer
Definition: c.h:302
#define ERROR
Definition: elog.h:43
signed char GinNullCategory
Definition: ginblock.h:200
Datum FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7)
Definition: fmgr.c:1268
struct GinScanKeyData * GinScanKey
Definition: gin_private.h:255
StrategyNumber sk_strategy
Definition: skey.h:68
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:363
static void ginFillScanKey(GinScanOpaque so, OffsetNumber attnum, StrategyNumber strategy, int32 searchMode, Datum query, uint32 nQueryValues, Datum *queryValues, GinNullCategory *queryCategories, bool *partial_matches, Pointer *extra_data)
Definition: ginscan.c:132
#define FirstOffsetNumber
Definition: off.h:27
MemoryContext keyCtx
Definition: gin_private.h:358
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:1291
FmgrInfo extractQueryFn[INDEX_MAX_KEYS]
Definition: gin_private.h:75
#define SK_ISNULL
Definition: skey.h:115
#define ereport(elevel, rest)
Definition: elog.h:122
GinScanKey keys
Definition: gin_private.h:351
#define GIN_CAT_NULL_KEY
Definition: ginblock.h:203
void * palloc0(Size size)
Definition: mcxt.c:955
struct GinScanKeyData GinScanKeyData
uintptr_t Datum
Definition: postgres.h:367
void ginGetStats(Relation index, GinStatsData *stats)
Definition: ginutil.c:642
#define GIN_SEARCH_MODE_DEFAULT
Definition: gin.h:33
#define Max(x, y)
Definition: c.h:851
int sk_flags
Definition: skey.h:66
ScanKey keyData
Definition: relscan.h:95
int32 ginVersion
Definition: gin.h:48
#define DatumGetPointer(X)
Definition: postgres.h:534
GinScanEntry * entries
Definition: gin_private.h:354
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
Datum sk_argument
Definition: skey.h:72
#define UInt16GetDatum(X)
Definition: postgres.h:450
AttrNumber sk_attno
Definition: skey.h:67

◆ ginoptions()

bytea* ginoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 607 of file ginutil.c.

References allocateReloptStruct(), fillRelOptions(), lengthof, offsetof, options, parseRelOptions(), pfree(), RELOPT_KIND_GIN, RELOPT_TYPE_BOOL, and RELOPT_TYPE_INT.

Referenced by ginhandler().

608 {
610  GinOptions *rdopts;
611  int numoptions;
612  static const relopt_parse_elt tab[] = {
613  {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)},
614  {"gin_pending_list_limit", RELOPT_TYPE_INT, offsetof(GinOptions,
615  pendingListCleanupSize)}
616  };
617 
618  options = parseRelOptions(reloptions, validate, RELOPT_KIND_GIN,
619  &numoptions);
620 
621  /* if none set, we're done */
622  if (numoptions == 0)
623  return NULL;
624 
625  rdopts = allocateReloptStruct(sizeof(GinOptions), options, numoptions);
626 
627  fillRelOptions((void *) rdopts, sizeof(GinOptions), options, numoptions,
628  validate, tab, lengthof(tab));
629 
630  pfree(options);
631 
632  return (bytea *) rdopts;
633 }
#define lengthof(array)
Definition: c.h:629
void pfree(void *pointer)
Definition: mcxt.c:1031
void * allocateReloptStruct(Size base, relopt_value *options, int numoptions)
Definition: reloptions.c:1242
static char ** options
void fillRelOptions(void *rdopts, Size basesize, relopt_value *options, int numoptions, bool validate, const relopt_parse_elt *elems, int numelems)
Definition: reloptions.c:1266
Definition: c.h:516
relopt_value * parseRelOptions(Datum options, bool validate, relopt_kind kind, int *numrelopts)
Definition: reloptions.c:1048
#define offsetof(type, field)
Definition: c.h:622

◆ 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:109
uint16 OffsetNumber
Definition: off.h:24
#define GinDataPageSetDataSize(page, size)
Definition: ginblock.h:303
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:292
#define memmove(d, s, c)
Definition: c.h:1135
#define FirstOffsetNumber
Definition: off.h:27
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define Assert(condition)
Definition: c.h:699

◆ ginPostingListDecode()

ItemPointer ginPostingListDecode ( GinPostingList ptr,
int *  ndecoded 
)

Definition at line 269 of file ginpostinglist.c.

References ginPostingListDecodeAllSegments(), and SizeOfGinPostingList.

Referenced by addItemsToLeaf(), dataBeginPlaceToPageLeaf(), gin_leafpage_items(), ginCompressPostingList(), ginReadTuple(), ginRedoRecompress(), ginVacuumEntryPage(), ginVacuumPostingTreeLeaf(), and leafRepackItems().

270 {
271  return ginPostingListDecodeAllSegments(plist,
272  SizeOfGinPostingList(plist),
273  ndecoded);
274 }
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:336
ItemPointer ginPostingListDecodeAllSegments(GinPostingList *segment, int len, int *ndecoded_out)

◆ ginPostingListDecodeAllSegments()

ItemPointer ginPostingListDecodeAllSegments ( GinPostingList ptr,
int  len,
int *  ndecoded 
)

Definition at line 282 of file ginpostinglist.c.

References Assert, GinPostingList::bytes, decode_varbyte(), GinPostingList::first, ginCompareItemPointers(), GinNextPostingListSegment, ItemPointerGetOffsetNumber, itemptr_to_uint64(), GinPostingList::nbytes, OffsetNumberIsValid, palloc(), repalloc(), uint64_to_itemptr(), and val.

Referenced by GinDataLeafPageGetItems(), ginPostingListDecode(), and ginPostingListDecodeAllSegmentsToTbm().

283 {
284  ItemPointer result;
285  int nallocated;
286  uint64 val;
287  char *endseg = ((char *) segment) + len;
288  int ndecoded;
289  unsigned char *ptr;
290  unsigned char *endptr;
291 
292  /*
293  * Guess an initial size of the array.
294  */
295  nallocated = segment->nbytes * 2 + 1;
296  result = palloc(nallocated * sizeof(ItemPointerData));
297 
298  ndecoded = 0;
299  while ((char *) segment < endseg)
300  {
301  /* enlarge output array if needed */
302  if (ndecoded >= nallocated)
303  {
304  nallocated *= 2;
305  result = repalloc(result, nallocated * sizeof(ItemPointerData));
306  }
307 
308  /* copy the first item */
310  Assert(ndecoded == 0 || ginCompareItemPointers(&segment->first, &result[ndecoded - 1]) > 0);
311  result[ndecoded] = segment->first;
312  ndecoded++;
313 
314  val = itemptr_to_uint64(&segment->first);
315  ptr = segment->bytes;
316  endptr = segment->bytes + segment->nbytes;
317  while (ptr < endptr)
318  {
319  /* enlarge output array if needed */
320  if (ndecoded >= nallocated)
321  {
322  nallocated *= 2;
323  result = repalloc(result, nallocated * sizeof(ItemPointerData));
324  }
325 
326  val += decode_varbyte(&ptr);
327 
328  uint64_to_itemptr(val, &result[ndecoded]);
329  ndecoded++;
330  }
331  segment = GinNextPostingListSegment(segment);
332  }
333 
334  if (ndecoded_out)
335  *ndecoded_out = ndecoded;
336  return result;
337 }
static uint64 decode_varbyte(unsigned char **ptr)
#define GinNextPostingListSegment(cur)
Definition: ginblock.h:337
static void uint64_to_itemptr(uint64 val, ItemPointer iptr)
uint16 nbytes
Definition: ginblock.h:332
#define Assert(condition)
Definition: c.h:699
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
static uint64 itemptr_to_uint64(const ItemPointer iptr)
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1044
static int ginCompareItemPointers(ItemPointer a, ItemPointer b)
Definition: gin_private.h:460
void * palloc(Size size)
Definition: mcxt.c:924
#define OffsetNumberIsValid(offsetNumber)
Definition: off.h:40
long val
Definition: informix.c:689

◆ ginPostingListDecodeAllSegmentsToTbm()

int ginPostingListDecodeAllSegmentsToTbm ( GinPostingList ptr,
int  totalsize,
TIDBitmap tbm 
)

Definition at line 343 of file ginpostinglist.c.

References ginPostingListDecodeAllSegments(), pfree(), and tbm_add_tuples().

Referenced by GinDataLeafPageGetItemsToTbm().

345 {
346  int ndecoded;
347  ItemPointer items;
348 
349  items = ginPostingListDecodeAllSegments(ptr, len, &ndecoded);
350  tbm_add_tuples(tbm, items, ndecoded, false);
351  pfree(items);
352 
353  return ndecoded;
354 }
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:376
void pfree(void *pointer)
Definition: mcxt.c:1031
ItemPointer ginPostingListDecodeAllSegments(GinPostingList *segment, int len, int *ndecoded_out)

◆ ginPrepareEntryScan()

void ginPrepareEntryScan ( GinBtree  btree,
OffsetNumber  attnum,
Datum  key,
GinNullCategory  category,
GinState ginstate 
)

Definition at line 745 of file ginentrypage.c.

References attnum, GinBtreeData::beginPlaceToPage, GinBtreeData::entryAttnum, entryBeginPlaceToPage(), GinBtreeData::entryCategory, entryExecPlaceToPage(), entryFindChildPtr(), entryGetLeftMostPage(), entryIsMoveRight(), GinBtreeData::entryKey, entryLocateEntry(), entryLocateLeafEntry(), entryPrepareDownlink(), GinBtreeData::execPlaceToPage, GinBtreeData::fillRoot, GinBtreeData::findChildPage, GinBtreeData::findChildPtr, GinBtreeData::findItem, GinBtreeData::fullScan, GinBtreeData::getLeftMostChild, GIN_ROOT_BLKNO, ginEntryFillRoot(), GinBtreeData::ginstate, GinState::index, GinBtreeData::index, GinBtreeData::isBuild, GinBtreeData::isData, GinBtreeData::isMoveRight, GinBtreeData::prepareDownlink, and GinBtreeData::rootBlkno.

Referenced by ginEntryInsert(), and startScanEntry().

748 {
749  memset(btree, 0, sizeof(GinBtreeData));
750 
751  btree->index = ginstate->index;
752  btree->rootBlkno = GIN_ROOT_BLKNO;
753  btree->ginstate = ginstate;
754 
757  btree->isMoveRight = entryIsMoveRight;
762  btree->fillRoot = ginEntryFillRoot;
764 
765  btree->isData = false;
766  btree->fullScan = false;
767  btree->isBuild = false;
768 
769  btree->entryAttnum = attnum;
770  btree->entryKey = key;
771  btree->entryCategory = category;
772 }
static bool entryIsMoveRight(GinBtree btree, Page page)
Definition: ginentrypage.c:244
GinState * ginstate
Definition: gin_private.h:162
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
Definition: gin_private.h:156
Relation index
Definition: gin_private.h:53
static BlockNumber entryLocateEntry(GinBtree btree, GinBtreeStack *stack)
Definition: ginentrypage.c:271
static OffsetNumber entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
Definition: ginentrypage.c:406
bool(* isMoveRight)(GinBtree, Page)
Definition: gin_private.h:148
BlockNumber rootBlkno
Definition: gin_private.h:161
bool(* findItem)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:149
OffsetNumber entryAttnum
Definition: gin_private.h:167
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
Definition: gin_private.h:153
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
Definition: gin_private.h:154
Datum entryKey
Definition: gin_private.h:168
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:146
void ginEntryFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
Definition: ginentrypage.c:721
GinNullCategory entryCategory
Definition: gin_private.h:169
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:147
static bool entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack)
Definition: ginentrypage.c:347
static BlockNumber entryGetLeftMostPage(GinBtree btree, Page page)
Definition: ginentrypage.c:447
static GinPlaceToPageRC entryBeginPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertPayload, BlockNumber updateblkno, void **ptp_workspace, Page *newlpage, Page *newrpage)
Definition: ginentrypage.c:528
static void entryExecPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertPayload, BlockNumber updateblkno, void *ptp_workspace)
Definition: ginentrypage.c:555
Relation index
Definition: gin_private.h:160
static void * entryPrepareDownlink(GinBtree btree, Buffer lbuf)
Definition: ginentrypage.c:700
int16 attnum
Definition: pg_attribute.h:79
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:155
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:152
#define GIN_ROOT_BLKNO
Definition: ginblock.h:51

◆ ginReadTuple()

ItemPointer ginReadTuple ( GinState ginstate,
OffsetNumber  attnum,
IndexTuple  itup,
int *  nitems 
)

Definition at line 163 of file ginentrypage.c.

References elog, ERROR, GinGetNPosting, GinGetPosting, GinItupIsCompressed, ginPostingListDecode(), and palloc().

Referenced by addItemPointersToLeafTuple(), collectMatchBitmap(), and startScanEntry().

165 {
166  Pointer ptr = GinGetPosting(itup);
167  int nipd = GinGetNPosting(itup);
168  ItemPointer ipd;
169  int ndecoded;
170 
171  if (GinItupIsCompressed(itup))
172  {
173  if (nipd > 0)
174  {
175  ipd = ginPostingListDecode((GinPostingList *) ptr, &ndecoded);
176  if (nipd != ndecoded)
177  elog(ERROR, "number of items mismatch in GIN entry tuple, %d in tuple header, %d decoded",
178  nipd, ndecoded);
179  }
180  else
181  {
182  ipd = palloc(0);
183  }
184  }
185  else
186  {
187  ipd = (ItemPointer) palloc(sizeof(ItemPointerData) * nipd);
188  memcpy(ipd, ptr, sizeof(ItemPointerData) * nipd);
189  }
190  *nitems = nipd;
191  return ipd;
192 }
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded)
#define GinGetNPosting(itup)
Definition: ginblock.h:222
#define GinGetPosting(itup)
Definition: ginblock.h:232
#define GinItupIsCompressed(itup)
Definition: ginblock.h:233
ItemPointerData * ItemPointer
Definition: itemptr.h:49
char * Pointer
Definition: c.h:302
#define ERROR
Definition: elog.h:43
void * palloc(Size size)
Definition: mcxt.c:924
#define elog
Definition: elog.h:219

◆ ginrescan()

void ginrescan ( IndexScanDesc  scan,
ScanKey  key,
int  nscankeys,
ScanKey  orderbys,
int  norderbys 
)

Definition at line 413 of file ginscan.c.

References ginFreeScanKeys(), IndexScanDescData::keyData, memmove, IndexScanDescData::numberOfKeys, and IndexScanDescData::opaque.

Referenced by ginhandler().

415 {
416  GinScanOpaque so = (GinScanOpaque) scan->opaque;
417 
418  ginFreeScanKeys(so);
419 
420  if (scankey && scan->numberOfKeys > 0)
421  {
422  memmove(scan->keyData, scankey,
423  scan->numberOfKeys * sizeof(ScanKeyData));
424  }
425 }
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:363
#define memmove(d, s, c)
Definition: c.h:1135
ScanKey keyData
Definition: relscan.h:95
void ginFreeScanKeys(GinScanOpaque so)
Definition: ginscan.c:232

◆ ginScanBeginPostingTree()

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

Definition at line 1922 of file gindatapage.c.

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

Referenced by scanPostingTree(), and startScanEntry().

1924 {
1925  GinBtreeStack *stack;
1926 
1927  ginPrepareDataScan(btree, index, rootBlkno);
1928 
1929  btree->fullScan = true;
1930 
1931  stack = ginFindLeafPage(btree, true, snapshot);
1932 
1933  return stack;
1934 }
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, Snapshot snapshot)
Definition: ginbtree.c:77
static void ginPrepareDataScan(GinBtree btree, Relation index, BlockNumber rootBlkno)
Definition: gindatapage.c:1868

◆ ginStepRight()

Buffer ginStepRight ( Buffer  buffer,
Relation  index,
int  lockmode 
)

Definition at line 169 of file ginbtree.c.

References BufferGetPage, elog, ERROR, GinPageGetOpaque, GinPageIsData, GinPageIsDeleted, GinPageIsLeaf, LockBuffer(), ReadBuffer(), and UnlockReleaseBuffer().

Referenced by entryLoadMoreItems(), ginFindLeafPage(), ginFindParents(), ginFinishSplit(), moveRightIfItNeeded(), and scanPostingTree().

170 {
171  Buffer nextbuffer;
172  Page page = BufferGetPage(buffer);
173  bool isLeaf = GinPageIsLeaf(page);
174  bool isData = GinPageIsData(page);
175  BlockNumber blkno = GinPageGetOpaque(page)->rightlink;
176 
177  nextbuffer = ReadBuffer(index, blkno);
178  LockBuffer(nextbuffer, lockmode);
180 
181  /* Sanity check that the page we stepped to is of similar kind. */
182  page = BufferGetPage(nextbuffer);
183  if (isLeaf != GinPageIsLeaf(page) || isData != GinPageIsData(page))
184  elog(ERROR, "right sibling of GIN page is of different type");
185 
186  /*
187  * Given the proper lock sequence above, we should never land on a deleted
188  * page.
189  */
190  if (GinPageIsDeleted(page))
191  elog(ERROR, "right sibling of GIN page was deleted");
192 
193  return nextbuffer;
194 }
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ERROR
Definition: elog.h:43
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define GinPageIsDeleted(page)
Definition: ginblock.h:123
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define GinPageIsData(page)
Definition: ginblock.h:114
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define elog
Definition: elog.h:219
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

◆ ginTraverseLock()

int ginTraverseLock ( Buffer  buffer,
bool  searchMode 
)

Definition at line 36 of file ginbtree.c.

References BufferGetPage, GIN_EXCLUSIVE, GIN_SHARE, GIN_UNLOCK, GinPageIsLeaf, and LockBuffer().

Referenced by ginCompareItemPointers(), ginFindLeafPage(), and ginVacuumPostingTreeLeaves().

37 {
38  Page page;
39  int access = GIN_SHARE;
40 
42  page = BufferGetPage(buffer);
43  if (GinPageIsLeaf(page))
44  {
45  if (searchMode == false)
46  {
47  /* we should relock our page */
50 
51  /* But root can become non-leaf during relock */
52  if (!GinPageIsLeaf(page))
53  {
54  /* restore old lock type (very rare) */
57  }
58  else
59  access = GIN_EXCLUSIVE;
60  }
61  }
62 
63  return access;
64 }
#define GIN_UNLOCK
Definition: gin_private.h:43
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define GIN_SHARE
Definition: gin_private.h:44
#define GIN_EXCLUSIVE
Definition: gin_private.h:45
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
Pointer Page
Definition: bufpage.h:74

◆ gintuple_get_attrnum()

OffsetNumber gintuple_get_attrnum ( GinState ginstate,
IndexTuple  tuple 
)

Definition at line 217 of file ginutil.c.

References Assert, DatumGetUInt16, FirstOffsetNumber, index_getattr, GinState::oneCol, and GinState::tupdesc.

Referenced by addItemPointersToLeafTuple(), collectMatchBitmap(), collectMatchesForHeapRow(), entryIsMoveRight(), entryLocateEntry(), entryLocateLeafEntry(), gintuple_get_key(), ginVacuumEntryPage(), matchPartialInPendingList(), and processPendingPage().

218 {
219  OffsetNumber colN;
220 
221  if (ginstate->oneCol)
222  {
223  /* column number is not stored explicitly */
224  colN = FirstOffsetNumber;
225  }
226  else
227  {
228  Datum res;
229  bool isnull;
230 
231  /*
232  * First attribute is always int16, so we can safely use any tuple
233  * descriptor to obtain first attribute of tuple
234  */
235  res = index_getattr(tuple, FirstOffsetNumber, ginstate->tupdesc[0],
236  &isnull);
237  Assert(!isnull);
238 
239  colN = DatumGetUInt16(res);
240  Assert(colN >= FirstOffsetNumber && colN <= ginstate->origTupdesc->natts);
241  }
242 
243  return colN;
244 }
#define DatumGetUInt16(X)
Definition: postgres.h:443
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
uintptr_t Datum
Definition: postgres.h:367
TupleDesc tupdesc[INDEX_MAX_KEYS]
Definition: gin_private.h:68
#define Assert(condition)
Definition: c.h:699
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
bool oneCol
Definition: gin_private.h:54

◆ gintuple_get_key()

Datum gintuple_get_key ( GinState ginstate,
IndexTuple  tuple,
GinNullCategory category 
)

Definition at line 250 of file ginutil.c.

References FirstOffsetNumber, GIN_CAT_NORM_KEY, GinGetNullCategory, gintuple_get_attrnum(), index_getattr, OffsetNumberNext, GinState::oneCol, GinState::origTupdesc, and GinState::tupdesc.

Referenced by addItemPointersToLeafTuple(), collectMatchBitmap(), collectMatchesForHeapRow(), entryIsMoveRight(), entryLocateEntry(), entryLocateLeafEntry(), ginVacuumEntryPage(), matchPartialInPendingList(), and processPendingPage().

252 {
253  Datum res;
254  bool isnull;
255 
256  if (ginstate->oneCol)
257  {
258  /*
259  * Single column index doesn't store attribute numbers in tuples
260  */
261  res = index_getattr(tuple, FirstOffsetNumber, ginstate->origTupdesc,
262  &isnull);
263  }
264  else
265  {
266  /*
267  * Since the datum type depends on which index column it's from, we
268  * must be careful to use the right tuple descriptor here.
269  */
270  OffsetNumber colN = gintuple_get_attrnum(ginstate, tuple);
271 
273  ginstate->tupdesc[colN - 1],
274  &isnull);
275  }
276 
277  if (isnull)
278  *category = GinGetNullCategory(tuple, ginstate);
279  else
280  *category = GIN_CAT_NORM_KEY;
281 
282  return res;
283 }
#define GinGetNullCategory(itup, ginstate)
Definition: ginblock.h:214
uint16 OffsetNumber
Definition: off.h:24
OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple)
Definition: ginutil.c:217
#define GIN_CAT_NORM_KEY
Definition: ginblock.h:202
#define FirstOffsetNumber
Definition: off.h:27
uintptr_t Datum
Definition: postgres.h:367
TupleDesc tupdesc[INDEX_MAX_KEYS]
Definition: gin_private.h:68
#define OffsetNumberNext(offsetNumber)
Definition: off.h:53
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
TupleDesc origTupdesc
Definition: gin_private.h:67
bool oneCol
Definition: gin_private.h:54

◆ ginvacuumcleanup()

IndexBulkDeleteResult* ginvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)

Definition at line 674 of file ginvacuum.c.

References IndexVacuumInfo::analyze_only, Assert, DataPageDeleteStack::blkno, buffer, BufferGetPage, IndexVacuumInfo::estimated_count, IndexBulkDeleteResult::estimated_count, ExclusiveLock, GIN_ROOT_BLKNO, GIN_SHARE, ginInsertCleanup(), GinPageIsData, GinPageIsDeleted, GinPageIsLeaf, GinPageIsList, GinVacuumState::ginstate, ginUpdateStats(), IndexVacuumInfo::index, IndexFreeSpaceMapVacuum(), initGinState(), IsAutoVacuumWorkerProcess(), LockBuffer(), LockRelationForExtension(), MAIN_FORKNUM, GinStatsData::nDataPages, GinStatsData::nEntries, GinStatsData::nEntryPages, GinStatsData::nTotalPages, IndexVacuumInfo::num_heap_tuples, IndexBulkDeleteResult::num_index_tuples, IndexBulkDeleteResult::num_pages, PageGetMaxOffsetNumber, PageIsNew, IndexBulkDeleteResult::pages_free, palloc0(), RBM_NORMAL, ReadBufferExtended(), RecordFreeIndexPage(), RELATION_IS_LOCAL, RelationGetNumberOfBlocks, IndexVacuumInfo::strategy, UnlockRelationForExtension(), UnlockReleaseBuffer(), and vacuum_delay_point().

Referenced by ginhandler().

675 {
676  Relation index = info->index;
677  bool needLock;
678  BlockNumber npages,
679  blkno;
680  BlockNumber totFreePages;
681  GinState ginstate;
682  GinStatsData idxStat;
683 
684  /*
685  * In an autovacuum analyze, we want to clean up pending insertions.
686  * Otherwise, an ANALYZE-only call is a no-op.
687  */
688  if (info->analyze_only)
689  {
691  {
692  initGinState(&ginstate, index);
693  ginInsertCleanup(&ginstate, false, true, true, stats);
694  }
695  return stats;
696  }
697 
698  /*
699  * Set up all-zero stats and cleanup pending inserts if ginbulkdelete
700  * wasn't called
701  */
702  if (stats == NULL)
703  {
705  initGinState(&ginstate, index);
707  false, true, stats);
708  }
709 
710  memset(&idxStat, 0, sizeof(idxStat));
711 
712  /*
713  * XXX we always report the heap tuple count as the number of index
714  * entries. This is bogus if the index is partial, but it's real hard to
715  * tell how many distinct heap entries are referenced by a GIN index.
716  */
717  stats->num_index_tuples = info->num_heap_tuples;
718  stats->estimated_count = info->estimated_count;
719 
720  /*
721  * Need lock unless it's local to this backend.
722  */
723  needLock = !RELATION_IS_LOCAL(index);
724 
725  if (needLock)
727  npages = RelationGetNumberOfBlocks(index);
728  if (needLock)
730 
731  totFreePages = 0;
732 
733  for (blkno = GIN_ROOT_BLKNO; blkno < npages; blkno++)
734  {
735  Buffer buffer;
736  Page page;
737 
739 
740  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
741  RBM_NORMAL, info->strategy);
742  LockBuffer(buffer, GIN_SHARE);
743  page = (Page) BufferGetPage(buffer);
744 
745  if (PageIsNew(page) || GinPageIsDeleted(page))
746  {
747  Assert(blkno != GIN_ROOT_BLKNO);
748  RecordFreeIndexPage(index, blkno);
749  totFreePages++;
750  }
751  else if (GinPageIsData(page))
752  {
753  idxStat.nDataPages++;
754  }
755  else if (!GinPageIsList(page))
756  {
757  idxStat.nEntryPages++;
758 
759  if (GinPageIsLeaf(page))
760  idxStat.nEntries += PageGetMaxOffsetNumber(page);
761  }
762 
763  UnlockReleaseBuffer(buffer);
764  }
765 
766  /* Update the metapage with accurate page and entry counts */
767  idxStat.nTotalPages = npages;
768  ginUpdateStats(info->index, &idxStat);
769 
770  /* Finally, vacuum the FSM */
772 
773  stats->pages_free = totFreePages;
774 
775  if (needLock)
777  stats->num_pages = RelationGetNumberOfBlocks(index);
778  if (needLock)
780 
781  return stats;
782 }
BlockNumber nEntryPages
Definition: gin.h:45
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:528
bool analyze_only
Definition: genam.h:47
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:640
BufferAccessStrategy strategy
Definition: genam.h:51
Relation index
Definition: genam.h:46
int64 nEntries
Definition: gin.h:47
uint32 BlockNumber
Definition: block.h:31
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
Definition: type.h:89
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
BlockNumber num_pages
Definition: genam.h:73
BlockNumber pages_free
Definition: genam.h:79
void ginUpdateStats(Relation index, const GinStatsData *stats)
Definition: ginutil.c:669
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:88
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3295
#define GIN_SHARE
Definition: gin_private.h:44
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:332
void * palloc0(Size size)
Definition: mcxt.c:955
#define GinPageIsDeleted(page)
Definition: ginblock.h:123
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:382
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
BlockNumber nDataPages
Definition: gin.h:46
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition: ginfast.c:762
#define GinPageIsData(page)
Definition: ginblock.h:114
double num_heap_tuples
Definition: genam.h:50
#define Assert(condition)
Definition: c.h:699
void IndexFreeSpaceMapVacuum(Relation rel)
Definition: indexfsm.c:71
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#define GinPageIsList(page)
Definition: ginblock.h:116
BlockNumber nTotalPages
Definition: gin.h:44
#define PageIsNew(page)
Definition: bufpage.h:225
void vacuum_delay_point(void)
Definition: vacuum.c:1672
void RecordFreeIndexPage(Relation rel, BlockNumber freeBlock)
Definition: indexfsm.c:52
double num_index_tuples
Definition: genam.h:76
int Buffer
Definition: buf.h:23
bool estimated_count
Definition: genam.h:75
#define GIN_ROOT_BLKNO
Definition: ginblock.h:51
Pointer Page
Definition: bufpage.h:74
bool estimated_count
Definition: genam.h:48

◆ ginVacuumItemPointers()

ItemPointer ginVacuumItemPointers ( GinVacuumState gvs,
ItemPointerData items,
int  nitem,
int *  nremaining 
)

Definition at line 48 of file ginvacuum.c.

References GinVacuumState::callback, GinVacuumState::callback_state, i, IndexBulkDeleteResult::num_index_tuples, palloc(), remaining, GinVacuumState::result, and IndexBulkDeleteResult::tuples_removed.

Referenced by ginVacuumEntryPage(), and ginVacuumPostingTreeLeaf().

50 {
51  int i,
52  remaining = 0;
53  ItemPointer tmpitems = NULL;
54 
55  /*
56  * Iterate over TIDs array
57  */
58  for (i = 0; i < nitem; i++)
59  {
60  if (gvs->callback(items + i, gvs->callback_state))
61  {
62  gvs->result->tuples_removed += 1;
63  if (!tmpitems)
64  {
65  /*
66  * First TID to be deleted: allocate memory to hold the
67  * remaining items.
68  */
69  tmpitems = palloc(sizeof(ItemPointerData) * nitem);
70  memcpy(tmpitems, items, sizeof(ItemPointerData) * i);
71  }
72  }
73  else
74  {
75  gvs->result->num_index_tuples += 1;
76  if (tmpitems)
77  tmpitems[remaining] = items[i];
78  remaining++;
79  }
80  }
81 
82  *nremaining = remaining;
83  return tmpitems;
84 }
int remaining
Definition: informix.c:692
double tuples_removed
Definition: genam.h:77
IndexBulkDeleteResult * result
Definition: ginvacuum.c:31
IndexBulkDeleteCallback callback
Definition: ginvacuum.c:32
void * callback_state
Definition: ginvacuum.c:33
void * palloc(Size size)
Definition: mcxt.c:924
int i
double num_index_tuples
Definition: genam.h:76

◆ ginVacuumPostingTreeLeaf()

void ginVacuumPostingTreeLeaf ( Relation  rel,
Buffer  buf,
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->