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)
 
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 ginPrepareDataScan (GinBtree btree, Relation index, BlockNumber rootBlkno)
 
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:37

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 258 of file gin_private.h.

◆ GinScanEntryData

◆ GinScanKey

Definition at line 256 of file gin_private.h.

◆ GinScanKeyData

◆ GinScanOpaque

◆ GinScanOpaqueData

◆ GinState

◆ GinTupleCollector

◆ GinVacuumState

Definition at line 235 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 
)

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

1763 {
1764  BlockNumber blkno;
1765  Buffer buffer;
1766  Page tmppage;
1767  Page page;
1768  Pointer ptr;
1769  int nrootitems;
1770  int rootsize;
1771 
1772  /* Construct the new root page in memory first. */
1773  tmppage = (Page) palloc(BLCKSZ);
1774  GinInitPage(tmppage, GIN_DATA | GIN_LEAF | GIN_COMPRESSED, BLCKSZ);
1775  GinPageGetOpaque(tmppage)->rightlink = InvalidBlockNumber;
1776 
1777  /*
1778  * Write as many of the items to the root page as fit. In segments of max
1779  * GinPostingListSegmentMaxSize bytes each.
1780  */
1781  nrootitems = 0;
1782  rootsize = 0;
1783  ptr = (Pointer) GinDataLeafPageGetPostingList(tmppage);
1784  while (nrootitems < nitems)
1785  {
1786  GinPostingList *segment;
1787  int npacked;
1788  int segsize;
1789 
1790  segment = ginCompressPostingList(&items[nrootitems],
1791  nitems - nrootitems,
1793  &npacked);
1794  segsize = SizeOfGinPostingList(segment);
1795  if (rootsize + segsize > GinDataPageMaxDataSize)
1796  break;
1797 
1798  memcpy(ptr, segment, segsize);
1799  ptr += segsize;
1800  rootsize += segsize;
1801  nrootitems += npacked;
1802  pfree(segment);
1803  }
1804  GinDataPageSetDataSize(tmppage, rootsize);
1805 
1806  /*
1807  * All set. Get a new physical page, and copy the in-memory page to it.
1808  */
1809  buffer = GinNewBuffer(index);
1810  page = BufferGetPage(buffer);
1811  blkno = BufferGetBlockNumber(buffer);
1812 
1814 
1815  PageRestoreTempPage(tmppage, page);
1816  MarkBufferDirty(buffer);
1817 
1818  if (RelationNeedsWAL(index))
1819  {
1820  XLogRecPtr recptr;
1822 
1823  data.size = rootsize;
1824 
1825  XLogBeginInsert();
1826  XLogRegisterData((char *) &data, sizeof(ginxlogCreatePostingTree));
1827 
1829  rootsize);
1831 
1832  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_PTREE);
1833  PageSetLSN(page, recptr);
1834  }
1835 
1836  UnlockReleaseBuffer(buffer);
1837 
1838  END_CRIT_SECTION();
1839 
1840  /* During index build, count the newly-added data page */
1841  if (buildStats)
1842  buildStats->nDataPages++;
1843 
1844  elog(DEBUG2, "created GIN posting tree with %d items", nrootitems);
1845 
1846  /*
1847  * Add any remaining TIDs to the newly-created posting tree.
1848  */
1849  if (nitems > nrootitems)
1850  {
1851  ginInsertItemPointers(index, blkno,
1852  items + nrootitems,
1853  nitems - nrootitems,
1854  buildStats);
1855  }
1856 
1857  return blkno;
1858 }
GinPostingList * ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:289
#define GinPostingListSegmentMaxSize
Definition: gindatapage.c:33
void ginInsertItemPointers(Relation index, BlockNumber rootBlkno, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gindatapage.c:1887
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:407
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:340
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:300
void pfree(void *pointer)
Definition: mcxt.c:949
char * Pointer
Definition: c.h:273
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:269
BlockNumber nDataPages
Definition: gin.h:46
uint64 XLogRecPtr
Definition: xlogdefs.h:21
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
#define InvalidBlockNumber
Definition: block.h:33
#define RelationNeedsWAL(relation)
Definition: rel.h:505
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define GinDataPageMaxDataSize
Definition: ginblock.h:310
void * palloc(Size size)
Definition: mcxt.c:848
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:333
#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 GIN_LEAF
Definition: ginblock.h:40

◆ freeGinBtreeStack()

void freeGinBtreeStack ( GinBtreeStack stack)

Definition at line 193 of file ginbtree.c.

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

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

194 {
195  while (stack)
196  {
197  GinBtreeStack *tmp = stack->parent;
198 
199  if (stack->buffer != InvalidBuffer)
200  ReleaseBuffer(stack->buffer);
201 
202  pfree(stack);
203  stack = tmp;
204  }
205 }
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
void pfree(void *pointer)
Definition: mcxt.c:949
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:412

◆ 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:90
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:364
MemoryContext keyCtx
Definition: gin_private.h:359
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:86
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
GinScanKey keys
Definition: gin_private.h:352
MemoryContext tempCtx
Definition: gin_private.h:349
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
#define Assert(condition)
Definition: c.h:670
void * palloc(Size size)
Definition: mcxt.c:848
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 311 of file gininsert.c.

References GinBuildState::accum, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), 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, START_CRIT_SECTION, GinBuildState::tmpCtx, UnlockReleaseBuffer(), XLOG_GIN_CREATE_INDEX, XLogBeginInsert(), XLogInsert(), and XLogRegisterBuffer().

Referenced by ginhandler().

312 {
313  IndexBuildResult *result;
314  double reltuples;
315  GinBuildState buildstate;
316  Buffer RootBuffer,
317  MetaBuffer;
319  Datum key;
320  GinNullCategory category;
321  uint32 nlist;
322  MemoryContext oldCtx;
323  OffsetNumber attnum;
324 
325  if (RelationGetNumberOfBlocks(index) != 0)
326  elog(ERROR, "index \"%s\" already contains data",
327  RelationGetRelationName(index));
328 
329  initGinState(&buildstate.ginstate, index);
330  buildstate.indtuples = 0;
331  memset(&buildstate.buildStats, 0, sizeof(GinStatsData));
332 
333  /* initialize the meta page */
334  MetaBuffer = GinNewBuffer(index);
335 
336  /* initialize the root page */
337  RootBuffer = GinNewBuffer(index);
338 
340  GinInitMetabuffer(MetaBuffer);
341  MarkBufferDirty(MetaBuffer);
342  GinInitBuffer(RootBuffer, GIN_LEAF);
343  MarkBufferDirty(RootBuffer);
344 
345  if (RelationNeedsWAL(index))
346  {
347  XLogRecPtr recptr;
348  Page page;
349 
350  XLogBeginInsert();
352  XLogRegisterBuffer(1, RootBuffer, REGBUF_WILL_INIT);
353 
354  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_INDEX);
355 
356  page = BufferGetPage(RootBuffer);
357  PageSetLSN(page, recptr);
358 
359  page = BufferGetPage(MetaBuffer);
360  PageSetLSN(page, recptr);
361  }
362 
363  UnlockReleaseBuffer(MetaBuffer);
364  UnlockReleaseBuffer(RootBuffer);
366 
367  /* count the root as first entry page */
368  buildstate.buildStats.nEntryPages++;
369 
370  /*
371  * create a temporary memory context that is used to hold data not yet
372  * dumped out to the index
373  */
375  "Gin build temporary context",
377 
378  /*
379  * create a temporary memory context that is used for calling
380  * ginExtractEntries(), and can be reset after each tuple
381  */
383  "Gin build temporary context for user-defined function",
385 
386  buildstate.accum.ginstate = &buildstate.ginstate;
387  ginInitBA(&buildstate.accum);
388 
389  /*
390  * Do the heap scan. We disallow sync scan here because dataPlaceToPage
391  * prefers to receive tuples in TID order.
392  */
393  reltuples = IndexBuildHeapScan(heap, index, indexInfo, false,
394  ginBuildCallback, (void *) &buildstate);
395 
396  /* dump remaining entries to the index */
397  oldCtx = MemoryContextSwitchTo(buildstate.tmpCtx);
398  ginBeginBAScan(&buildstate.accum);
399  while ((list = ginGetBAEntry(&buildstate.accum,
400  &attnum, &key, &category, &nlist)) != NULL)
401  {
402  /* there could be many entries, so be willing to abort here */
404  ginEntryInsert(&buildstate.ginstate, attnum, key, category,
405  list, nlist, &buildstate.buildStats);
406  }
407  MemoryContextSwitchTo(oldCtx);
408 
409  MemoryContextDelete(buildstate.funcCtx);
410  MemoryContextDelete(buildstate.tmpCtx);
411 
412  /*
413  * Update metapage stats
414  */
416  ginUpdateStats(index, &buildstate.buildStats);
417 
418  /*
419  * Return statistics
420  */
421  result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
422 
423  result->heap_tuples = reltuples;
424  result->index_tuples = buildstate.indtuples;
425 
426  return result;
427 }
BlockNumber nEntryPages
Definition: gin.h:45
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:289
void GinInitMetabuffer(Buffer b)
Definition: ginutil.c:359
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
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:33
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:32
static void ginBuildCallback(Relation index, HeapTuple htup, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition: gininsert.c:270
uint16 OffsetNumber
Definition: off.h:24
GinState ginstate
Definition: gininsert.c:31
void ginEntryInsert(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gininsert.c:177
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ERROR
Definition: elog.h:43
signed char GinNullCategory
Definition: ginblock.h:197
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
void ginUpdateStats(Relation index, const GinStatsData *stats)
Definition: ginutil.c:669
BuildAccumulator accum
Definition: gininsert.c:36
#define REGBUF_STANDARD
Definition: xloginsert.h:34
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:86
#define RelationGetRelationName(relation)
Definition: rel.h:436
unsigned int uint32
Definition: c.h:296
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
GinState * ginstate
Definition: gin_private.h:407
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define XLOG_GIN_CREATE_INDEX
Definition: ginxlog.h:19
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
uintptr_t Datum
Definition: postgres.h:372
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void GinInitBuffer(Buffer b, uint32 f)
Definition: ginutil.c:353
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:505
void ginBeginBAScan(BuildAccumulator *accum)
Definition: ginbulk.c:257
double IndexBuildHeapScan(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool allow_sync, IndexBuildCallback callback, void *callback_state)
Definition: index.c:2178
void * palloc(Size size)
Definition: mcxt.c:848
MemoryContext tmpCtx
Definition: gininsert.c:34
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define elog
Definition: elog.h:219
MemoryContext funcCtx
Definition: gininsert.c:35
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
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 433 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().

434 {
435  Buffer RootBuffer,
436  MetaBuffer;
437 
438  /* An empty GIN index has two pages. */
439  MetaBuffer =
441  LockBuffer(MetaBuffer, BUFFER_LOCK_EXCLUSIVE);
442  RootBuffer =
444  LockBuffer(RootBuffer, BUFFER_LOCK_EXCLUSIVE);
445 
446  /* Initialize and xlog metabuffer and root buffer. */
448  GinInitMetabuffer(MetaBuffer);
449  MarkBufferDirty(MetaBuffer);
450  log_newpage_buffer(MetaBuffer, true);
451  GinInitBuffer(RootBuffer, GIN_LEAF);
452  MarkBufferDirty(RootBuffer);
453  log_newpage_buffer(RootBuffer, false);
455 
456  /* Unlock and release the buffers. */
457  UnlockReleaseBuffer(MetaBuffer);
458  UnlockReleaseBuffer(RootBuffer);
459 }
void GinInitMetabuffer(Buffer b)
Definition: ginutil.c:359
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:353
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 544 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().

546 {
547  Relation index = info->index;
548  BlockNumber blkno = GIN_ROOT_BLKNO;
549  GinVacuumState gvs;
550  Buffer buffer;
551  BlockNumber rootOfPostingTree[BLCKSZ / (sizeof(IndexTupleData) + sizeof(ItemId))];
552  uint32 nRoot;
553 
555  "Gin vacuum temporary context",
557  gvs.index = index;
558  gvs.callback = callback;
559  gvs.callback_state = callback_state;
560  gvs.strategy = info->strategy;
561  initGinState(&gvs.ginstate, index);
562 
563  /* first time through? */
564  if (stats == NULL)
565  {
566  /* Yes, so initialize stats to zeroes */
568 
569  /*
570  * and cleanup any pending inserts
571  */
573  false, true, stats);
574  }
575 
576  /* we'll re-count the tuples each time */
577  stats->num_index_tuples = 0;
578  gvs.result = stats;
579 
580  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
581  RBM_NORMAL, info->strategy);
582 
583  /* find leaf page */
584  for (;;)
585  {
586  Page page = BufferGetPage(buffer);
587  IndexTuple itup;
588 
589  LockBuffer(buffer, GIN_SHARE);
590 
591  Assert(!GinPageIsData(page));
592 
593  if (GinPageIsLeaf(page))
594  {
595  LockBuffer(buffer, GIN_UNLOCK);
596  LockBuffer(buffer, GIN_EXCLUSIVE);
597 
598  if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page))
599  {
600  LockBuffer(buffer, GIN_UNLOCK);
601  continue; /* check it one more */
602  }
603  break;
604  }
605 
607 
608  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber));
609  blkno = GinGetDownlink(itup);
610  Assert(blkno != InvalidBlockNumber);
611 
612  UnlockReleaseBuffer(buffer);
613  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
614  RBM_NORMAL, info->strategy);
615  }
616 
617  /* right now we found leftmost page in entry's BTree */
618 
619  for (;;)
620  {
621  Page page = BufferGetPage(buffer);
622  Page resPage;
623  uint32 i;
624 
625  Assert(!GinPageIsData(page));
626 
627  resPage = ginVacuumEntryPage(&gvs, buffer, rootOfPostingTree, &nRoot);
628 
629  blkno = GinPageGetOpaque(page)->rightlink;
630 
631  if (resPage)
632  {
634  PageRestoreTempPage(resPage, page);
635  MarkBufferDirty(buffer);
636  xlogVacuumPage(gvs.index, buffer);
637  UnlockReleaseBuffer(buffer);
639  }
640  else
641  {
642  UnlockReleaseBuffer(buffer);
643  }
644 
646 
647  for (i = 0; i < nRoot; i++)
648  {
649  ginVacuumPostingTree(&gvs, rootOfPostingTree[i]);
651  }
652 
653  if (blkno == InvalidBlockNumber) /* rightmost page */
654  break;
655 
656  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
657  RBM_NORMAL, info->strategy);
658  LockBuffer(buffer, GIN_EXCLUSIVE);
659  }
660 
662 
663  return gvs.result;
664 }
#define GIN_UNLOCK
Definition: gin_private.h:43
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:407
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
Relation index
Definition: ginvacuum.c:29
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:640
BufferAccessStrategy strategy
Definition: ginvacuum.c:34
#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:30
Definition: type.h:89
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
static void xlogVacuumPage(Relation index, Buffer buffer)
Definition: ginvacuum.c:89
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:48
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
static Page ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
Definition: ginvacuum.c:435
IndexBulkDeleteCallback callback
Definition: ginvacuum.c:31
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:86
unsigned int uint32
Definition: c.h:296
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
void * callback_state
Definition: ginvacuum.c:32
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3256
#define GIN_SHARE
Definition: gin_private.h:44
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:877
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:248
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition: ginfast.c:754
#define GinPageIsData(page)
Definition: ginblock.h:114
#define Assert(condition)
Definition: c.h:670
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
#define InvalidBlockNumber
Definition: block.h:33
int i
static void ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
Definition: ginvacuum.c:424
void vacuum_delay_point(void)
Definition: vacuum.c:1658
MemoryContext tmpCxt
Definition: ginvacuum.c:35
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:33

◆ ginCompareAttEntries()

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

Definition at line 413 of file ginutil.c.

References ginCompareEntries().

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

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

◆ ginCompareEntries()

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

Definition at line 391 of file ginutil.c.

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

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

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

◆ ginCompareItemPointers()

static int ginCompareItemPointers ( ItemPointer  a,
ItemPointer  b 
)
inlinestatic

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

462 {
463  uint64 ia = (uint64) GinItemPointerGetBlockNumber(a) << 32 | GinItemPointerGetOffsetNumber(a);
464  uint64 ib = (uint64) GinItemPointerGetBlockNumber(b) << 32 | GinItemPointerGetOffsetNumber(b);
465 
466  if (ia == ib)
467  return 0;
468  else if (ia > ib)
469  return 1;
470  else
471  return -1;
472 }
#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:631
ItemPointerData first
Definition: ginblock.h:328
void pfree(void *pointer)
Definition: mcxt.c:949
unsigned char bytes[FLEXIBLE_ARRAY_MEMBER]
Definition: ginblock.h:330
static char * buf
Definition: pg_test_fsync.c:67
uint16 nbytes
Definition: ginblock.h:329
#define Assert(condition)
Definition: c.h:670
static uint64 itemptr_to_uint64(const ItemPointer iptr)
static void encode_varbyte(uint64 val, unsigned char **ptr)
void * palloc(Size size)
Definition: mcxt.c:848
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:333
int i
#define SHORTALIGN(LEN)
Definition: c.h:619
long val
Definition: informix.c:689
#define offsetof(type, field)
Definition: c.h:593

◆ ginDataFillRoot()

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

Definition at line 1339 of file gindatapage.c.

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

Referenced by ginPrepareDataScan().

1340 {
1341  PostingItem li,
1342  ri;
1343 
1344  li.key = *GinDataPageGetRightBound(lpage);
1345  PostingItemSetBlockNumber(&li, lblkno);
1347 
1348  ri.key = *GinDataPageGetRightBound(rpage);
1349  PostingItemSetBlockNumber(&ri, rblkno);
1351 }
#define PostingItemSetBlockNumber(pointer, blockNumber)
Definition: ginblock.h:186
void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset)
Definition: gindatapage.c:376
ItemPointerData key
Definition: ginblock.h:180
#define InvalidOffsetNumber
Definition: off.h:26
#define GinDataPageGetRightBound(page)
Definition: ginblock.h:279

◆ GinDataLeafPageGetItems()

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

Definition at line 134 of file gindatapage.c.

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

Referenced by entryLoadMoreItems(), and startScanEntry().

135 {
136  ItemPointer result;
137 
138  if (GinPageIsCompressed(page))
139  {
142  Pointer endptr = ((Pointer) seg) + len;
144 
145  /* Skip to the segment containing advancePast+1 */
146  if (ItemPointerIsValid(&advancePast))
147  {
148  next = GinNextPostingListSegment(seg);
149  while ((Pointer) next < endptr &&
150  ginCompareItemPointers(&next->first, &advancePast) <= 0)
151  {
152  seg = next;
153  next = GinNextPostingListSegment(seg);
154  }
155  len = endptr - (Pointer) seg;
156  }
157 
158  if (len > 0)
159  result = ginPostingListDecodeAllSegments(seg, len, nitems);
160  else
161  {
162  result = NULL;
163  *nitems = 0;
164  }
165  }
166  else
167  {
168  ItemPointer tmp = dataLeafPageGetUncompressed(page, nitems);
169 
170  result = palloc((*nitems) * sizeof(ItemPointerData));
171  memcpy(result, tmp, (*nitems) * sizeof(ItemPointerData));
172  }
173 
174  return result;
175 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
static int32 next
Definition: blutils.c:210
#define GinPageIsCompressed(page)
Definition: ginblock.h:120
ItemPointerData first
Definition: ginblock.h:328
char * Pointer
Definition: c.h:273
#define GinNextPostingListSegment(cur)
Definition: ginblock.h:334
#define GinDataLeafPageGetPostingListSize(page)
Definition: ginblock.h:271
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:269
size_t Size
Definition: c.h:404
static int ginCompareItemPointers(ItemPointer a, ItemPointer b)
Definition: gin_private.h:461
void * palloc(Size size)
Definition: mcxt.c:848
ItemPointer ginPostingListDecodeAllSegments(GinPostingList *segment, int len, int *ndecoded_out)
static ItemPointer dataLeafPageGetUncompressed(Page page, int *nitems)
Definition: gindatapage.c:210

◆ GinDataLeafPageGetItemsToTbm()

int GinDataLeafPageGetItemsToTbm ( Page  page,
TIDBitmap tbm 
)

Definition at line 181 of file gindatapage.c.

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

Referenced by scanPostingTree().

182 {
183  ItemPointer uncompressed;
184  int nitems;
185 
186  if (GinPageIsCompressed(page))
187  {
190 
191  nitems = ginPostingListDecodeAllSegmentsToTbm(segment, len, tbm);
192  }
193  else
194  {
195  uncompressed = dataLeafPageGetUncompressed(page, &nitems);
196 
197  if (nitems > 0)
198  tbm_add_tuples(tbm, uncompressed, nitems, false);
199  }
200 
201  return nitems;
202 }
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:271
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:269
size_t Size
Definition: c.h:404
static ItemPointer dataLeafPageGetUncompressed(Page page, int *nitems)
Definition: gindatapage.c:210

◆ GinDataPageAddPostingItem()

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

Definition at line 376 of file gindatapage.c.

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

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

377 {
378  OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
379  char *ptr;
380 
382  Assert(!GinPageIsLeaf(page));
383 
384  if (offset == InvalidOffsetNumber)
385  {
386  ptr = (char *) GinDataPageGetPostingItem(page, maxoff + 1);
387  }
388  else
389  {
390  ptr = (char *) GinDataPageGetPostingItem(page, offset);
391  if (offset != maxoff + 1)
392  memmove(ptr + sizeof(PostingItem),
393  ptr,
394  (maxoff - offset + 1) * sizeof(PostingItem));
395  }
396  memcpy(ptr, data, sizeof(PostingItem));
397 
398  maxoff++;
399  GinPageGetOpaque(page)->maxoff = maxoff;
400 
401  /*
402  * Also set pd_lower to the end of the posting items, to follow the
403  * "standard" page layout, so that we can squeeze out the unused space
404  * from full-page images.
405  */
406  GinDataPageSetDataSize(page, maxoff * sizeof(PostingItem));
407 }
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
uint16 OffsetNumber
Definition: off.h:24
#define GinDataPageSetDataSize(page, size)
Definition: ginblock.h:300
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:289
#define memmove(d, s, c)
Definition: c.h:1045
#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:670
#define InvalidBlockNumber
Definition: block.h:33

◆ ginendscan()

void ginendscan ( IndexScanDesc  scan)

Definition at line 432 of file ginscan.c.

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

Referenced by ginhandler().

433 {
434  GinScanOpaque so = (GinScanOpaque) scan->opaque;
435 
436  ginFreeScanKeys(so);
437 
440 
441  pfree(so);
442 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
void pfree(void *pointer)
Definition: mcxt.c:949
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:364
MemoryContext keyCtx
Definition: gin_private.h:359
MemoryContext tempCtx
Definition: gin_private.h:349
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:949
#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:70

◆ ginEntryInsert()

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

Definition at line 177 of file gininsert.c.

References addItemPointersToLeafTuple(), GinBtreeStack::buffer, BufferGetPage, buildFreshLeafTuple(), 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().

181 {
182  GinBtreeData btree;
183  GinBtreeEntryInsertData insertdata;
184  GinBtreeStack *stack;
185  IndexTuple itup;
186  Page page;
187 
188  insertdata.isDelete = false;
189 
190  /* During index build, count the to-be-inserted entry */
191  if (buildStats)
192  buildStats->nEntries++;
193 
194  ginPrepareEntryScan(&btree, attnum, key, category, ginstate);
195 
196  stack = ginFindLeafPage(&btree, false, NULL);
197  page = BufferGetPage(stack->buffer);
198 
199  if (btree.findItem(&btree, stack))
200  {
201  /* found pre-existing entry */
202  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off));
203 
204  if (GinIsPostingTree(itup))
205  {
206  /* add entries to existing posting tree */
207  BlockNumber rootPostingTree = GinGetPostingTree(itup);
208 
209  /* release all stack */
210  LockBuffer(stack->buffer, GIN_UNLOCK);
211  freeGinBtreeStack(stack);
212 
213  /* insert into posting tree */
214  ginInsertItemPointers(ginstate->index, rootPostingTree,
215  items, nitem,
216  buildStats);
217  return;
218  }
219 
220  /* modify an existing leaf entry */
221  itup = addItemPointersToLeafTuple(ginstate, itup,
222  items, nitem, buildStats);
223 
224  insertdata.isDelete = true;
225  }
226  else
227  {
228  /* no match, so construct a new leaf entry */
229  itup = buildFreshLeafTuple(ginstate, attnum, key, category,
230  items, nitem, buildStats);
231  }
232 
233  /* Insert the new or modified leaf tuple */
234  insertdata.entry = itup;
235  ginInsertValue(&btree, stack, &insertdata, buildStats);
236  pfree(itup);
237 }
#define GIN_UNLOCK
Definition: gin_private.h:43
void ginInsertItemPointers(Relation index, BlockNumber rootBlkno, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gindatapage.c:1887
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
bool(* findItem)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:149
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, Snapshot snapshot)
Definition: ginbtree.c:76
void pfree(void *pointer)
Definition: mcxt.c:949
IndexTupleData * IndexTuple
Definition: itup.h:53
#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:755
static IndexTuple addItemPointersToLeafTuple(GinState *ginstate, IndexTuple old, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gininsert.c:48
#define GinGetPostingTree(itup)
Definition: ginblock.h:224
#define GinIsPostingTree(itup)
Definition: ginblock.h:222
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:193
#define PageGetItem(page, itemId)
Definition: bufpage.h:336
Pointer Page
Definition: bufpage.h:74
static IndexTuple buildFreshLeafTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gininsert.c:127

◆ ginExtractEntries()

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

Definition at line 486 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_NULL_ITEM, cmpEntriesArg::haveDups, i, keyEntryData::isnull, palloc(), palloc0(), pfree(), PointerGetDatum, qsort_arg(), and GinState::supportCollation.

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

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

◆ ginFindLeafPage()

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

Definition at line 76 of file ginbtree.c.

References Assert, GinBtreeStack::blkno, GinBtreeStack::buffer, BufferGetPage, 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().

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

◆ 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:220
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:229
IndexTuple index_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: indextuple.c:37
void pfree(void *pointer)
Definition: mcxt.c:949
#define ERROR
Definition: elog.h:43
signed char GinNullCategory
Definition: ginblock.h:197
#define GinSetPostingOffset(itup, n)
Definition: ginblock.h:228
#define GIN_CAT_NORM_KEY
Definition: ginblock.h:199
#define RelationGetRelationName(relation)
Definition: rel.h:436
unsigned int uint32
Definition: c.h:296
#define ereport(elevel, rest)
Definition: elog.h:122
uintptr_t Datum
Definition: postgres.h:372
TupleDesc tupdesc[INDEX_MAX_KEYS]
Definition: gin_private.h:68
#define Max(x, y)
Definition: c.h:796
#define Assert(condition)
Definition: c.h:670
#define GinSetNullCategory(itup, ginstate, c)
Definition: ginblock.h:213
size_t Size
Definition: c.h:404
#define MAXALIGN(LEN)
Definition: c.h:623
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:962
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define GinMaxItemSize
Definition: ginblock.h:239
unsigned short t_info
Definition: itup.h:49
#define SHORTALIGN(LEN)
Definition: c.h:619
bool oneCol
Definition: gin_private.h:54
#define GinCategoryOffset(itup, ginstate)
Definition: ginblock.h:208
#define UInt16GetDatum(X)
Definition: postgres.h:471
#define IndexTupleSize(itup)
Definition: itup.h:70

◆ 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:333
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
ItemPointerData * list
Definition: gin_private.h:337
void pfree(void *pointer)
Definition: mcxt.c:949
void tbm_free(TIDBitmap *tbm)
Definition: tidbitmap.c:321
MemoryContext keyCtx
Definition: gin_private.h:359
unsigned int uint32
Definition: c.h:296
TIDBitmap * matchBitmap
Definition: gin_private.h:332
GinScanKey keys
Definition: gin_private.h:352
#define MemoryContextResetAndDeleteChildren(ctx)
Definition: memutils.h:67
GinScanEntry * entries
Definition: gin_private.h:355
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:398
RBNode * rb_iterate(RBTreeIterator *iter)
Definition: rbtree.c:761
GinNullCategory category
Definition: gin_private.h:397
#define Assert(condition)
Definition: c.h:670
static int qsortCompareItemPointers(const void *a, const void *b)
Definition: ginbulk.c:246
RBTreeIterator tree_walk
Definition: gin_private.h:412
#define qsort(a, b, c, d)
Definition: port.h:408
ItemPointerData * list
Definition: gin_private.h:400

◆ gingetbitmap()

int64 gingetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

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

1796 {
1797  GinScanOpaque so = (GinScanOpaque) scan->opaque;
1798  int64 ntids;
1799  ItemPointerData iptr;
1800  bool recheck;
1801 
1802  /*
1803  * Set up the scan keys, and check for unsatisfiable query.
1804  */
1805  ginFreeScanKeys(so); /* there should be no keys yet, but just to be
1806  * sure */
1807  ginNewScanKey(scan);
1808 
1809  if (GinIsVoidRes(scan))
1810  return 0;
1811 
1812  ntids = 0;
1813 
1814  /*
1815  * First, scan the pending list and collect any matching entries into the
1816  * bitmap. After we scan a pending item, some other backend could post it
1817  * into the main index, and so we might visit it a second time during the
1818  * main scan. This is okay because we'll just re-set the same bit in the
1819  * bitmap. (The possibility of duplicate visits is a major reason why GIN
1820  * can't support the amgettuple API, however.) Note that it would not do
1821  * to scan the main index before the pending list, since concurrent
1822  * cleanup could then make us miss entries entirely.
1823  */
1824  scanPendingInsert(scan, tbm, &ntids);
1825 
1826  /*
1827  * Now scan the main index.
1828  */
1829  startScan(scan);
1830 
1831  ItemPointerSetMin(&iptr);
1832 
1833  for (;;)
1834  {
1836 
1837  if (!scanGetItem(scan, iptr, &iptr, &recheck))
1838  break;
1839 
1840  if (ItemPointerIsLossyPage(&iptr))
1842  else
1843  tbm_add_tuples(tbm, &iptr, 1, recheck);
1844  ntids++;
1845  }
1846 
1847  return ntids;
1848 }
static void scanPendingInsert(IndexScanDesc scan, TIDBitmap *tbm, int64 *ntids)
Definition: ginget.c:1706
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:536
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:364
#define ItemPointerSetMin(p)
Definition: ginblock.h:157
static bool scanGetItem(IndexScanDesc scan, ItemPointerData advancePast, ItemPointerData *item, bool *recheck)
Definition: ginget.c:1185
void ginNewScanKey(IndexScanDesc scan)
Definition: ginscan.c:262
#define GinIsVoidRes(s)
Definition: ginget.c:1792
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:76
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 470 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().

474 {
475  Datum *entries;
476  GinNullCategory *categories;
477  int32 i,
478  nentries;
479 
480  /*
481  * Extract the key values that need to be inserted in the index
482  */
483  entries = ginExtractEntries(ginstate, attnum, value, isNull,
484  &nentries, &categories);
485 
486  /*
487  * Allocate/reallocate memory for storing collected tuples
488  */
489  if (collector->tuples == NULL)
490  {
491  collector->lentuples = nentries * ginstate->origTupdesc->natts;
492  collector->tuples = (IndexTuple *) palloc(sizeof(IndexTuple) * collector->lentuples);
493  }
494 
495  while (collector->ntuples + nentries > collector->lentuples)
496  {
497  collector->lentuples *= 2;
498  collector->tuples = (IndexTuple *) repalloc(collector->tuples,
499  sizeof(IndexTuple) * collector->lentuples);
500  }
501 
502  /*
503  * Build an index tuple for each key value, and add to array. In pending
504  * tuples we just stick the heap TID into t_tid.
505  */
506  for (i = 0; i < nentries; i++)
507  {
508  IndexTuple itup;
509 
510  itup = GinFormTuple(ginstate, attnum, entries[i], categories[i],
511  NULL, 0, 0, true);
512  itup->t_tid = *ht_ctid;
513  collector->tuples[collector->ntuples++] = itup;
514  collector->sumsize += IndexTupleSize(itup);
515  }
516 }
ItemPointerData t_tid
Definition: itup.h:37
int natts
Definition: tupdesc.h:79
signed int int32
Definition: c.h:284
signed char GinNullCategory
Definition: ginblock.h:197
static struct @121 value
IndexTuple * tuples
Definition: gin_private.h:429
uintptr_t Datum
Definition: postgres.h:372
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:962
void * palloc(Size size)
Definition: mcxt.c:848
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:486
#define IndexTupleSize(itup)
Definition: itup.h:70

◆ ginHeapTupleFastInsert()

void ginHeapTupleFastInsert ( GinState ginstate,
GinTupleCollector collector 
)

Definition at line 222 of file ginfast.c.

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

223 {
224  Relation index = ginstate->index;
225  Buffer metabuffer;
226  Page metapage;
227  GinMetaPageData *metadata = NULL;
229  Page page = NULL;
230  ginxlogUpdateMeta data;
231  bool separateList = false;
232  bool needCleanup = false;
233  int cleanupSize;
234  bool needWal;
235 
236  if (collector->ntuples == 0)
237  return;
238 
239  needWal = RelationNeedsWAL(index);
240 
241  data.node = index->rd_node;
242  data.ntuples = 0;
244 
245  metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
246  metapage = BufferGetPage(metabuffer);
247 
248  if (collector->sumsize + collector->ntuples * sizeof(ItemIdData) > GinListPageSize)
249  {
250  /*
251  * Total size is greater than one page => make sublist
252  */
253  separateList = true;
254  }
255  else
256  {
257  LockBuffer(metabuffer, GIN_EXCLUSIVE);
258  metadata = GinPageGetMeta(metapage);
259 
260  if (metadata->head == InvalidBlockNumber ||
261  collector->sumsize + collector->ntuples * sizeof(ItemIdData) > metadata->tailFreeSize)
262  {
263  /*
264  * Pending list is empty or total size is greater than freespace
265  * on tail page => make sublist
266  *
267  * We unlock metabuffer to keep high concurrency
268  */
269  separateList = true;
270  LockBuffer(metabuffer, GIN_UNLOCK);
271  }
272  }
273 
274  if (separateList)
275  {
276  /*
277  * We should make sublist separately and append it to the tail
278  */
279  GinMetaPageData sublist;
280 
281  memset(&sublist, 0, sizeof(GinMetaPageData));
282  makeSublist(index, collector->tuples, collector->ntuples, &sublist);
283 
284  if (needWal)
285  XLogBeginInsert();
286 
287  /*
288  * metapage was unlocked, see above
289  */
290  LockBuffer(metabuffer, GIN_EXCLUSIVE);
291  metadata = GinPageGetMeta(metapage);
292 
293  if (metadata->head == InvalidBlockNumber)
294  {
295  /*
296  * Main list is empty, so just insert sublist as main list
297  */
299 
300  metadata->head = sublist.head;
301  metadata->tail = sublist.tail;
302  metadata->tailFreeSize = sublist.tailFreeSize;
303 
304  metadata->nPendingPages = sublist.nPendingPages;
305  metadata->nPendingHeapTuples = sublist.nPendingHeapTuples;
306  }
307  else
308  {
309  /*
310  * Merge lists
311  */
312  data.prevTail = metadata->tail;
313  data.newRightlink = sublist.head;
314 
315  buffer = ReadBuffer(index, metadata->tail);
316  LockBuffer(buffer, GIN_EXCLUSIVE);
317  page = BufferGetPage(buffer);
318 
319  Assert(GinPageGetOpaque(page)->rightlink == InvalidBlockNumber);
320 
322 
323  GinPageGetOpaque(page)->rightlink = sublist.head;
324 
325  MarkBufferDirty(buffer);
326 
327  metadata->tail = sublist.tail;
328  metadata->tailFreeSize = sublist.tailFreeSize;
329 
330  metadata->nPendingPages += sublist.nPendingPages;
331  metadata->nPendingHeapTuples += sublist.nPendingHeapTuples;
332 
333  if (needWal)
335  }
336  }
337  else
338  {
339  /*
340  * Insert into tail page. Metapage is already locked
341  */
342  OffsetNumber l,
343  off;
344  int i,
345  tupsize;
346  char *ptr;
347  char *collectordata;
348 
349  buffer = ReadBuffer(index, metadata->tail);
350  LockBuffer(buffer, GIN_EXCLUSIVE);
351  page = BufferGetPage(buffer);
352 
353  off = (PageIsEmpty(page)) ? FirstOffsetNumber :
355 
356  collectordata = ptr = (char *) palloc(collector->sumsize);
357 
358  data.ntuples = collector->ntuples;
359 
360  if (needWal)
361  XLogBeginInsert();
362 
364 
365  /*
366  * Increase counter of heap tuples
367  */
368  Assert(GinPageGetOpaque(page)->maxoff <= metadata->nPendingHeapTuples);
369  GinPageGetOpaque(page)->maxoff++;
370  metadata->nPendingHeapTuples++;
371 
372  for (i = 0; i < collector->ntuples; i++)
373  {
374  tupsize = IndexTupleSize(collector->tuples[i]);
375  l = PageAddItem(page, (Item) collector->tuples[i], tupsize, off, false, false);
376 
377  if (l == InvalidOffsetNumber)
378  elog(ERROR, "failed to add item to index page in \"%s\"",
379  RelationGetRelationName(index));
380 
381  memcpy(ptr, collector->tuples[i], tupsize);
382  ptr += tupsize;
383 
384  off++;
385  }
386 
387  Assert((ptr - collectordata) <= collector->sumsize);
388  if (needWal)
389  {
391  XLogRegisterBufData(1, collectordata, collector->sumsize);
392  }
393 
394  metadata->tailFreeSize = PageGetExactFreeSpace(page);
395 
396  MarkBufferDirty(buffer);
397  }
398 
399  /*
400  * Set pd_lower just past the end of the metadata. This is essential,
401  * because without doing so, metadata will be lost if xlog.c compresses
402  * the page. (We must do this here because pre-v11 versions of PG did not
403  * set the metapage's pd_lower correctly, so a pg_upgraded index might
404  * contain the wrong value.)
405  */
406  ((PageHeader) metapage)->pd_lower =
407  ((char *) metadata + sizeof(GinMetaPageData)) - (char *) metapage;
408 
409  /*
410  * Write metabuffer, make xlog entry
411  */
412  MarkBufferDirty(metabuffer);
413 
414  if (needWal)
415  {
416  XLogRecPtr recptr;
417 
418  memcpy(&data.metadata, metadata, sizeof(GinMetaPageData));
419 
421  XLogRegisterData((char *) &data, sizeof(ginxlogUpdateMeta));
422 
423  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_UPDATE_META_PAGE);
424  PageSetLSN(metapage, recptr);
425 
426  if (buffer != InvalidBuffer)
427  {
428  PageSetLSN(page, recptr);
429  }
430  }
431 
432  if (buffer != InvalidBuffer)
433  UnlockReleaseBuffer(buffer);
434 
435  /*
436  * Force pending list cleanup when it becomes too long. And,
437  * ginInsertCleanup could take significant amount of time, so we prefer to
438  * call it when it can do all the work in a single collection cycle. In
439  * non-vacuum mode, it shouldn't require maintenance_work_mem, so fire it
440  * while pending list is still small enough to fit into
441  * gin_pending_list_limit.
442  *
443  * ginInsertCleanup() should not be called inside our CRIT_SECTION.
444  */
445  cleanupSize = GinGetPendingListCleanupSize(index);
446  if (metadata->nPendingPages * GIN_PAGE_FREESIZE > cleanupSize * 1024L)
447  needCleanup = true;
448 
449  UnlockReleaseBuffer(metabuffer);
450 
452 
453  /*
454  * Since it could contend with concurrent cleanup process we cleanup
455  * pending list not forcibly.
456  */
457  if (needCleanup)
458  ginInsertCleanup(ginstate, false, true, false, NULL);
459 }
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:318
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
static void makeSublist(Relation index, IndexTuple *tuples, int32 ntuples, GinMetaPageData *res)
Definition: ginfast.c:148
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:436
#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:429
#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:754
GinMetaPageData metadata
Definition: ginxlog.h:172
RelFileNode rd_node
Definition: rel.h:85
PageHeaderData * PageHeader
Definition: bufpage.h:162
uint32 tailFreeSize
Definition: ginblock.h:66
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:670
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
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:505
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:629
void * palloc(Size size)
Definition: mcxt.c:848
int i
#define GIN_PAGE_FREESIZE
Definition: ginfast.c:39
#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:70
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:409
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 353 of file ginutil.c.

References BufferGetPage, BufferGetPageSize, and GinInitPage().

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

354 {
356 }
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:340
#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:288
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:287
#define OidIsValid(objectId)
Definition: c.h:576
OffsetNumber attnum
Definition: gin_private.h:299
static GinTernaryValue trueTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:62
bool(* boolConsistentFn)(GinScanKey key)
Definition: gin_private.h:285
Oid fn_oid
Definition: fmgr.h:59
GinTernaryValue(* triConsistentFn)(GinScanKey key)
Definition: gin_private.h:286
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 359 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().

360 {
361  GinMetaPageData *metadata;
362  Page page = BufferGetPage(b);
363 
365 
366  metadata = GinPageGetMeta(page);
367 
368  metadata->head = metadata->tail = InvalidBlockNumber;
369  metadata->tailFreeSize = 0;
370  metadata->nPendingPages = 0;
371  metadata->nPendingHeapTuples = 0;
372  metadata->nTotalPages = 0;
373  metadata->nEntryPages = 0;
374  metadata->nDataPages = 0;
375  metadata->nEntries = 0;
376  metadata->ginVersion = GIN_CURRENT_VERSION;
377 
378  /*
379  * Set pd_lower just past the end of the metadata. This is essential,
380  * because without doing so, metadata will be lost if xlog.c compresses
381  * the page.
382  */
383  ((PageHeader) page)->pd_lower =
384  ((char *) metadata + sizeof(GinMetaPageData)) - (char *) page;
385 }
BlockNumber nEntryPages
Definition: ginblock.h:79
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:340
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 340 of file ginutil.c.

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

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

341 {
342  GinPageOpaque opaque;
343 
344  PageInit(page, pageSize, sizeof(GinPageOpaqueData));
345 
346  opaque = GinPageGetOpaque(page);
347  memset(opaque, 0, sizeof(GinPageOpaqueData));
348  opaque->flags = f;
349  opaque->rightlink = InvalidBlockNumber;
350 }
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 484 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().

488 {
489  GinState *ginstate = (GinState *) indexInfo->ii_AmCache;
490  MemoryContext oldCtx;
491  MemoryContext insertCtx;
492  int i;
493 
494  /* Initialize GinState cache if first call in this statement */
495  if (ginstate == NULL)
496  {
497  oldCtx = MemoryContextSwitchTo(indexInfo->ii_Context);
498  ginstate = (GinState *) palloc(sizeof(GinState));
499  initGinState(ginstate, index);
500  indexInfo->ii_AmCache = (void *) ginstate;
501  MemoryContextSwitchTo(oldCtx);
502  }
503 
505  "Gin insert temporary context",
507 
508  oldCtx = MemoryContextSwitchTo(insertCtx);
509 
510  if (GinGetUseFastUpdate(index))
511  {
512  GinTupleCollector collector;
513 
514  memset(&collector, 0, sizeof(GinTupleCollector));
515 
516  for (i = 0; i < ginstate->origTupdesc->natts; i++)
517  ginHeapTupleFastCollect(ginstate, &collector,
518  (OffsetNumber) (i + 1),
519  values[i], isnull[i],
520  ht_ctid);
521 
522  ginHeapTupleFastInsert(ginstate, &collector);
523  }
524  else
525  {
526  for (i = 0; i < ginstate->origTupdesc->natts; i++)
527  ginHeapTupleInsert(ginstate, (OffsetNumber) (i + 1),
528  values[i], isnull[i],
529  ht_ctid);
530  }
531 
532  MemoryContextSwitchTo(oldCtx);
533  MemoryContextDelete(insertCtx);
534 
535  return false;
536 }
MemoryContext ii_Context
Definition: execnodes.h:151
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
void ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
Definition: ginfast.c:222
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:466
int natts
Definition: tupdesc.h:79
uint16 OffsetNumber
Definition: off.h:24
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:86
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
void * ii_AmCache
Definition: execnodes.h:150
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
#define GinGetUseFastUpdate(relation)
Definition: gin_private.h:32
static Datum values[MAXATTR]
Definition: bootstrap.c:164
void * palloc(Size size)
Definition: mcxt.c:848
int i
void ginHeapTupleFastCollect(GinState *ginstate, GinTupleCollector *collector, OffsetNumber attnum, Datum value, bool isNull, ItemPointer ht_ctid)
Definition: ginfast.c:470
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 
220  Assert(ItemPointerIsValid(heapptr) && attnum >= FirstOffsetNumber);
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:60
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:296
#define Assert(condition)
Definition: c.h:670
int i

◆ ginInsertCleanup()

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

Definition at line 754 of file ginfast.c.

References BuildAccumulator::allocatedMemory, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), Assert, 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().

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

1890 {
1891  GinBtreeData btree;
1892  GinBtreeDataLeafInsertData insertdata;
1893  GinBtreeStack *stack;
1894 
1895  ginPrepareDataScan(&btree, index, rootBlkno);
1896  btree.isBuild = (buildStats != NULL);
1897  insertdata.items = items;
1898  insertdata.nitem = nitem;
1899  insertdata.curitem = 0;
1900 
1901  while (insertdata.curitem < insertdata.nitem)
1902  {
1903  /* search for the leaf page where the first item should go to */
1904  btree.itemptr = insertdata.items[insertdata.curitem];
1905  stack = ginFindLeafPage(&btree, false, NULL);
1906 
1907  ginInsertValue(&btree, stack, &insertdata, buildStats);
1908  }
1909 }
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, Snapshot snapshot)
Definition: ginbtree.c:76
ItemPointerData * items
Definition: gin_private.h:188
void ginInsertValue(GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
Definition: ginbtree.c:755
ItemPointerData itemptr
Definition: gin_private.h:172
void ginPrepareDataScan(GinBtree btree, Relation index, BlockNumber rootBlkno)
Definition: gindatapage.c:1861

◆ ginInsertValue()

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

Definition at line 755 of file ginbtree.c.

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

Referenced by ginEntryInsert(), and ginInsertItemPointers().

757 {
758  bool done;
759 
760  /* If the leaf page was incompletely split, finish the split first */
762  ginFinishSplit(btree, stack, false, buildStats);
763 
764  done = ginPlaceToPage(btree, stack,
765  insertdata, InvalidBlockNumber,
766  InvalidBuffer, buildStats);
767  if (done)
768  {
769  LockBuffer(stack->buffer, GIN_UNLOCK);
770  freeGinBtreeStack(stack);
771  }
772  else
773  ginFinishSplit(btree, stack, true, buildStats);
774 }
#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:646
#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:193
static bool ginPlaceToPage(GinBtree btree, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, Buffer childbuf, GinStatsData *buildStats)
Definition: ginbtree.c:329

◆ 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:461
void * palloc(Size size)
Definition: mcxt.c:848
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 289 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().

290 {
291  Buffer buffer;
292  bool needLock;
293 
294  /* First, try to get a page from FSM */
295  for (;;)
296  {
297  BlockNumber blkno = GetFreeIndexPage(index);
298 
299  if (blkno == InvalidBlockNumber)
300  break;
301 
302  buffer = ReadBuffer(index, blkno);
303 
304  /*
305  * We have to guard against the possibility that someone else already
306  * recycled this page; the buffer may be locked if so.
307  */
308  if (ConditionalLockBuffer(buffer))
309  {
310  Page page = BufferGetPage(buffer);
311 
312  if (PageIsNew(page))
313  return buffer; /* OK to use, if never initialized */
314 
315  if (GinPageIsDeleted(page))
316  return buffer; /* OK to use */
317 
318  LockBuffer(buffer, GIN_UNLOCK);
319  }
320 
321  /* Can't use it, so release buffer and try again */
322  ReleaseBuffer(buffer);
323  }
324 
325  /* Must extend the file */
326  needLock = !RELATION_IS_LOCAL(index);
327  if (needLock)
329 
330  buffer = ReadBuffer(index, P_NEW);
331  LockBuffer(buffer, GIN_EXCLUSIVE);
332 
333  if (needLock)
335 
336  return buffer;
337 }
#define GIN_UNLOCK
Definition: gin_private.h:43
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:523
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:214
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_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  int32 searchMode = GIN_SEARCH_MODE_DEFAULT;
299 
300  /*
301  * We assume that GIN-indexable operators are strict, so a null query
302  * argument means an unsatisfiable query.
303  */
304  if (skey->sk_flags & SK_ISNULL)
305  {
306  so->isVoidRes = true;
307  break;
308  }
309 
310  /* OK to call the extractQueryFn */
311  queryValues = (Datum *)
313  so->ginstate.supportCollation[skey->sk_attno - 1],
314  skey->sk_argument,
315  PointerGetDatum(&nQueryValues),
317  PointerGetDatum(&partial_matches),
318  PointerGetDatum(&extra_data),
319  PointerGetDatum(&nullFlags),
320  PointerGetDatum(&searchMode)));
321 
322  /*
323  * If bogus searchMode is returned, treat as GIN_SEARCH_MODE_ALL; note
324  * in particular we don't allow extractQueryFn to select
325  * GIN_SEARCH_MODE_EVERYTHING.
326  */
327  if (searchMode < GIN_SEARCH_MODE_DEFAULT ||
328  searchMode > GIN_SEARCH_MODE_ALL)
329  searchMode = GIN_SEARCH_MODE_ALL;
330 
331  /* Non-default modes require the index to have placeholders */
332  if (searchMode != GIN_SEARCH_MODE_DEFAULT)
333  hasNullQuery = true;
334 
335  /*
336  * In default mode, no keys means an unsatisfiable query.
337  */
338  if (queryValues == NULL || nQueryValues <= 0)
339  {
340  if (searchMode == GIN_SEARCH_MODE_DEFAULT)
341  {
342  so->isVoidRes = true;
343  break;
344  }
345  nQueryValues = 0; /* ensure sane value */
346  }
347 
348  /*
349  * If the extractQueryFn didn't create a nullFlags array, create one,
350  * assuming that everything's non-null. Otherwise, run through the
351  * array and make sure each value is exactly 0 or 1; this ensures
352  * binary compatibility with the GinNullCategory representation. While
353  * at it, detect whether any null keys are present.
354  */
355  if (nullFlags == NULL)
356  nullFlags = (bool *) palloc0(nQueryValues * sizeof(bool));
357  else
358  {
359  int32 j;
360 
361  for (j = 0; j < nQueryValues; j++)
362  {
363  if (nullFlags[j])
364  {
365  nullFlags[j] = true; /* not any other nonzero value */
366  hasNullQuery = true;
367  }
368  }
369  }
370  /* now we can use the nullFlags as category codes */
371 
372  ginFillScanKey(so, skey->sk_attno,
373  skey->sk_strategy, searchMode,
374  skey->sk_argument, nQueryValues,
375  queryValues, (GinNullCategory *) nullFlags,
376  partial_matches, extra_data);
377  }
378 
379  /*
380  * If there are no regular scan keys, generate an EVERYTHING scankey to
381  * drive a full-index scan.
382  */
383  if (so->nkeys == 0 && !so->isVoidRes)
384  {
385  hasNullQuery = true;
388  (Datum) 0, 0,
389  NULL, NULL, NULL, NULL);
390  }
391 
392  /*
393  * If the index is version 0, it may be missing null and placeholder
394  * entries, which would render searches for nulls and full-index scans
395  * unreliable. Throw an error if so.
396  */
397  if (hasNullQuery && !so->isVoidRes)
398  {
399  GinStatsData ginStats;
400 
401  ginGetStats(scan->indexRelation, &ginStats);
402  if (ginStats.ginVersion < 1)
403  ereport(ERROR,
404  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
405  errmsg("old GIN indexes do not support whole-index scans nor searches for nulls"),
406  errhint("To fix this, do REINDEX INDEX \"%s\".",
408  }
409 
410  MemoryContextSwitchTo(oldCtx);
411 
413 }
#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:562
#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:284
Relation indexRelation
Definition: relscan.h:90
#define GIN_SEARCH_MODE_ALL
Definition: gin.h:35
char * Pointer
Definition: c.h:273
#define ERROR
Definition: elog.h:43
signed char GinNullCategory
Definition: ginblock.h:197
Datum FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7)
Definition: fmgr.c:1177
struct GinScanKeyData * GinScanKey
Definition: gin_private.h:256
StrategyNumber sk_strategy
Definition: skey.h:68
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:364
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:359
#define RelationGetRelationName(relation)
Definition: rel.h:436
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:1275
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:352
void * palloc0(Size size)
Definition: mcxt.c:877
struct GinScanKeyData GinScanKeyData
uintptr_t Datum
Definition: postgres.h:372
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:796
int sk_flags
Definition: skey.h:66
ScanKey keyData
Definition: relscan.h:94
int32 ginVersion
Definition: gin.h:48
#define DatumGetPointer(X)
Definition: postgres.h:555
GinScanEntry * entries
Definition: gin_private.h:355
void * palloc(Size size)
Definition: mcxt.c:848
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
Datum sk_argument
Definition: skey.h:72
#define UInt16GetDatum(X)
Definition: postgres.h:471
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:600
void pfree(void *pointer)
Definition: mcxt.c:949
void * allocateReloptStruct(Size base, relopt_value *options, int numoptions)
Definition: reloptions.c:1215
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:1239
Definition: c.h:487
relopt_value * parseRelOptions(Datum options, bool validate, relopt_kind kind, int *numrelopts)
Definition: reloptions.c:1020
#define offsetof(type, field)
Definition: c.h:593

◆ GinPageDeletePostingItem()

void GinPageDeletePostingItem ( Page  page,
OffsetNumber  offset 
)

Definition at line 413 of file gindatapage.c.

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

Referenced by ginDeletePage(), and ginRedoDeletePage().

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

◆ 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:333
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:334
static void uint64_to_itemptr(uint64 val, ItemPointer iptr)
uint16 nbytes
Definition: ginblock.h:329
#define Assert(condition)
Definition: c.h:670
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:95
static uint64 itemptr_to_uint64(const ItemPointer iptr)
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:962
static int ginCompareItemPointers(ItemPointer a, ItemPointer b)
Definition: gin_private.h:461
void * palloc(Size size)
Definition: mcxt.c:848
#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:949
ItemPointer ginPostingListDecodeAllSegments(GinPostingList *segment, int len, int *ndecoded_out)

◆ ginPrepareDataScan()

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

Definition at line 1861 of file gindatapage.c.

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

Referenced by ginInsertItemPointers(), and ginScanBeginPostingTree().

1862 {
1863  memset(btree, 0, sizeof(GinBtreeData));
1864 
1865  btree->index = index;
1866  btree->rootBlkno = rootBlkno;
1867 
1868  btree->findChildPage = dataLocateItem;
1870  btree->isMoveRight = dataIsMoveRight;
1871  btree->findItem = NULL;
1872  btree->findChildPtr = dataFindChildPtr;
1875  btree->fillRoot = ginDataFillRoot;
1877 
1878  btree->isData = true;
1879  btree->fullScan = false;
1880  btree->isBuild = false;
1881 }
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
Definition: gin_private.h:156
bool(* isMoveRight)(GinBtree, Page)
Definition: gin_private.h:148
static BlockNumber dataLocateItem(GinBtree btree, GinBtreeStack *stack)
Definition: gindatapage.c:248
BlockNumber rootBlkno
Definition: gin_private.h:161
bool(* findItem)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:149
static GinPlaceToPageRC dataBeginPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, void **ptp_workspace, Page *newlpage, Page *newrpage)
Definition: gindatapage.c:1191
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
Definition: gin_private.h:153
static bool dataIsMoveRight(GinBtree btree, Page page)
Definition: gindatapage.c:233
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
Definition: gin_private.h:154
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:146
static OffsetNumber dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
Definition: gindatapage.c:315
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:147
Relation index
Definition: gin_private.h:160
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:155
void ginDataFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
Definition: gindatapage.c:1339
static void * dataPrepareDownlink(GinBtree btree, Buffer lbuf)
Definition: gindatapage.c:1323
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:152
static void dataExecPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, void *ptp_workspace)
Definition: gindatapage.c:1221
static BlockNumber dataGetLeftMostPage(GinBtree btree, Page page)
Definition: gindatapage.c:360

◆ ginPrepareEntryScan()

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

Definition at line 745 of file ginentrypage.c.

References 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
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:219
#define GinGetPosting(itup)
Definition: ginblock.h:229
#define GinItupIsCompressed(itup)
Definition: ginblock.h:230
ItemPointerData * ItemPointer
Definition: itemptr.h:49
char * Pointer
Definition: c.h:273
#define ERROR
Definition: elog.h:43
void * palloc(Size size)
Definition: mcxt.c:848
#define elog
Definition: elog.h:219

◆ ginrescan()

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

Definition at line 416 of file ginscan.c.

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

Referenced by ginhandler().

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

◆ ginScanBeginPostingTree()

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

Definition at line 1915 of file gindatapage.c.

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

Referenced by scanPostingTree(), and startScanEntry().

1917 {
1918  GinBtreeStack *stack;
1919 
1920  ginPrepareDataScan(btree, index, rootBlkno);
1921 
1922  btree->fullScan = true;
1923 
1924  stack = ginFindLeafPage(btree, true, snapshot);
1925 
1926  return stack;
1927 }
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, Snapshot snapshot)
Definition: ginbtree.c:76
void ginPrepareDataScan(GinBtree btree, Relation index, BlockNumber rootBlkno)
Definition: gindatapage.c:1861

◆ ginStepRight()

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

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

166 {
167  Buffer nextbuffer;
168  Page page = BufferGetPage(buffer);
169  bool isLeaf = GinPageIsLeaf(page);
170  bool isData = GinPageIsData(page);
171  BlockNumber blkno = GinPageGetOpaque(page)->rightlink;
172 
173  nextbuffer = ReadBuffer(index, blkno);
174  LockBuffer(nextbuffer, lockmode);
176 
177  /* Sanity check that the page we stepped to is of similar kind. */
178  page = BufferGetPage(nextbuffer);
179  if (isLeaf != GinPageIsLeaf(page) || isData != GinPageIsData(page))
180  elog(ERROR, "right sibling of GIN page is of different type");
181 
182  /*
183  * Given the proper lock sequence above, we should never land on a deleted
184  * page.
185  */
186  if (GinPageIsDeleted(page))
187  elog(ERROR, "right sibling of GIN page was deleted");
188 
189  return nextbuffer;
190 }
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:214
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 35 of file ginbtree.c.

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

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

36 {
37  Page page;
38  int access = GIN_SHARE;
39 
41  page = BufferGetPage(buffer);
42  if (GinPageIsLeaf(page))
43  {
44  if (searchMode == false)
45  {
46  /* we should relock our page */
49 
50  /* But root can become non-leaf during relock */
51  if (!GinPageIsLeaf(page))
52  {
53  /* restore old lock type (very rare) */
56  }
57  else
58  access = GIN_EXCLUSIVE;
59  }
60  }
61 
62  return access;
63 }
#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:214
Pointer Page
Definition: bufpage.h:74

◆ gintuple_get_attrnum()

OffsetNumber gintuple_get_attrnum ( GinState ginstate,
IndexTuple  tuple 
)

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

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

250 {
251  Datum res;
252  bool isnull;
253 
254  if (ginstate->oneCol)
255  {
256  /*
257  * Single column index doesn't store attribute numbers in tuples
258  */
259  res = index_getattr(tuple, FirstOffsetNumber, ginstate->origTupdesc,
260  &isnull);
261  }
262  else
263  {
264  /*
265  * Since the datum type depends on which index column it's from, we
266  * must be careful to use the right tuple descriptor here.
267  */
268  OffsetNumber colN = gintuple_get_attrnum(ginstate, tuple);
269 
271  ginstate->tupdesc[colN - 1],
272  &isnull);
273  }
274 
275  if (isnull)
276  *category = GinGetNullCategory(tuple, ginstate);
277  else
278  *category = GIN_CAT_NORM_KEY;
279 
280  return res;
281 }
#define GinGetNullCategory(itup, ginstate)
Definition: ginblock.h:211
uint16 OffsetNumber
Definition: off.h:24
OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple)
Definition: ginutil.c:215
#define GIN_CAT_NORM_KEY
Definition: ginblock.h:199
#define FirstOffsetNumber
Definition: off.h:27
uintptr_t Datum
Definition: postgres.h:372
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 667 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().

668 {
669  Relation index = info->index;
670  bool needLock;
671  BlockNumber npages,
672  blkno;
673  BlockNumber totFreePages;
674  GinState ginstate;
675  GinStatsData idxStat;
676 
677  /*
678  * In an autovacuum analyze, we want to clean up pending insertions.
679  * Otherwise, an ANALYZE-only call is a no-op.
680  */
681  if (info->analyze_only)
682  {
684  {
685  initGinState(&ginstate, index);
686  ginInsertCleanup(&ginstate, false, true, true, stats);
687  }
688  return stats;
689  }
690 
691  /*
692  * Set up all-zero stats and cleanup pending inserts if ginbulkdelete
693  * wasn't called
694  */
695  if (stats == NULL)
696  {
698  initGinState(&ginstate, index);
700  false, true, stats);
701  }
702 
703  memset(&idxStat, 0, sizeof(idxStat));
704 
705  /*
706  * XXX we always report the heap tuple count as the number of index
707  * entries. This is bogus if the index is partial, but it's real hard to
708  * tell how many distinct heap entries are referenced by a GIN index.
709  */
710  stats->num_index_tuples = info->num_heap_tuples;
711  stats->estimated_count = info->estimated_count;
712 
713  /*
714  * Need lock unless it's local to this backend.
715  */
716  needLock = !RELATION_IS_LOCAL(index);
717 
718  if (needLock)
720  npages = RelationGetNumberOfBlocks(index);
721  if (needLock)
723 
724  totFreePages = 0;
725 
726  for (blkno = GIN_ROOT_BLKNO; blkno < npages; blkno++)
727  {
728  Buffer buffer;
729  Page page;
730 
732 
733  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
734  RBM_NORMAL, info->strategy);
735  LockBuffer(buffer, GIN_SHARE);
736  page = (Page) BufferGetPage(buffer);
737 
738  if (PageIsNew(page) || GinPageIsDeleted(page))
739  {
740  Assert(blkno != GIN_ROOT_BLKNO);
741  RecordFreeIndexPage(index, blkno);
742  totFreePages++;
743  }
744  else if (GinPageIsData(page))
745  {
746  idxStat.nDataPages++;
747  }
748  else if (!GinPageIsList(page))
749  {
750  idxStat.nEntryPages++;
751 
752  if (GinPageIsLeaf(page))
753  idxStat.nEntries += PageGetMaxOffsetNumber(page);
754  }
755 
756  UnlockReleaseBuffer(buffer);
757  }
758 
759  /* Update the metapage with accurate page and entry counts */
760  idxStat.nTotalPages = npages;
761  ginUpdateStats(info->index, &idxStat);
762 
763  /* Finally, vacuum the FSM */
765 
766  stats->pages_free = totFreePages;
767 
768  if (needLock)
770  stats->num_pages = RelationGetNumberOfBlocks(index);
771  if (needLock)
773 
774  return stats;
775 }
BlockNumber nEntryPages
Definition: gin.h:45
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:523
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:86
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3256
#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:877
#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:754
#define GinPageIsData(page)
Definition: ginblock.h:114
double num_heap_tuples
Definition: genam.h:50
#define Assert(condition)
Definition: c.h:670
void IndexFreeSpaceMapVacuum(Relation rel)
Definition: indexfsm.c:71
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
#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:1658
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 47 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().

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

◆ ginVacuumPostingTreeLeaf()