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 "catalog/pg_am_d.h"
#include "fmgr.h"
#include "lib/rbtree.h"
#include "storage/bufmgr.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, bool rootConflictCheck, Snapshot snapshot)
 
Buffer ginStepRight (Buffer buffer, Relation index, int lockmode)
 
void freeGinBtreeStack (GinBtreeStack *stack)
 
void ginInsertValue (GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
 
IndexTuple GinFormTuple (GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, Pointer data, Size dataSize, int nipd, bool errorTooBig)
 
void ginPrepareEntryScan (GinBtree btree, OffsetNumber attnum, Datum key, GinNullCategory category, GinState *ginstate)
 
void ginEntryFillRoot (GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
 
ItemPointer ginReadTuple (GinState *ginstate, OffsetNumber attnum, IndexTuple itup, int *nitems)
 
ItemPointer GinDataLeafPageGetItems (Page page, int *nitems, ItemPointerData advancePast)
 
int GinDataLeafPageGetItemsToTbm (Page page, TIDBitmap *tbm)
 
BlockNumber createPostingTree (Relation index, ItemPointerData *items, uint32 nitems, GinStatsData *buildStats, Buffer entrybuffer)
 
void GinDataPageAddPostingItem (Page page, PostingItem *data, OffsetNumber offset)
 
void GinPageDeletePostingItem (Page page, OffsetNumber offset)
 
void ginInsertItemPointers (Relation index, BlockNumber rootBlkno, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
 
GinBtreeStackginScanBeginPostingTree (GinBtree btree, Relation index, BlockNumber rootBlkno, Snapshot snapshot)
 
void ginDataFillRoot (GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
 
void ginVacuumPostingTreeLeaf (Relation rel, Buffer buf, GinVacuumState *gvs)
 
IndexScanDesc ginbeginscan (Relation rel, int nkeys, int norderbys)
 
void ginendscan (IndexScanDesc scan)
 
void ginrescan (IndexScanDesc scan, ScanKey key, int nscankeys, ScanKey orderbys, int norderbys)
 
void ginNewScanKey (IndexScanDesc scan)
 
void ginFreeScanKeys (GinScanOpaque so)
 
int64 gingetbitmap (IndexScanDesc scan, TIDBitmap *tbm)
 
void ginInitConsistentFunction (GinState *ginstate, GinScanKey key)
 
IndexBulkDeleteResultginbulkdelete (IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
 
IndexBulkDeleteResultginvacuumcleanup (IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
 
ItemPointer ginVacuumItemPointers (GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining)
 
bool ginvalidate (Oid opclassoid)
 
void ginInitBA (BuildAccumulator *accum)
 
void ginInsertBAEntries (BuildAccumulator *accum, ItemPointer heapptr, OffsetNumber attnum, Datum *entries, GinNullCategory *categories, int32 nentries)
 
void ginBeginBAScan (BuildAccumulator *accum)
 
ItemPointerDataginGetBAEntry (BuildAccumulator *accum, OffsetNumber *attnum, Datum *key, GinNullCategory *category, uint32 *n)
 
void ginHeapTupleFastInsert (GinState *ginstate, GinTupleCollector *collector)
 
void ginHeapTupleFastCollect (GinState *ginstate, GinTupleCollector *collector, OffsetNumber attnum, Datum value, bool isNull, ItemPointer ht_ctid)
 
void ginInsertCleanup (GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
 
GinPostingListginCompressPostingList (const ItemPointer ipd, int nipd, 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 32 of file gin_private.h.

◆ GIN_EXCLUSIVE

◆ GIN_SHARE

◆ GIN_UNLOCK

◆ GinGetPendingListCleanupSize

#define GinGetPendingListCleanupSize (   relation)
Value:
(AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \
relation->rd_rel->relam == GIN_AM_OID), \
(relation)->rd_options && \
((GinOptions *) (relation)->rd_options)->pendingListCleanupSize != -1 ? \
((GinOptions *) (relation)->rd_options)->pendingListCleanupSize : \
#define AssertMacro(condition)
Definition: c.h:739
int gin_pending_list_limit
Definition: ginfast.c:38

Definition at line 38 of file gin_private.h.

Referenced by ginHeapTupleFastInsert().

◆ GinGetUseFastUpdate

#define GinGetUseFastUpdate (   relation)
Value:
(AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \
relation->rd_rel->relam == GIN_AM_OID), \
(relation)->rd_options ? \
((GinOptions *) (relation)->rd_options)->useFastUpdate : GIN_DEFAULT_USE_FASTUPDATE)
#define AssertMacro(condition)
Definition: c.h:739
#define GIN_DEFAULT_USE_FASTUPDATE
Definition: gin_private.h:32

Definition at line 33 of file gin_private.h.

Referenced by gininsert().

Typedef Documentation

◆ GinBtree

typedef struct GinBtreeData* GinBtree

Definition at line 138 of file gin_private.h.

◆ GinBtreeData

typedef struct GinBtreeData GinBtreeData

◆ GinBtreeStack

typedef struct GinBtreeStack GinBtreeStack

◆ GinEntryAccumulator

◆ GinOptions

typedef struct GinOptions GinOptions

◆ GinScanEntry

typedef struct GinScanEntryData* GinScanEntry

Definition at line 263 of file gin_private.h.

◆ GinScanEntryData

◆ GinScanKey

typedef struct GinScanKeyData* GinScanKey

Definition at line 261 of file gin_private.h.

◆ GinScanKeyData

◆ GinScanOpaque

Definition at line 383 of file gin_private.h.

◆ GinScanOpaqueData

◆ GinState

typedef struct GinState GinState

◆ GinTupleCollector

◆ GinVacuumState

Definition at line 240 of file gin_private.h.

Enumeration Type Documentation

◆ GinPlaceToPageRC

Enumerator
GPTP_NO_WORK 
GPTP_INSERT 
GPTP_SPLIT 

Definition at line 141 of file gin_private.h.

Function Documentation

◆ createPostingTree()

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

Definition at line 1769 of file gindatapage.c.

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

Referenced by addItemPointersToLeafTuple(), and buildFreshLeafTuple().

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

◆ freeGinBtreeStack()

void freeGinBtreeStack ( GinBtreeStack stack)

Definition at line 194 of file ginbtree.c.

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

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

195 {
196  while (stack)
197  {
198  GinBtreeStack *tmp = stack->parent;
199 
200  if (stack->buffer != InvalidBuffer)
201  ReleaseBuffer(stack->buffer);
202 
203  pfree(stack);
204  stack = tmp;
205  }
206 }
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3323
void pfree(void *pointer)
Definition: mcxt.c:1056
struct GinBtreeStack * parent
Definition: gin_private.h:135

◆ ginBeginBAScan()

void ginBeginBAScan ( BuildAccumulator accum)

Definition at line 257 of file ginbulk.c.

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

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

258 {
259  rbt_begin_iterate(accum->tree, LeftRightWalk, &accum->tree_walk);
260 }
void rbt_begin_iterate(RBTree *rbt, RBTOrderControl ctrl, RBTreeIterator *iter)
Definition: rbtree.c:740
RBTreeIterator tree_walk
Definition: gin_private.h:431

◆ 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 }
#define AllocSetContextCreate
Definition: memutils.h:170
Relation indexRelation
Definition: relscan.h:103
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:383
MemoryContext keyCtx
Definition: gin_private.h:378
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:94
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
GinScanKey keys
Definition: gin_private.h:371
MemoryContext tempCtx
Definition: gin_private.h:368
#define Assert(condition)
Definition: c.h:738
void * palloc(Size size)
Definition: mcxt.c:949
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:80

◆ ginbuild()

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

Definition at line 320 of file gininsert.c.

References GinBuildState::accum, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, attnum, 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, GinBuildState::indtuples, initGinState(), sort-test::key, sort-test::list, log_newpage_range(), MAIN_FORKNUM, MarkBufferDirty(), MemoryContextDelete(), MemoryContextSwitchTo(), GinStatsData::nEntryPages, palloc(), RelationGetNumberOfBlocks, RelationGetRelationName, RelationNeedsWAL, START_CRIT_SECTION, table_index_build_scan(), GinBuildState::tmpCtx, and UnlockReleaseBuffer().

Referenced by ginhandler().

321 {
322  IndexBuildResult *result;
323  double reltuples;
324  GinBuildState buildstate;
325  Buffer RootBuffer,
326  MetaBuffer;
328  Datum key;
329  GinNullCategory category;
330  uint32 nlist;
331  MemoryContext oldCtx;
333 
334  if (RelationGetNumberOfBlocks(index) != 0)
335  elog(ERROR, "index \"%s\" already contains data",
336  RelationGetRelationName(index));
337 
338  initGinState(&buildstate.ginstate, index);
339  buildstate.indtuples = 0;
340  memset(&buildstate.buildStats, 0, sizeof(GinStatsData));
341 
342  /* initialize the meta page */
343  MetaBuffer = GinNewBuffer(index);
344 
345  /* initialize the root page */
346  RootBuffer = GinNewBuffer(index);
347 
349  GinInitMetabuffer(MetaBuffer);
350  MarkBufferDirty(MetaBuffer);
351  GinInitBuffer(RootBuffer, GIN_LEAF);
352  MarkBufferDirty(RootBuffer);
353 
354 
355  UnlockReleaseBuffer(MetaBuffer);
356  UnlockReleaseBuffer(RootBuffer);
358 
359  /* count the root as first entry page */
360  buildstate.buildStats.nEntryPages++;
361 
362  /*
363  * create a temporary memory context that is used to hold data not yet
364  * dumped out to the index
365  */
367  "Gin build temporary context",
369 
370  /*
371  * create a temporary memory context that is used for calling
372  * ginExtractEntries(), and can be reset after each tuple
373  */
375  "Gin build temporary context for user-defined function",
377 
378  buildstate.accum.ginstate = &buildstate.ginstate;
379  ginInitBA(&buildstate.accum);
380 
381  /*
382  * Do the heap scan. We disallow sync scan here because dataPlaceToPage
383  * prefers to receive tuples in TID order.
384  */
385  reltuples = table_index_build_scan(heap, index, indexInfo, false, true,
386  ginBuildCallback, (void *) &buildstate,
387  NULL);
388 
389  /* dump remaining entries to the index */
390  oldCtx = MemoryContextSwitchTo(buildstate.tmpCtx);
391  ginBeginBAScan(&buildstate.accum);
392  while ((list = ginGetBAEntry(&buildstate.accum,
393  &attnum, &key, &category, &nlist)) != NULL)
394  {
395  /* there could be many entries, so be willing to abort here */
397  ginEntryInsert(&buildstate.ginstate, attnum, key, category,
398  list, nlist, &buildstate.buildStats);
399  }
400  MemoryContextSwitchTo(oldCtx);
401 
402  MemoryContextDelete(buildstate.funcCtx);
403  MemoryContextDelete(buildstate.tmpCtx);
404 
405  /*
406  * Update metapage stats
407  */
409  ginUpdateStats(index, &buildstate.buildStats, true);
410 
411  /*
412  * We didn't write WAL records as we built the index, so if WAL-logging is
413  * required, write all pages to the WAL now.
414  */
415  if (RelationNeedsWAL(index))
416  {
418  0, RelationGetNumberOfBlocks(index),
419  true);
420  }
421 
422  /*
423  * Return statistics
424  */
425  result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
426 
427  result->heap_tuples = reltuples;
428  result->index_tuples = buildstate.indtuples;
429 
430  return result;
431 }
BlockNumber nEntryPages
Definition: gin.h:46
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:297
void GinInitMetabuffer(Buffer b)
Definition: ginutil.c:362
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
#define AllocSetContextCreate
Definition: memutils.h:170
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1406
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
GinStatsData buildStats
Definition: gininsert.c:34
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
static void ginBuildCallback(Relation index, ItemPointer tid, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition: gininsert.c:280
double indtuples
Definition: gininsert.c:33
uint16 OffsetNumber
Definition: off.h:24
GinState ginstate
Definition: gininsert.c:32
void ginEntryInsert(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gininsert.c:179
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3346
#define ERROR
Definition: elog.h:43
signed char GinNullCategory
Definition: ginblock.h:207
static double table_index_build_scan(Relation table_rel, Relation index_rel, struct IndexInfo *index_info, bool allow_sync, bool progress, IndexBuildCallback callback, void *callback_state, TableScanDesc scan)
Definition: tableam.h:1531
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
BuildAccumulator accum
Definition: gininsert.c:37
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:94
#define RelationGetRelationName(relation)
Definition: rel.h:470
unsigned int uint32
Definition: c.h:367
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
GinState * ginstate
Definition: gin_private.h:426
uintptr_t Datum
Definition: postgres.h:367
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:195
int16 attnum
Definition: pg_attribute.h:79
void GinInitBuffer(Buffer b, uint32 f)
Definition: ginutil.c:356
BlockNumber nTotalPages
Definition: gin.h:45
ItemPointerData * ginGetBAEntry(BuildAccumulator *accum, OffsetNumber *attnum, Datum *key, GinNullCategory *category, uint32 *n)
Definition: ginbulk.c:268
#define RelationNeedsWAL(relation)
Definition: rel.h:538
void ginBeginBAScan(BuildAccumulator *accum)
Definition: ginbulk.c:257
void log_newpage_range(Relation rel, ForkNumber forkNum, BlockNumber startblk, BlockNumber endblk, bool page_std)
Definition: xloginsert.c:1042
void ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
Definition: ginutil.c:656
void * palloc(Size size)
Definition: mcxt.c:949
MemoryContext tmpCtx
Definition: gininsert.c:35
#define elog(elevel,...)
Definition: elog.h:214
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
MemoryContext funcCtx
Definition: gininsert.c:36
int Buffer
Definition: buf.h:23
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:41

◆ ginbuildempty()

void ginbuildempty ( Relation  index)

Definition at line 437 of file gininsert.c.

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

Referenced by ginhandler().

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

◆ ginbulkdelete()

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

Definition at line 564 of file ginvacuum.c.

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

566 {
567  Relation index = info->index;
568  BlockNumber blkno = GIN_ROOT_BLKNO;
569  GinVacuumState gvs;
570  Buffer buffer;
571  BlockNumber rootOfPostingTree[BLCKSZ / (sizeof(IndexTupleData) + sizeof(ItemId))];
572  uint32 nRoot;
573 
575  "Gin vacuum temporary context",
577  gvs.index = index;
578  gvs.callback = callback;
579  gvs.callback_state = callback_state;
580  gvs.strategy = info->strategy;
581  initGinState(&gvs.ginstate, index);
582 
583  /* first time through? */
584  if (stats == NULL)
585  {
586  /* Yes, so initialize stats to zeroes */
588 
589  /*
590  * and cleanup any pending inserts
591  */
593  false, true, stats);
594  }
595 
596  /* we'll re-count the tuples each time */
597  stats->num_index_tuples = 0;
598  gvs.result = stats;
599 
600  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
601  RBM_NORMAL, info->strategy);
602 
603  /* find leaf page */
604  for (;;)
605  {
606  Page page = BufferGetPage(buffer);
607  IndexTuple itup;
608 
609  LockBuffer(buffer, GIN_SHARE);
610 
611  Assert(!GinPageIsData(page));
612 
613  if (GinPageIsLeaf(page))
614  {
615  LockBuffer(buffer, GIN_UNLOCK);
616  LockBuffer(buffer, GIN_EXCLUSIVE);
617 
618  if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page))
619  {
620  LockBuffer(buffer, GIN_UNLOCK);
621  continue; /* check it one more */
622  }
623  break;
624  }
625 
627 
628  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber));
629  blkno = GinGetDownlink(itup);
630  Assert(blkno != InvalidBlockNumber);
631 
632  UnlockReleaseBuffer(buffer);
633  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
634  RBM_NORMAL, info->strategy);
635  }
636 
637  /* right now we found leftmost page in entry's BTree */
638 
639  for (;;)
640  {
641  Page page = BufferGetPage(buffer);
642  Page resPage;
643  uint32 i;
644 
645  Assert(!GinPageIsData(page));
646 
647  resPage = ginVacuumEntryPage(&gvs, buffer, rootOfPostingTree, &nRoot);
648 
649  blkno = GinPageGetOpaque(page)->rightlink;
650 
651  if (resPage)
652  {
654  PageRestoreTempPage(resPage, page);
655  MarkBufferDirty(buffer);
656  xlogVacuumPage(gvs.index, buffer);
657  UnlockReleaseBuffer(buffer);
659  }
660  else
661  {
662  UnlockReleaseBuffer(buffer);
663  }
664 
666 
667  for (i = 0; i < nRoot; i++)
668  {
669  ginVacuumPostingTree(&gvs, rootOfPostingTree[i]);
671  }
672 
673  if (blkno == InvalidBlockNumber) /* rightmost page */
674  break;
675 
676  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
677  RBM_NORMAL, info->strategy);
678  LockBuffer(buffer, GIN_EXCLUSIVE);
679  }
680 
682 
683  return gvs.result;
684 }
#define GIN_UNLOCK
Definition: gin_private.h:48
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
#define AllocSetContextCreate
Definition: memutils.h:170
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:403
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1406
Relation index
Definition: ginvacuum.c:30
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:590
BufferAccessStrategy strategy
Definition: ginvacuum.c:35
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
BufferAccessStrategy strategy
Definition: genam.h:52
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
Relation index
Definition: genam.h:46
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
IndexBulkDeleteResult * result
Definition: ginvacuum.c:31
Definition: type.h:89
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3346
static void xlogVacuumPage(Relation index, Buffer buffer)
Definition: ginvacuum.c:90
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:48
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
static Page ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
Definition: ginvacuum.c:455
IndexBulkDeleteCallback callback
Definition: ginvacuum.c:32
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:94
unsigned int uint32
Definition: c.h:367
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
void * callback_state
Definition: ginvacuum.c:33
#define BufferGetPage(buffer)
Definition: bufmgr.h:157
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3302
#define GIN_SHARE
Definition: gin_private.h:49
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void * palloc0(Size size)
Definition: mcxt.c:980
struct IndexTupleData IndexTupleData
#define GIN_EXCLUSIVE
Definition: gin_private.h:50
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3560
#define GinGetDownlink(itup)
Definition: ginblock.h:258
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition: ginfast.c:780
#define GinPageIsData(page)
Definition: ginblock.h:115
#define Assert(condition)
Definition: c.h:738
#define InvalidBlockNumber
Definition: block.h:33
int i
static void ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
Definition: ginvacuum.c:408
void vacuum_delay_point(void)
Definition: vacuum.c:1997
MemoryContext tmpCxt
Definition: ginvacuum.c:36
double num_index_tuples
Definition: genam.h:77
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
#define GIN_ROOT_BLKNO
Definition: ginblock.h:52
Pointer Page
Definition: bufpage.h:78
GinState ginstate
Definition: ginvacuum.c:34

◆ ginCompareAttEntries()

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

Definition at line 416 of file ginutil.c.

References ginCompareEntries().

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

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

◆ ginCompareEntries()

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

Definition at line 394 of file ginutil.c.

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

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

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

◆ ginCompareItemPointers()

static int ginCompareItemPointers ( ItemPointer  a,
ItemPointer  b 
)
inlinestatic

Definition at line 480 of file gin_private.h.

References GinItemPointerGetBlockNumber, GinItemPointerGetOffsetNumber, and ginTraverseLock().

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

481 {
482  uint64 ia = (uint64) GinItemPointerGetBlockNumber(a) << 32 | GinItemPointerGetOffsetNumber(a);
483  uint64 ib = (uint64) GinItemPointerGetBlockNumber(b) << 32 | GinItemPointerGetOffsetNumber(b);
484 
485  if (ia == ib)
486  return 0;
487  else if (ia > ib)
488  return 1;
489  else
490  return -1;
491 }
#define GinItemPointerGetOffsetNumber(pointer)
Definition: ginblock.h:147
#define GinItemPointerGetBlockNumber(pointer)
Definition: ginblock.h:144

◆ ginCompressPostingList()

GinPostingList* ginCompressPostingList ( const ItemPointer  ipd,
int  nipd,
int  maxsize,
int *  nwritten 
)

Definition at line 197 of file ginpostinglist.c.

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

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

199 {
200  uint64 prev;
201  int totalpacked = 0;
202  int maxbytes;
203  GinPostingList *result;
204  unsigned char *ptr;
205  unsigned char *endptr;
206 
207  maxsize = SHORTALIGN_DOWN(maxsize);
208 
209  result = palloc(maxsize);
210 
211  maxbytes = maxsize - offsetof(GinPostingList, bytes);
212  Assert(maxbytes > 0);
213 
214  /* Store the first special item */
215  result->first = ipd[0];
216 
217  prev = itemptr_to_uint64(&result->first);
218 
219  ptr = result->bytes;
220  endptr = result->bytes + maxbytes;
221  for (totalpacked = 1; totalpacked < nipd; totalpacked++)
222  {
223  uint64 val = itemptr_to_uint64(&ipd[totalpacked]);
224  uint64 delta = val - prev;
225 
226  Assert(val > prev);
227 
228  if (endptr - ptr >= MaxBytesPerInteger)
229  encode_varbyte(delta, &ptr);
230  else
231  {
232  /*
233  * There are less than 7 bytes left. Have to check if the next
234  * item fits in that space before writing it out.
235  */
236  unsigned char buf[MaxBytesPerInteger];
237  unsigned char *p = buf;
238 
239  encode_varbyte(delta, &p);
240  if (p - buf > (endptr - ptr))
241  break; /* output is full */
242 
243  memcpy(ptr, buf, p - buf);
244  ptr += (p - buf);
245  }
246  prev = val;
247  }
248  result->nbytes = ptr - result->bytes;
249 
250  /*
251  * If we wrote an odd number of bytes, zero out the padding byte at the
252  * end.
253  */
254  if (result->nbytes != SHORTALIGN(result->nbytes))
255  result->bytes[result->nbytes] = 0;
256 
257  if (nwritten)
258  *nwritten = totalpacked;
259 
260  Assert(SizeOfGinPostingList(result) <= maxsize);
261 
262  /*
263  * Check that the encoded segment decodes back to the original items.
264  */
265 #if defined (CHECK_ENCODING_ROUNDTRIP)
266  {
267  int ndecoded;
268  ItemPointer tmp = ginPostingListDecode(result, &ndecoded);
269 
270  Assert(ndecoded == totalpacked);
271  Assert(memcmp(tmp, ipd, ndecoded * sizeof(ItemPointerData)) == 0);
272  pfree(tmp);
273  }
274 #endif
275 
276  return result;
277 }
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded)
def bytes(source, encoding='ascii', errors='strict')
#define SHORTALIGN_DOWN(LEN)
Definition: c.h:699
ItemPointerData first
Definition: ginblock.h:338
void pfree(void *pointer)
Definition: mcxt.c:1056
unsigned char bytes[FLEXIBLE_ARRAY_MEMBER]
Definition: ginblock.h:340
#define MaxBytesPerInteger
static char * buf
Definition: pg_test_fsync.c:67
uint16 nbytes
Definition: ginblock.h:339
#define Assert(condition)
Definition: c.h:738
static uint64 itemptr_to_uint64(const ItemPointer iptr)
static void encode_varbyte(uint64 val, unsigned char **ptr)
void * palloc(Size size)
Definition: mcxt.c:949
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:343
#define SHORTALIGN(LEN)
Definition: c.h:687
long val
Definition: informix.c:664
#define offsetof(type, field)
Definition: c.h:661

◆ ginDataFillRoot()

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

Definition at line 1343 of file gindatapage.c.

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

Referenced by ginPrepareDataScan().

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

◆ GinDataLeafPageGetItems()

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

Definition at line 135 of file gindatapage.c.

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

Referenced by entryLoadMoreItems(), and startScanEntry().

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

◆ GinDataLeafPageGetItemsToTbm()

int GinDataLeafPageGetItemsToTbm ( Page  page,
TIDBitmap tbm 
)

Definition at line 182 of file gindatapage.c.

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

Referenced by scanPostingTree().

183 {
184  ItemPointer uncompressed;
185  int nitems;
186 
187  if (GinPageIsCompressed(page))
188  {
191 
192  nitems = ginPostingListDecodeAllSegmentsToTbm(segment, len, tbm);
193  }
194  else
195  {
196  uncompressed = dataLeafPageGetUncompressed(page, &nitems);
197 
198  if (nitems > 0)
199  tbm_add_tuples(tbm, uncompressed, nitems, false);
200  }
201 
202  return nitems;
203 }
int ginPostingListDecodeAllSegmentsToTbm(GinPostingList *ptr, int len, TIDBitmap *tbm)
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:376
#define GinPageIsCompressed(page)
Definition: ginblock.h:121
#define GinDataLeafPageGetPostingListSize(page)
Definition: ginblock.h:281
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:279
size_t Size
Definition: c.h:466
static ItemPointer dataLeafPageGetUncompressed(Page page, int *nitems)
Definition: gindatapage.c:211

◆ GinDataPageAddPostingItem()

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

Definition at line 380 of file gindatapage.c.

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

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

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

◆ ginendscan()

void ginendscan ( IndexScanDesc  scan)

Definition at line 458 of file ginscan.c.

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

Referenced by ginhandler().

459 {
460  GinScanOpaque so = (GinScanOpaque) scan->opaque;
461 
462  ginFreeScanKeys(so);
463 
466 
467  pfree(so);
468 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
void pfree(void *pointer)
Definition: mcxt.c:1056
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:383
MemoryContext keyCtx
Definition: gin_private.h:378
MemoryContext tempCtx
Definition: gin_private.h:368
void ginFreeScanKeys(GinScanOpaque so)
Definition: ginscan.c:233

◆ 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:416
void pfree(void *pointer)
Definition: mcxt.c:1056
#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(elevel,...)
Definition: elog.h:214
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ ginEntryInsert()

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

Definition at line 179 of file gininsert.c.

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

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

183 {
184  GinBtreeData btree;
185  GinBtreeEntryInsertData insertdata;
186  GinBtreeStack *stack;
187  IndexTuple itup;
188  Page page;
189 
190  insertdata.isDelete = false;
191 
192  ginPrepareEntryScan(&btree, attnum, key, category, ginstate);
193  btree.isBuild = (buildStats != NULL);
194 
195  stack = ginFindLeafPage(&btree, false, false, NULL);
196  page = BufferGetPage(stack->buffer);
197 
198  if (btree.findItem(&btree, stack))
199  {
200  /* found pre-existing entry */
201  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off));
202 
203  if (GinIsPostingTree(itup))
204  {
205  /* add entries to existing posting tree */
206  BlockNumber rootPostingTree = GinGetPostingTree(itup);
207 
208  /* release all stack */
209  LockBuffer(stack->buffer, GIN_UNLOCK);
210  freeGinBtreeStack(stack);
211 
212  /* insert into posting tree */
213  ginInsertItemPointers(ginstate->index, rootPostingTree,
214  items, nitem,
215  buildStats);
216  return;
217  }
218 
219  CheckForSerializableConflictIn(ginstate->index, NULL,
220  BufferGetBlockNumber(stack->buffer));
221  /* modify an existing leaf entry */
222  itup = addItemPointersToLeafTuple(ginstate, itup,
223  items, nitem, buildStats, stack->buffer);
224 
225  insertdata.isDelete = true;
226  }
227  else
228  {
229  CheckForSerializableConflictIn(ginstate->index, NULL,
230  BufferGetBlockNumber(stack->buffer));
231  /* no match, so construct a new leaf entry */
232  itup = buildFreshLeafTuple(ginstate, attnum, key, category,
233  items, nitem, buildStats, stack->buffer);
234 
235  /*
236  * nEntries counts leaf tuples, so increment it only when we make a
237  * new one.
238  */
239  if (buildStats)
240  buildStats->nEntries++;
241  }
242 
243  /* Insert the new or modified leaf tuple */
244  insertdata.entry = itup;
245  ginInsertValue(&btree, stack, &insertdata, buildStats);
246  pfree(itup);
247 }
#define GIN_UNLOCK
Definition: gin_private.h:48
void ginInsertItemPointers(Relation index, BlockNumber rootBlkno, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gindatapage.c:1902
Relation index
Definition: gin_private.h:58
OffsetNumber off
Definition: gin_private.h:131
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, bool rootConflictCheck, Snapshot snapshot)
Definition: ginbtree.c:80
int64 nEntries
Definition: gin.h:48
uint32 BlockNumber
Definition: block.h:31
static IndexTuple addItemPointersToLeafTuple(GinState *ginstate, IndexTuple old, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats, Buffer buffer)
Definition: gininsert.c:49
bool(* findItem)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:154
void pfree(void *pointer)
Definition: mcxt.c:1056
IndexTupleData * IndexTuple
Definition: itup.h:53
static IndexTuple buildFreshLeafTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats, Buffer buffer)
Definition: gininsert.c:129
#define BufferGetPage(buffer)
Definition: bufmgr.h:157
void ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum, Datum key, GinNullCategory category, GinState *ginstate)
Definition: ginentrypage.c:745
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3560
void ginInsertValue(GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
Definition: ginbtree.c:777
void CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno)
Definition: predicate.c:4374
int16 attnum
Definition: pg_attribute.h:79
#define GinGetPostingTree(itup)
Definition: ginblock.h:234
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2571
#define GinIsPostingTree(itup)
Definition: ginblock.h:232
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:194
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78

◆ ginExtractEntries()

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

Definition at line 489 of file ginutil.c.

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

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

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

◆ ginFindLeafPage()

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

Definition at line 80 of file ginbtree.c.

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

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

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

◆ GinFormTuple()

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

Definition at line 45 of file ginentrypage.c.

References Assert, ereport, errcode(), errmsg(), ERROR, GIN_CAT_NORM_KEY, GinCategoryOffset, GinGetPosting, GinMaxItemSize, GinSetNPosting, GinSetNullCategory, GinSetPostingOffset, GinState::index, index_form_tuple(), INDEX_SIZE_MASK, IndexTupleHasNulls, IndexTupleSize, sort-test::key, 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:230
Relation index
Definition: gin_private.h:58
#define INDEX_SIZE_MASK
Definition: itup.h:65
int errcode(int sqlerrcode)
Definition: elog.c:610
#define IndexTupleHasNulls(itup)
Definition: itup.h:72
#define GinGetPosting(itup)
Definition: ginblock.h:239
IndexTuple index_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: indextuple.c:47
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
signed char GinNullCategory
Definition: ginblock.h:207
#define GinSetPostingOffset(itup, n)
Definition: ginblock.h:238
#define GIN_CAT_NORM_KEY
Definition: ginblock.h:209
#define RelationGetRelationName(relation)
Definition: rel.h:470
unsigned int uint32
Definition: c.h:367
uintptr_t Datum
Definition: postgres.h:367
TupleDesc tupdesc[INDEX_MAX_KEYS]
Definition: gin_private.h:73
int16 attnum
Definition: pg_attribute.h:79
#define ereport(elevel,...)
Definition: elog.h:144
#define Max(x, y)
Definition: c.h:914
#define Assert(condition)
Definition: c.h:738
#define GinSetNullCategory(itup, ginstate, c)
Definition: ginblock.h:223
size_t Size
Definition: c.h:466
#define MAXALIGN(LEN)
Definition: c.h:691
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define GinMaxItemSize
Definition: ginblock.h:249
unsigned short t_info
Definition: itup.h:49
#define SHORTALIGN(LEN)
Definition: c.h:687
bool oneCol
Definition: gin_private.h:59
#define GinCategoryOffset(itup, ginstate)
Definition: ginblock.h:218
#define UInt16GetDatum(X)
Definition: postgres.h:465
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ ginFreeScanKeys()

void ginFreeScanKeys ( GinScanOpaque  so)

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

234 {
235  uint32 i;
236 
237  if (so->keys == NULL)
238  return;
239 
240  for (i = 0; i < so->totalentries; i++)
241  {
242  GinScanEntry entry = so->entries[i];
243 
244  if (entry->buffer != InvalidBuffer)
245  ReleaseBuffer(entry->buffer);
246  if (entry->list)
247  pfree(entry->list);
248  if (entry->matchIterator)
250  if (entry->matchBitmap)
251  tbm_free(entry->matchBitmap);
252  }
253 
255 
256  so->keys = NULL;
257  so->nkeys = 0;
258  so->entries = NULL;
259  so->totalentries = 0;
260 }
void tbm_end_iterate(TBMIterator *iterator)
Definition: tidbitmap.c:1145
TBMIterator * matchIterator
Definition: gin_private.h:352
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3323
ItemPointerData * list
Definition: gin_private.h:356
void pfree(void *pointer)
Definition: mcxt.c:1056
void tbm_free(TIDBitmap *tbm)
Definition: tidbitmap.c:321
MemoryContext keyCtx
Definition: gin_private.h:378
unsigned int uint32
Definition: c.h:367
TIDBitmap * matchBitmap
Definition: gin_private.h:351
GinScanKey keys
Definition: gin_private.h:371
#define MemoryContextResetAndDeleteChildren(ctx)
Definition: memutils.h:67
GinScanEntry * entries
Definition: gin_private.h:374
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(), rbt_iterate(), GinEntryAccumulator::shouldSort, and BuildAccumulator::tree_walk.

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

271 {
272  GinEntryAccumulator *entry;
274 
275  entry = (GinEntryAccumulator *) rbt_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 }
RBTNode * rbt_iterate(RBTreeIterator *iter)
Definition: rbtree.c:764
OffsetNumber attnum
Definition: gin_private.h:417
GinNullCategory category
Definition: gin_private.h:416
int16 attnum
Definition: pg_attribute.h:79
#define Assert(condition)
Definition: c.h:738
static int qsortCompareItemPointers(const void *a, const void *b)
Definition: ginbulk.c:246
RBTreeIterator tree_walk
Definition: gin_private.h:431
#define qsort(a, b, c, d)
Definition: port.h:479
ItemPointerData * list
Definition: gin_private.h:419

◆ gingetbitmap()

int64 gingetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

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

1894 {
1895  GinScanOpaque so = (GinScanOpaque) scan->opaque;
1896  int64 ntids;
1897  ItemPointerData iptr;
1898  bool recheck;
1899 
1900  /*
1901  * Set up the scan keys, and check for unsatisfiable query.
1902  */
1903  ginFreeScanKeys(so); /* there should be no keys yet, but just to be
1904  * sure */
1905  ginNewScanKey(scan);
1906 
1907  if (GinIsVoidRes(scan))
1908  return 0;
1909 
1910  ntids = 0;
1911 
1912  /*
1913  * First, scan the pending list and collect any matching entries into the
1914  * bitmap. After we scan a pending item, some other backend could post it
1915  * into the main index, and so we might visit it a second time during the
1916  * main scan. This is okay because we'll just re-set the same bit in the
1917  * bitmap. (The possibility of duplicate visits is a major reason why GIN
1918  * can't support the amgettuple API, however.) Note that it would not do
1919  * to scan the main index before the pending list, since concurrent
1920  * cleanup could then make us miss entries entirely.
1921  */
1922  scanPendingInsert(scan, tbm, &ntids);
1923 
1924  /*
1925  * Now scan the main index.
1926  */
1927  startScan(scan);
1928 
1929  ItemPointerSetMin(&iptr);
1930 
1931  for (;;)
1932  {
1934 
1935  if (!scanGetItem(scan, iptr, &iptr, &recheck))
1936  break;
1937 
1938  if (ItemPointerIsLossyPage(&iptr))
1940  else
1941  tbm_add_tuples(tbm, &iptr, 1, recheck);
1942  ntids++;
1943  }
1944 
1945  return ntids;
1946 }
static void scanPendingInsert(IndexScanDesc scan, TIDBitmap *tbm, int64 *ntids)
Definition: ginget.c:1798
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:376
#define ItemPointerIsLossyPage(p)
Definition: ginblock.h:176
static void startScan(IndexScanDesc scan)
Definition: ginget.c:596
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:383
#define ItemPointerSetMin(p)
Definition: ginblock.h:167
static bool scanGetItem(IndexScanDesc scan, ItemPointerData advancePast, ItemPointerData *item, bool *recheck)
Definition: ginget.c:1260
void ginNewScanKey(IndexScanDesc scan)
Definition: ginscan.c:263
#define GinIsVoidRes(s)
Definition: ginget.c:1890
void tbm_add_page(TIDBitmap *tbm, BlockNumber pageno)
Definition: tidbitmap.c:442
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
void ginFreeScanKeys(GinScanOpaque so)
Definition: ginscan.c:233

◆ ginHeapTupleFastCollect()

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

Definition at line 473 of file ginfast.c.

References KeyArray::categories, elog, ERROR, ginExtractEntries(), GinFormTuple(), i, IndexTupleSize, GinTupleCollector::lentuples, MaxAllocSize, GinTupleCollector::ntuples, palloc(), repalloc(), GinTupleCollector::sumsize, IndexTupleData::t_tid, and GinTupleCollector::tuples.

Referenced by gininsert().

477 {
478  Datum *entries;
479  GinNullCategory *categories;
480  int32 i,
481  nentries;
482 
483  /*
484  * Extract the key values that need to be inserted in the index
485  */
486  entries = ginExtractEntries(ginstate, attnum, value, isNull,
487  &nentries, &categories);
488 
489  /*
490  * Protect against integer overflow in allocation calculations
491  */
492  if (nentries < 0 ||
493  collector->ntuples + nentries > MaxAllocSize / sizeof(IndexTuple))
494  elog(ERROR, "too many entries for GIN index");
495 
496  /*
497  * Allocate/reallocate memory for storing collected tuples
498  */
499  if (collector->tuples == NULL)
500  {
501  /*
502  * Determine the number of elements to allocate in the tuples array
503  * initially. Make it a power of 2 to avoid wasting memory when
504  * resizing (since palloc likes powers of 2).
505  */
506  collector->lentuples = 16;
507  while (collector->lentuples < nentries)
508  collector->lentuples *= 2;
509 
510  collector->tuples = (IndexTuple *) palloc(sizeof(IndexTuple) * collector->lentuples);
511  }
512  else if (collector->lentuples < collector->ntuples + nentries)
513  {
514  /*
515  * Advance lentuples to the next suitable power of 2. This won't
516  * overflow, though we could get to a value that exceeds
517  * MaxAllocSize/sizeof(IndexTuple), causing an error in repalloc.
518  */
519  do
520  {
521  collector->lentuples *= 2;
522  } while (collector->lentuples < collector->ntuples + nentries);
523 
524  collector->tuples = (IndexTuple *) repalloc(collector->tuples,
525  sizeof(IndexTuple) * collector->lentuples);
526  }
527 
528  /*
529  * Build an index tuple for each key value, and add to array. In pending
530  * tuples we just stick the heap TID into t_tid.
531  */
532  for (i = 0; i < nentries; i++)
533  {
534  IndexTuple itup;
535 
536  itup = GinFormTuple(ginstate, attnum, entries[i], categories[i],
537  NULL, 0, 0, true);
538  itup->t_tid = *ht_ctid;
539  collector->tuples[collector->ntuples++] = itup;
540  collector->sumsize += IndexTupleSize(itup);
541  }
542 }
ItemPointerData t_tid
Definition: itup.h:37
signed int int32
Definition: c.h:355
#define ERROR
Definition: elog.h:43
signed char GinNullCategory
Definition: ginblock.h:207
#define MaxAllocSize
Definition: memutils.h:40
IndexTuple * tuples
Definition: gin_private.h:448
uintptr_t Datum
Definition: postgres.h:367
int16 attnum
Definition: pg_attribute.h:79
static struct @143 value
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:1069
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:214
int i
Datum * ginExtractEntries(GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, int32 *nentries, GinNullCategory **categories)
Definition: ginutil.c:489
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ ginHeapTupleFastInsert()

void ginHeapTupleFastInsert ( GinState ginstate,
GinTupleCollector collector 
)

Definition at line 218 of file ginfast.c.

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

Referenced by gininsert().

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

◆ ginInitBA()

void ginInitBA ( BuildAccumulator accum)

Definition at line 109 of file ginbulk.c.

References BuildAccumulator::allocatedMemory, cmpEntryAccumulator(), BuildAccumulator::eas_used, BuildAccumulator::entryallocator, ginAllocEntryAccumulator(), ginCombineData(), rbt_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 = rbt_create(sizeof(GinEntryAccumulator),
119  NULL, /* no freefunc needed */
120  (void *) accum);
121 }
GinEntryAccumulator * entryallocator
Definition: gin_private.h:428
RBTree * rbt_create(Size node_size, rbt_comparator comparator, rbt_combiner combiner, rbt_allocfunc allocfunc, rbt_freefunc freefunc, void *arg)
Definition: rbtree.c:102
static void ginCombineData(RBTNode *existing, const RBTNode *newdata, void *arg)
Definition: ginbulk.c:30
static RBTNode * ginAllocEntryAccumulator(void *arg)
Definition: ginbulk.c:85
static int cmpEntryAccumulator(const RBTNode *a, const RBTNode *b, void *arg)
Definition: ginbulk.c:72

◆ GinInitBuffer()

void GinInitBuffer ( Buffer  b,
uint32  f 
)

Definition at line 356 of file ginutil.c.

References BufferGetPage, BufferGetPageSize, and GinInitPage().

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

357 {
359 }
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:343
#define BufferGetPage(buffer)
Definition: bufmgr.h:157
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:144

◆ ginInitConsistentFunction()

void ginInitConsistentFunction ( GinState ginstate,
GinScanKey  key 
)

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

224 {
226  {
229  }
230  else
231  {
232  key->consistentFmgrInfo = &ginstate->consistentFn[key->attnum - 1];
233  key->triConsistentFmgrInfo = &ginstate->triConsistentFn[key->attnum - 1];
234  key->collation = ginstate->supportCollation[key->attnum - 1];
235 
236  if (OidIsValid(ginstate->consistentFn[key->attnum - 1].fn_oid))
238  else
240 
241  if (OidIsValid(ginstate->triConsistentFn[key->attnum - 1].fn_oid))
243  else
245  }
246 }
FmgrInfo * triConsistentFmgrInfo
Definition: gin_private.h:293
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gin_private.h:87
static GinTernaryValue directTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:95
static GinTernaryValue shimTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:152
#define GIN_SEARCH_MODE_EVERYTHING
Definition: gin.h:37
FmgrInfo consistentFn[INDEX_MAX_KEYS]
Definition: gin_private.h:81
FmgrInfo * consistentFmgrInfo
Definition: gin_private.h:292
#define OidIsValid(objectId)
Definition: c.h:644
OffsetNumber attnum
Definition: gin_private.h:304
static GinTernaryValue trueTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:62
bool(* boolConsistentFn)(GinScanKey key)
Definition: gin_private.h:290
Oid fn_oid
Definition: fmgr.h:59
GinTernaryValue(* triConsistentFn)(GinScanKey key)
Definition: gin_private.h:291
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:114
FmgrInfo triConsistentFn[INDEX_MAX_KEYS]
Definition: gin_private.h:82

◆ GinInitMetabuffer()

void GinInitMetabuffer ( Buffer  b)

Definition at line 362 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(), ginRedoDeleteListPages(), and ginRedoUpdateMetapage().

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

◆ GinInitPage()

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

Definition at line 343 of file ginutil.c.

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

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

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

◆ gininsert()

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

Definition at line 488 of file gininsert.c.

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

Referenced by ginhandler().

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

◆ ginInsertBAEntries()

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

Definition at line 210 of file ginbulk.c.

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

Referenced by ginHeapTupleBulkInsert(), and processPendingPage().

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

◆ ginInsertCleanup()

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

Definition at line 780 of file ginfast.c.

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

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

◆ ginInsertItemPointers()

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

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

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

◆ ginInsertValue()

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

Definition at line 777 of file ginbtree.c.

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

Referenced by ginEntryInsert(), and ginInsertItemPointers().

779 {
780  bool done;
781 
782  /* If the leaf page was incompletely split, finish the split first */
784  ginFinishSplit(btree, stack, false, buildStats);
785 
786  done = ginPlaceToPage(btree, stack,
787  insertdata, InvalidBlockNumber,
788  InvalidBuffer, buildStats);
789  if (done)
790  {
791  LockBuffer(stack->buffer, GIN_UNLOCK);
792  freeGinBtreeStack(stack);
793  }
794  else
795  ginFinishSplit(btree, stack, true, buildStats);
796 }
#define GIN_UNLOCK
Definition: gin_private.h:48
#define GinPageIsIncompleteSplit(page)
Definition: ginblock.h:127
static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack, GinStatsData *buildStats)
Definition: ginbtree.c:668
#define InvalidBuffer
Definition: buf.h:25
#define BufferGetPage(buffer)
Definition: bufmgr.h:157
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3560
#define InvalidBlockNumber
Definition: block.h:33
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:194
static bool ginPlaceToPage(GinBtree btree, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, Buffer childbuf, GinStatsData *buildStats)
Definition: ginbtree.c:330

◆ ginMergeItemPointers()

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

Definition at line 378 of file ginpostinglist.c.

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

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

381 {
382  ItemPointerData *dst;
383 
384  dst = (ItemPointer) palloc((na + nb) * sizeof(ItemPointerData));
385 
386  /*
387  * If the argument arrays don't overlap, we can just append them to each
388  * other.
389  */
390  if (na == 0 || nb == 0 || ginCompareItemPointers(&a[na - 1], &b[0]) < 0)
391  {
392  memcpy(dst, a, na * sizeof(ItemPointerData));
393  memcpy(&dst[na], b, nb * sizeof(ItemPointerData));
394  *nmerged = na + nb;
395  }
396  else if (ginCompareItemPointers(&b[nb - 1], &a[0]) < 0)
397  {
398  memcpy(dst, b, nb * sizeof(ItemPointerData));
399  memcpy(&dst[nb], a, na * sizeof(ItemPointerData));
400  *nmerged = na + nb;
401  }
402  else
403  {
404  ItemPointerData *dptr = dst;
405  ItemPointerData *aptr = a;
406  ItemPointerData *bptr = b;
407 
408  while (aptr - a < na && bptr - b < nb)
409  {
410  int cmp = ginCompareItemPointers(aptr, bptr);
411 
412  if (cmp > 0)
413  *dptr++ = *bptr++;
414  else if (cmp == 0)
415  {
416  /* only keep one copy of the identical items */
417  *dptr++ = *bptr++;
418  aptr++;
419  }
420  else
421  *dptr++ = *aptr++;
422  }
423 
424  while (aptr - a < na)
425  *dptr++ = *aptr++;
426 
427  while (bptr - b < nb)
428  *dptr++ = *bptr++;
429 
430  *nmerged = dptr - dst;
431  }
432 
433  return dst;
434 }
ItemPointerData * ItemPointer
Definition: itemptr.h:49
struct ItemPointerData ItemPointerData
static int ginCompareItemPointers(ItemPointer a, ItemPointer b)
Definition: gin_private.h:480
void * palloc(Size size)
Definition: mcxt.c:949
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 297 of file ginutil.c.

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

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

298 {
299  Buffer buffer;
300  bool needLock;
301 
302  /* First, try to get a page from FSM */
303  for (;;)
304  {
305  BlockNumber blkno = GetFreeIndexPage(index);
306 
307  if (blkno == InvalidBlockNumber)
308  break;
309 
310  buffer = ReadBuffer(index, blkno);
311 
312  /*
313  * We have to guard against the possibility that someone else already
314  * recycled this page; the buffer may be locked if so.
315  */
316  if (ConditionalLockBuffer(buffer))
317  {
318  if (GinPageIsRecyclable(BufferGetPage(buffer)))
319  return buffer; /* OK to use */
320 
321  LockBuffer(buffer, GIN_UNLOCK);
322  }
323 
324  /* Can't use it, so release buffer and try again */
325  ReleaseBuffer(buffer);
326  }
327 
328  /* Must extend the file */
329  needLock = !RELATION_IS_LOCAL(index);
330  if (needLock)
332 
333  buffer = ReadBuffer(index, P_NEW);
334  LockBuffer(buffer, GIN_EXCLUSIVE);
335 
336  if (needLock)
338 
339  return buffer;
340 }
#define GIN_UNLOCK
Definition: gin_private.h:48
#define GinPageIsRecyclable(page)
Definition: ginblock.h:137
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:556
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3323
#define P_NEW
Definition: bufmgr.h:79
#define BufferGetPage(buffer)
Definition: bufmgr.h:157
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3586
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:402
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:452
#define GIN_EXCLUSIVE
Definition: gin_private.h:50
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3560
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:544
#define InvalidBlockNumber
Definition: block.h:33
int Buffer
Definition: buf.h:23

◆ ginNewScanKey()

void ginNewScanKey ( IndexScanDesc  scan)

Definition at line 263 of file ginscan.c.

References i, INDEX_MAX_KEYS, IndexScanDescData::keyData, and IndexScanDescData::opaque.

Referenced by gingetbitmap().

264 {
265  ScanKey scankey = scan->keyData;
266  GinScanOpaque so = (GinScanOpaque) scan->opaque;
267  int i;
268  bool hasNullQuery = false;
269  bool attrHasNormalScan[INDEX_MAX_KEYS] = {false};
270  MemoryContext oldCtx;
271 
272  /*
273  * Allocate all the scan key information in the key context. (If
274  * extractQuery leaks anything there, it won't be reset until the end of
275  * scan or rescan, but that's OK.)
276  */
277  oldCtx = MemoryContextSwitchTo(so->keyCtx);
278 
279  /* if no scan keys provided, allocate extra EVERYTHING GinScanKey */
280  so->keys = (GinScanKey)
281  palloc(Max(scan->numberOfKeys, 1) * sizeof(GinScanKeyData));
282  so->nkeys = 0;
283 
284  /* initialize expansible array of GinScanEntry pointers */
285  so->totalentries = 0;
286  so->allocentries = 32;
287  so->entries = (GinScanEntry *)
288  palloc(so->allocentries * sizeof(GinScanEntry));
289 
290  so->isVoidRes = false;
291 
292  for (i = 0; i < scan->numberOfKeys; i++)
293  {
294  ScanKey skey = &scankey[i];
295  Datum *queryValues;
296  int32 nQueryValues = 0;
297  bool *partial_matches = NULL;
298  Pointer *extra_data = NULL;
299  bool *nullFlags = NULL;
300  GinNullCategory *categories;
301  int32 searchMode = GIN_SEARCH_MODE_DEFAULT;
302 
303  /*
304  * We assume that GIN-indexable operators are strict, so a null query
305  * argument means an unsatisfiable query.
306  */
307  if (skey->sk_flags & SK_ISNULL)
308  {
309  so->isVoidRes = true;
310  break;
311  }
312 
313  /* OK to call the extractQueryFn */
314  queryValues = (Datum *)
315  DatumGetPointer(FunctionCall7Coll(&so->ginstate.extractQueryFn[skey->sk_attno - 1],
316  so->ginstate.supportCollation[skey->sk_attno - 1],
317  skey->sk_argument,
318  PointerGetDatum(&nQueryValues),
320  PointerGetDatum(&partial_matches),
321  PointerGetDatum(&extra_data),
322  PointerGetDatum(&nullFlags),
323  PointerGetDatum(&searchMode)));
324 
325  /*
326  * If bogus searchMode is returned, treat as GIN_SEARCH_MODE_ALL; note
327  * in particular we don't allow extractQueryFn to select
328  * GIN_SEARCH_MODE_EVERYTHING.
329  */
330  if (searchMode < GIN_SEARCH_MODE_DEFAULT ||
331  searchMode > GIN_SEARCH_MODE_ALL)
332  searchMode = GIN_SEARCH_MODE_ALL;
333 
334  /* Non-default modes require the index to have placeholders */
335  if (searchMode != GIN_SEARCH_MODE_DEFAULT)
336  hasNullQuery = true;
337 
338  /*
339  * In default mode, no keys means an unsatisfiable query.
340  */
341  if (queryValues == NULL || nQueryValues <= 0)
342  {
343  if (searchMode == GIN_SEARCH_MODE_DEFAULT)
344  {
345  so->isVoidRes = true;
346  break;
347  }
348  nQueryValues = 0; /* ensure sane value */
349  }
350 
351  /*
352  * Create GinNullCategory representation. If the extractQueryFn
353  * didn't create a nullFlags array, we assume everything is non-null.
354  * While at it, detect whether any null keys are present.
355  */
356  categories = (GinNullCategory *) palloc0(nQueryValues * sizeof(GinNullCategory));
357  if (nullFlags)
358  {
359  int32 j;
360 
361  for (j = 0; j < nQueryValues; j++)
362  {
363  if (nullFlags[j])
364  {
365  categories[j] = GIN_CAT_NULL_KEY;
366  hasNullQuery = true;
367  }
368  }
369  }
370 
371  ginFillScanKey(so, skey->sk_attno,
372  skey->sk_strategy, searchMode,
373  skey->sk_argument, nQueryValues,
374  queryValues, categories,
375  partial_matches, extra_data);
376 
377  /* Remember if we had any non-excludeOnly keys */
378  if (searchMode != GIN_SEARCH_MODE_ALL)
379  attrHasNormalScan[skey->sk_attno - 1] = true;
380  }
381 
382  /*
383  * Processing GIN_SEARCH_MODE_ALL scan keys requires us to make a second
384  * pass over the scan keys. Above we marked each such scan key as
385  * excludeOnly. If the involved column has any normal (not excludeOnly)
386  * scan key as well, then we can leave it like that. Otherwise, one
387  * excludeOnly scan key must receive a GIN_CAT_EMPTY_QUERY hidden entry
388  * and be set to normal (excludeOnly = false).
389  */
390  for (i = 0; i < so->nkeys; i++)
391  {
392  GinScanKey key = &so->keys[i];
393 
394  if (key->searchMode != GIN_SEARCH_MODE_ALL)
395  continue;
396 
397  if (!attrHasNormalScan[key->attnum - 1])
398  {
399  key->excludeOnly = false;
401  attrHasNormalScan[key->attnum - 1] = true;
402  }
403  }
404 
405  /*
406  * If there are no regular scan keys, generate an EVERYTHING scankey to
407  * drive a full-index scan.
408  */
409  if (so->nkeys == 0 && !so->isVoidRes)
410  {
411  hasNullQuery = true;
414  (Datum) 0, 0,
415  NULL, NULL, NULL, NULL);
416  }
417 
418  /*
419  * If the index is version 0, it may be missing null and placeholder
420  * entries, which would render searches for nulls and full-index scans
421  * unreliable. Throw an error if so.
422  */
423  if (hasNullQuery && !so->isVoidRes)
424  {
425  GinStatsData ginStats;
426 
427  ginGetStats(scan->indexRelation, &ginStats);
428  if (ginStats.ginVersion < 1)
429  ereport(ERROR,
430  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
431  errmsg("old GIN indexes do not support whole-index scans nor searches for nulls"),
432  errhint("To fix this, do REINDEX INDEX \"%s\".",
434  }
435 
436  MemoryContextSwitchTo(oldCtx);
437 
439 }
#define InvalidStrategy
Definition: stratnum.h:24
#define GIN_CAT_EMPTY_QUERY
Definition: ginblock.h:213
int errhint(const char *fmt,...)
Definition: elog.c:1071
static void ginScanKeyAddHiddenEntry(GinScanOpaque so, GinScanKey key, GinNullCategory queryCategory)
Definition: ginscan.c:137
#define PointerGetDatum(X)
Definition: postgres.h:556
#define GIN_SEARCH_MODE_EVERYTHING
Definition: gin.h:37
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:610
signed int int32
Definition: c.h:355
Relation indexRelation
Definition: relscan.h:103
#define GIN_SEARCH_MODE_ALL
Definition: gin.h:36
char * Pointer
Definition: c.h:344
#define ERROR
Definition: elog.h:43
signed char GinNullCategory
Definition: ginblock.h:207
Datum FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7)
Definition: fmgr.c:1287
struct GinScanKeyData * GinScanKey
Definition: gin_private.h:261
StrategyNumber sk_strategy
Definition: skey.h:68
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:383
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:153
#define FirstOffsetNumber
Definition: off.h:27
#define RelationGetRelationName(relation)
Definition: rel.h:470
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:1361
OffsetNumber attnum
Definition: gin_private.h:304
#define SK_ISNULL
Definition: skey.h:115
#define GIN_CAT_NULL_KEY
Definition: ginblock.h:210
void * palloc0(Size size)
Definition: mcxt.c:980
struct GinScanKeyData GinScanKeyData
uintptr_t Datum
Definition: postgres.h:367
void ginGetStats(Relation index, GinStatsData *stats)
Definition: ginutil.c:629
#define GIN_SEARCH_MODE_DEFAULT
Definition: gin.h:34
#define ereport(elevel,...)
Definition: elog.h:144
#define Max(x, y)
Definition: c.h:914
int sk_flags
Definition: skey.h:66
#define INDEX_MAX_KEYS
int32 ginVersion
Definition: gin.h:49
#define DatumGetPointer(X)
Definition: postgres.h:549
struct ScanKeyData * keyData
Definition: relscan.h:107
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:824
int i
Datum sk_argument
Definition: skey.h:72
#define UInt16GetDatum(X)
Definition: postgres.h:465
AttrNumber sk_attno
Definition: skey.h:67

◆ ginoptions()

bytea* ginoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 608 of file ginutil.c.

References build_reloptions(), lengthof, offsetof, RELOPT_KIND_GIN, RELOPT_TYPE_BOOL, and RELOPT_TYPE_INT.

Referenced by ginhandler().

609 {
610  static const relopt_parse_elt tab[] = {
611  {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)},
612  {"gin_pending_list_limit", RELOPT_TYPE_INT, offsetof(GinOptions,
613  pendingListCleanupSize)}
614  };
615 
616  return (bytea *) build_reloptions(reloptions, validate,
618  sizeof(GinOptions),
619  tab, lengthof(tab));
620 }
#define lengthof(array)
Definition: c.h:668
void * build_reloptions(Datum reloptions, bool validate, relopt_kind kind, Size relopt_struct_size, const relopt_parse_elt *relopt_elems, int num_relopt_elems)
Definition: reloptions.c:1887
Definition: c.h:555
#define offsetof(type, field)
Definition: c.h:661

◆ GinPageDeletePostingItem()

void GinPageDeletePostingItem ( Page  page,
OffsetNumber  offset 
)

Definition at line 417 of file gindatapage.c.

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

Referenced by ginDeletePage(), and ginRedoDeletePage().

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

◆ ginPostingListDecode()

ItemPointer ginPostingListDecode ( GinPostingList ptr,
int *  ndecoded 
)

Definition at line 284 of file ginpostinglist.c.

References ginPostingListDecodeAllSegments(), and SizeOfGinPostingList.

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

285 {
286  return ginPostingListDecodeAllSegments(plist,
287  SizeOfGinPostingList(plist),
288  ndecoded);
289 }
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:343
ItemPointer ginPostingListDecodeAllSegments(GinPostingList *segment, int len, int *ndecoded_out)

◆ ginPostingListDecodeAllSegments()

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

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

298 {
299  ItemPointer result;
300  int nallocated;
301  uint64 val;
302  char *endseg = ((char *) segment) + len;
303  int ndecoded;
304  unsigned char *ptr;
305  unsigned char *endptr;
306 
307  /*
308  * Guess an initial size of the array.
309  */
310  nallocated = segment->nbytes * 2 + 1;
311  result = palloc(nallocated * sizeof(ItemPointerData));
312 
313  ndecoded = 0;
314  while ((char *) segment < endseg)
315  {
316  /* enlarge output array if needed */
317  if (ndecoded >= nallocated)
318  {
319  nallocated *= 2;
320  result = repalloc(result, nallocated * sizeof(ItemPointerData));
321  }
322 
323  /* copy the first item */
325  Assert(ndecoded == 0 || ginCompareItemPointers(&segment->first, &result[ndecoded - 1]) > 0);
326  result[ndecoded] = segment->first;
327  ndecoded++;
328 
329  val = itemptr_to_uint64(&segment->first);
330  ptr = segment->bytes;
331  endptr = segment->bytes + segment->nbytes;
332  while (ptr < endptr)
333  {
334  /* enlarge output array if needed */
335  if (ndecoded >= nallocated)
336  {
337  nallocated *= 2;
338  result = repalloc(result, nallocated * sizeof(ItemPointerData));
339  }
340 
341  val += decode_varbyte(&ptr);
342 
343  uint64_to_itemptr(val, &result[ndecoded]);
344  ndecoded++;
345  }
346  segment = GinNextPostingListSegment(segment);
347  }
348 
349  if (ndecoded_out)
350  *ndecoded_out = ndecoded;
351  return result;
352 }
static uint64 decode_varbyte(unsigned char **ptr)
#define GinNextPostingListSegment(cur)
Definition: ginblock.h:344
static void uint64_to_itemptr(uint64 val, ItemPointer iptr)
uint16 nbytes
Definition: ginblock.h:339
#define Assert(condition)
Definition: c.h:738
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
static uint64 itemptr_to_uint64(const ItemPointer iptr)
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
static int ginCompareItemPointers(ItemPointer a, ItemPointer b)
Definition: gin_private.h:480
void * palloc(Size size)
Definition: mcxt.c:949
#define OffsetNumberIsValid(offsetNumber)
Definition: off.h:39
long val
Definition: informix.c:664

◆ ginPostingListDecodeAllSegmentsToTbm()

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

Definition at line 358 of file ginpostinglist.c.

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

Referenced by GinDataLeafPageGetItemsToTbm().

360 {
361  int ndecoded;
362  ItemPointer items;
363 
364  items = ginPostingListDecodeAllSegments(ptr, len, &ndecoded);
365  tbm_add_tuples(tbm, items, ndecoded, false);
366  pfree(items);
367 
368  return ndecoded;
369 }
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:376
void pfree(void *pointer)
Definition: mcxt.c:1056
ItemPointer ginPostingListDecodeAllSegments(GinPostingList *segment, int len, int *ndecoded_out)

◆ ginPrepareEntryScan()

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

Definition at line 745 of file ginentrypage.c.

References attnum, GinBtreeData::beginPlaceToPage, GinBtreeData::entryAttnum, entryBeginPlaceToPage(), GinBtreeData::entryCategory, entryExecPlaceToPage(), entryFindChildPtr(), entryGetLeftMostPage(), entryIsMoveRight(), GinBtreeData::entryKey, entryLocateEntry(), entryLocateLeafEntry(), entryPrepareDownlink(), GinBtreeData::execPlaceToPage, GinBtreeData::fillRoot, GinBtreeData::findChildPage, GinBtreeData::findChildPtr, GinBtreeData::findItem, GinBtreeData::fullScan, GinBtreeData::getLeftMostChild, GIN_ROOT_BLKNO, ginEntryFillRoot(), GinBtreeData::ginstate, GinState::index, GinBtreeData::index, GinBtreeData::isBuild, GinBtreeData::isData, GinBtreeData::isMoveRight, sort-test::key, 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:167
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
Definition: gin_private.h:161
Relation index
Definition: gin_private.h:58
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:153
BlockNumber rootBlkno
Definition: gin_private.h:166
bool(* findItem)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:154
OffsetNumber entryAttnum
Definition: gin_private.h:172
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
Definition: gin_private.h:158
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
Definition: gin_private.h:159
Datum entryKey
Definition: gin_private.h:173
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:151
void ginEntryFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
Definition: ginentrypage.c:721
GinNullCategory entryCategory
Definition: gin_private.h:174
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:152
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:165
static void * entryPrepareDownlink(GinBtree btree, Buffer lbuf)
Definition: ginentrypage.c:700
int16 attnum
Definition: pg_attribute.h:79
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:160
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:157
#define GIN_ROOT_BLKNO
Definition: ginblock.h:52

◆ 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:229
#define GinGetPosting(itup)
Definition: ginblock.h:239
#define GinItupIsCompressed(itup)
Definition: ginblock.h:240
ItemPointerData * ItemPointer
Definition: itemptr.h:49
char * Pointer
Definition: c.h:344
#define ERROR
Definition: elog.h:43
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:214

◆ ginrescan()

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

Definition at line 442 of file ginscan.c.

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

Referenced by ginhandler().

444 {
445  GinScanOpaque so = (GinScanOpaque) scan->opaque;
446 
447  ginFreeScanKeys(so);
448 
449  if (scankey && scan->numberOfKeys > 0)
450  {
451  memmove(scan->keyData, scankey,
452  scan->numberOfKeys * sizeof(ScanKeyData));
453  }
454 }
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:383
struct ScanKeyData * keyData
Definition: relscan.h:107
void ginFreeScanKeys(GinScanOpaque so)
Definition: ginscan.c:233

◆ ginScanBeginPostingTree()

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

Definition at line 1930 of file gindatapage.c.

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

Referenced by scanPostingTree(), and startScanEntry().

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

◆ ginStepRight()

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

Definition at line 173 of file ginbtree.c.

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

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

174 {
175  Buffer nextbuffer;
176  Page page = BufferGetPage(buffer);
177  bool isLeaf = GinPageIsLeaf(page);
178  bool isData = GinPageIsData(page);
179  BlockNumber blkno = GinPageGetOpaque(page)->rightlink;
180 
181  nextbuffer = ReadBuffer(index, blkno);
182  LockBuffer(nextbuffer, lockmode);
183  UnlockReleaseBuffer(buffer);
184 
185  /* Sanity check that the page we stepped to is of similar kind. */
186  page = BufferGetPage(nextbuffer);
187  if (isLeaf != GinPageIsLeaf(page) || isData != GinPageIsData(page))
188  elog(ERROR, "right sibling of GIN page is of different type");
189 
190  return nextbuffer;
191 }
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3346
#define ERROR
Definition: elog.h:43
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
#define BufferGetPage(buffer)
Definition: bufmgr.h:157
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3560
#define GinPageIsData(page)
Definition: ginblock.h:115
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:544
#define elog(elevel,...)
Definition: elog.h:214
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ ginTraverseLock()

int ginTraverseLock ( Buffer  buffer,
bool  searchMode 
)

Definition at line 36 of file ginbtree.c.

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

Referenced by ginCompareItemPointers(), and ginFindLeafPage().

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

◆ gintuple_get_attrnum()

OffsetNumber gintuple_get_attrnum ( GinState ginstate,
IndexTuple  tuple 
)

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

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

◆ gintuple_get_key()

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

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

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

◆ ginvacuumcleanup()

IndexBulkDeleteResult* ginvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)

Definition at line 687 of file ginvacuum.c.

References IndexVacuumInfo::analyze_only, Assert, DataPageDeleteStack::blkno, BufferGetPage, IndexVacuumInfo::estimated_count, IndexBulkDeleteResult::estimated_count, ExclusiveLock, GIN_ROOT_BLKNO, GIN_SHARE, ginInsertCleanup(), GinPageIsData, GinPageIsLeaf, GinPageIsList, GinPageIsRecyclable, 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, IndexBulkDeleteResult::pages_free, palloc0(), RBM_NORMAL, ReadBufferExtended(), RecordFreeIndexPage(), RELATION_IS_LOCAL, RelationGetNumberOfBlocks, IndexVacuumInfo::strategy, UnlockRelationForExtension(), UnlockReleaseBuffer(), and vacuum_delay_point().

Referenced by ginhandler().

688 {
689  Relation index = info->index;
690  bool needLock;
691  BlockNumber npages,
692  blkno;
693  BlockNumber totFreePages;
694  GinState ginstate;
695  GinStatsData idxStat;
696 
697  /*
698  * In an autovacuum analyze, we want to clean up pending insertions.
699  * Otherwise, an ANALYZE-only call is a no-op.
700  */
701  if (info->analyze_only)
702  {
704  {
705  initGinState(&ginstate, index);
706  ginInsertCleanup(&ginstate, false, true, true, stats);
707  }
708  return stats;
709  }
710 
711  /*
712  * Set up all-zero stats and cleanup pending inserts if ginbulkdelete
713  * wasn't called
714  */
715  if (stats == NULL)
716  {
718  initGinState(&ginstate, index);
720  false, true, stats);
721  }
722 
723  memset(&idxStat, 0, sizeof(idxStat));
724 
725  /*
726  * XXX we always report the heap tuple count as the number of index
727  * entries. This is bogus if the index is partial, but it's real hard to
728  * tell how many distinct heap entries are referenced by a GIN index.
729  */
730  stats->num_index_tuples = info->num_heap_tuples;
731  stats->estimated_count = info->estimated_count;
732 
733  /*
734  * Need lock unless it's local to this backend.
735  */
736  needLock = !RELATION_IS_LOCAL(index);
737 
738  if (needLock)
740  npages = RelationGetNumberOfBlocks(index);
741  if (needLock)
743 
744  totFreePages = 0;
745 
746  for (blkno = GIN_ROOT_BLKNO; blkno < npages; blkno++)
747  {
748  Buffer buffer;
749  Page page;
750 
752 
753  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
754  RBM_NORMAL, info->strategy);
755  LockBuffer(buffer, GIN_SHARE);
756  page = (Page) BufferGetPage(buffer);
757 
758  if (GinPageIsRecyclable(page))
759  {
760  Assert(blkno != GIN_ROOT_BLKNO);
761  RecordFreeIndexPage(index, blkno);
762  totFreePages++;
763  }
764  else if (GinPageIsData(page))
765  {
766  idxStat.nDataPages++;
767  }
768  else if (!GinPageIsList(page))
769  {
770  idxStat.nEntryPages++;
771 
772  if (GinPageIsLeaf(page))
773  idxStat.nEntries += PageGetMaxOffsetNumber(page);
774  }
775 
776  UnlockReleaseBuffer(buffer);
777  }
778 
779  /* Update the metapage with accurate page and entry counts */
780  idxStat.nTotalPages = npages;
781  ginUpdateStats(info->index, &idxStat, false);
782 
783  /* Finally, vacuum the FSM */
785 
786  stats->pages_free = totFreePages;
787 
788  if (needLock)
790  stats->num_pages = RelationGetNumberOfBlocks(index);
791  if (needLock)
793 
794  return stats;
795 }
BlockNumber nEntryPages
Definition: gin.h:46
#define GinPageIsRecyclable(page)
Definition: ginblock.h:137
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:556
bool analyze_only
Definition: genam.h:47
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:590
BufferAccessStrategy strategy
Definition: genam.h:52
Relation index
Definition: genam.h:46
int64 nEntries
Definition: gin.h:48
uint32 BlockNumber
Definition: block.h:31
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
Definition: type.h:89
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3346
BlockNumber num_pages
Definition: genam.h:74
BlockNumber pages_free
Definition: genam.h:80
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:94
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
#define BufferGetPage(buffer)
Definition: bufmgr.h:157
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3302
#define GIN_SHARE
Definition: gin_private.h:49
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:402
void * palloc0(Size size)
Definition: mcxt.c:980
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:452
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3560
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:195
BlockNumber nDataPages
Definition: gin.h:47
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition: ginfast.c:780
#define GinPageIsData(page)
Definition: ginblock.h:115
double num_heap_tuples
Definition: genam.h:51
#define Assert(condition)
Definition: c.h:738
void IndexFreeSpaceMapVacuum(Relation rel)
Definition: indexfsm.c:71
#define GinPageIsList(page)
Definition: ginblock.h:117
BlockNumber nTotalPages
Definition: gin.h:45
void ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
Definition: ginutil.c:656
void vacuum_delay_point(void)
Definition: vacuum.c:1997
void RecordFreeIndexPage(Relation rel, BlockNumber freeBlock)
Definition: indexfsm.c:52
double num_index_tuples
Definition: genam.h:77
int Buffer
Definition: buf.h:23
bool estimated_count
Definition: genam.h:76
#define GIN_ROOT_BLKNO
Definition: ginblock.h:52
Pointer Page
Definition: bufpage.h:78
bool estimated_count
Definition: genam.h:49

◆ ginVacuumItemPointers()

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

Definition at line 48 of file ginvacuum.c.

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

Referenced by ginVacuumEntryPage(), and ginVacuumPostingTreeLeaf().

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

◆ ginVacuumPostingTreeLeaf()

void ginVacuumPostingTreeLeaf ( Relation  rel,
Buffer  buf,
GinVacuumState gvs 
)

Definition at line 735 of file gindatapage.c.

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

Referenced by ginVacuumPostingTreeLeaves().

736 {
737  Page page = BufferGetPage(buffer);
738  disassembledLeaf *leaf;
739  bool removedsomething = false;
740  dlist_iter iter;
741 
742  leaf = disassembleLeaf(page);
743 
744  /* Vacuum each segment. */
745  dlist_foreach(iter, &leaf->segments)
746  {
747  leafSegmentInfo *seginfo = dlist_container(leafSegmentInfo, node, iter.cur);
748  int oldsegsize;
749  ItemPointer cleaned;
750  int ncleaned;
751 
752  if (!seginfo->items)
753  seginfo->items = ginPostingListDecode(seginfo->seg,
754  &seginfo->nitems);
755  if (seginfo->seg)
756  oldsegsize = SizeOfGinPostingList(seginfo->seg);
757  else
758  oldsegsize = GinDataPageMaxDataSize;
759 
760  cleaned = ginVacuumItemPointers(gvs,
761  seginfo->items,
762  seginfo->nitems,
763  &ncleaned);
764  pfree(seginfo->items);
765  seginfo->items = NULL;
766  seginfo->nitems = 0;
767  if (cleaned)
768  {
769  if (ncleaned > 0)
770  {
771  int npacked;
772 
773  seginfo->seg = ginCompressPostingList(cleaned,
774  ncleaned,
775  oldsegsize,
776  &npacked);
777  /* Removing an item never increases the size of the segment */
778  if (npacked != ncleaned)
779  elog(ERROR, "could not fit vacuumed posting list");
780  seginfo->action = GIN_SEGMENT_REPLACE;
781  }
782  else
783  {
784  seginfo->seg = NULL;
785  seginfo->items = NULL;
786  seginfo->action = GIN_SEGMENT_DELETE;
787  }
788  seginfo->nitems = ncleaned;
789 
790  removedsomething = true;
791  }
792  }
793 
794  /*
795  * If we removed any items, reconstruct the page from the pieces.
796  *
797  * We don't try to re-encode the segments here, even though some of them
798  * might be really small now that we've removed some items from them. It
799  * seems like a waste of effort, as there isn't really any benefit from
800  * larger segments per se; larger segments only help to pack more items in
801  * the same space. We might as well delay doing that until the next
802  * insertion, which will need to re-encode at least part of the page
803  * anyway.
804  *
805  * Also note if the page was in uncompressed, pre-9.4 format before, it is
806  * now represented as one huge segment that contains all the items. It
807  * might make sense to split that, to speed up random access, but we don't
808  * bother. You'll have to REINDEX anyway if you want the full gain of the
809  * new tighter index format.
810  */
811  if (removedsomething)
812  {
813  bool modified;
814 
815  /*
816  * Make sure we have a palloc'd copy of all segments, after the first
817  * segment that is modified. (dataPlaceToPageLeafRecompress requires
818  * this).
819  */
820  modified = false;
821  dlist_foreach(iter, &leaf->segments)
822  {
824  iter.cur);
825 
826  if (seginfo->action