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, bool indexUnchanged, 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 indexrel, Buffer buffer, GinVacuumState *gvs)
 
IndexScanDesc ginbeginscan (Relation rel, int nkeys, int norderbys)
 
void ginendscan (IndexScanDesc scan)
 
void ginrescan (IndexScanDesc scan, ScanKey scankey, 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 ginadjustmembers (Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
 
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 len, TIDBitmap *tbm)
 
ItemPointer ginPostingListDecodeAllSegments (GinPostingList *segment, int len, int *ndecoded_out)
 
ItemPointer ginPostingListDecode (GinPostingList *plist, int *ndecoded_out)
 
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

#define GIN_EXCLUSIVE   BUFFER_LOCK_EXCLUSIVE

Definition at line 50 of file gin_private.h.

◆ GIN_SHARE

#define GIN_SHARE   BUFFER_LOCK_SHARE

Definition at line 49 of file gin_private.h.

◆ GIN_UNLOCK

#define GIN_UNLOCK   BUFFER_LOCK_UNLOCK

Definition at line 48 of file gin_private.h.

◆ 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:843
int gin_pending_list_limit
Definition: ginfast.c:39

Definition at line 38 of file gin_private.h.

◆ 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 GIN_DEFAULT_USE_FASTUPDATE
Definition: gin_private.h:32

Definition at line 33 of file gin_private.h.

Typedef Documentation

◆ GinBtree

typedef struct GinBtreeData* GinBtree

Definition at line 139 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 265 of file gin_private.h.

◆ GinScanEntryData

◆ GinScanKey

typedef struct GinScanKeyData* GinScanKey

Definition at line 263 of file gin_private.h.

◆ GinScanKeyData

◆ GinScanOpaque

Definition at line 385 of file gin_private.h.

◆ GinScanOpaqueData

◆ GinState

typedef struct GinState GinState

◆ GinTupleCollector

◆ GinVacuumState

Definition at line 234 of file gin_private.h.

Enumeration Type Documentation

◆ GinPlaceToPageRC

Enumerator
GPTP_NO_WORK 
GPTP_INSERT 
GPTP_SPLIT 

Definition at line 142 of file gin_private.h.

143 {
144  GPTP_NO_WORK,
145  GPTP_INSERT,
146  GPTP_SPLIT
GinPlaceToPageRC
Definition: gin_private.h:143
@ GPTP_INSERT
Definition: gin_private.h:145
@ GPTP_SPLIT
Definition: gin_private.h:146
@ GPTP_NO_WORK
Definition: gin_private.h:144

Function Documentation

◆ createPostingTree()

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

Definition at line 1769 of file gindatapage.c.

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  {
1867  items + nrootitems,
1868  nitems - nrootitems,
1869  buildStats);
1870  }
1871 
1872  return blkno;
1873 }
uint32 BlockNumber
Definition: block.h:31
#define InvalidBlockNumber
Definition: block.h:33
int Buffer
Definition: buf.h:23
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2791
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4008
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1621
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:284
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:424
Pointer Page
Definition: bufpage.h:78
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:388
char * Pointer
Definition: c.h:467
#define DEBUG2
Definition: elog.h:29
#define GIN_DATA
Definition: ginblock.h:41
#define GIN_COMPRESSED
Definition: ginblock.h:48
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:342
#define GIN_LEAF
Definition: ginblock.h:42
#define GinDataPageSetDataSize(page, size)
Definition: ginblock.h:309
#define GinDataPageMaxDataSize
Definition: ginblock.h:319
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:278
#define GinPostingListSegmentMaxSize
Definition: gindatapage.c:34
void ginInsertItemPointers(Relation index, BlockNumber rootBlkno, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gindatapage.c:1902
GinPostingList * ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:345
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:299
#define XLOG_GIN_CREATE_PTREE
Definition: ginxlog.h:19
#define nitems(x)
Definition: indent.h:31
void pfree(void *pointer)
Definition: mcxt.c:1436
void * palloc(Size size)
Definition: mcxt.c:1210
#define START_CRIT_SECTION()
Definition: miscadmin.h:148
#define END_CRIT_SECTION()
Definition: miscadmin.h:150
const void * data
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3078
#define RelationNeedsWAL(relation)
Definition: rel.h:628
BlockNumber nDataPages
Definition: gin.h:47
Definition: type.h:95
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:351
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:451
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:243
void XLogBeginInsert(void)
Definition: xloginsert.c:150
#define REGBUF_WILL_INIT
Definition: xloginsert.h:33

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

Referenced by addItemPointersToLeafTuple(), and buildFreshLeafTuple().

◆ freeGinBtreeStack()

void freeGinBtreeStack ( GinBtreeStack stack)

Definition at line 194 of file ginbtree.c.

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:3985
struct GinBtreeStack * parent
Definition: gin_private.h:136

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

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

◆ ginadjustmembers()

void ginadjustmembers ( Oid  opfamilyoid,
Oid  opclassoid,
List operators,
List functions 
)

Definition at line 279 of file ginvalidate.c.

283 {
284  ListCell *lc;
285 
286  /*
287  * Operator members of a GIN opfamily should never have hard dependencies,
288  * since their connection to the opfamily depends only on what the support
289  * functions think, and that can be altered. For consistency, we make all
290  * soft dependencies point to the opfamily, though a soft dependency on
291  * the opclass would work as well in the CREATE OPERATOR CLASS case.
292  */
293  foreach(lc, operators)
294  {
295  OpFamilyMember *op = (OpFamilyMember *) lfirst(lc);
296 
297  op->ref_is_hard = false;
298  op->ref_is_family = true;
299  op->refobjid = opfamilyoid;
300  }
301 
302  /*
303  * Required support functions should have hard dependencies. Preferably
304  * those are just dependencies on the opclass, but if we're in ALTER
305  * OPERATOR FAMILY, we leave the dependency pointing at the whole
306  * opfamily. (Given that GIN opclasses generally don't share opfamilies,
307  * it seems unlikely to be worth working harder.)
308  */
309  foreach(lc, functions)
310  {
311  OpFamilyMember *op = (OpFamilyMember *) lfirst(lc);
312 
313  switch (op->number)
314  {
317  /* Required support function */
318  op->ref_is_hard = true;
319  break;
320  case GIN_COMPARE_PROC:
321  case GIN_CONSISTENT_PROC:
324  case GIN_OPTIONS_PROC:
325  /* Optional, so force it to be a soft family dependency */
326  op->ref_is_hard = false;
327  op->ref_is_family = true;
328  op->refobjid = opfamilyoid;
329  break;
330  default:
331  ereport(ERROR,
332  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
333  errmsg("support function number %d is invalid for access method %s",
334  op->number, "gin")));
335  break;
336  }
337  }
338 }
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define GIN_COMPARE_PROC
Definition: gin.h:22
#define GIN_CONSISTENT_PROC
Definition: gin.h:25
#define GIN_EXTRACTQUERY_PROC
Definition: gin.h:24
#define GIN_EXTRACTVALUE_PROC
Definition: gin.h:23
#define GIN_TRICONSISTENT_PROC
Definition: gin.h:27
#define GIN_COMPARE_PARTIAL_PROC
Definition: gin.h:26
#define GIN_OPTIONS_PROC
Definition: gin.h:28
#define lfirst(lc)
Definition: pg_list.h:172
static const struct fns functions
Definition: regcomp.c:357
Oid refobjid
Definition: amapi.h:90
bool ref_is_family
Definition: amapi.h:89
int number
Definition: amapi.h:84
bool ref_is_hard
Definition: amapi.h:88

References ereport, errcode(), errmsg(), ERROR, functions, GIN_COMPARE_PARTIAL_PROC, GIN_COMPARE_PROC, GIN_CONSISTENT_PROC, GIN_EXTRACTQUERY_PROC, GIN_EXTRACTVALUE_PROC, GIN_OPTIONS_PROC, GIN_TRICONSISTENT_PROC, lfirst, OpFamilyMember::number, OpFamilyMember::ref_is_family, OpFamilyMember::ref_is_hard, and OpFamilyMember::refobjid.

Referenced by ginhandler().

◆ ginBeginBAScan()

void ginBeginBAScan ( BuildAccumulator accum)

Definition at line 257 of file ginbulk.c.

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:802
@ LeftRightWalk
Definition: rbtree.h:37
RBTreeIterator tree_walk
Definition: gin_private.h:437

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

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

◆ ginbeginscan()

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

Definition at line 25 of file ginscan.c.

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 }
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:81
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:385
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:96
Assert(fmt[strlen(fmt) - 1] !='\n')
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
GinScanKey keys
Definition: gin_private.h:373
MemoryContext keyCtx
Definition: gin_private.h:380
MemoryContext tempCtx
Definition: gin_private.h:370
Relation indexRelation
Definition: relscan.h:118

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

◆ ginbuild()

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

Definition at line 320 of file gininsert.c.

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 
335  elog(ERROR, "index \"%s\" already contains data",
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  {
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 }
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:161
unsigned int uint32
Definition: c.h:490
signed char GinNullCategory
Definition: ginblock.h:206
void ginBeginBAScan(BuildAccumulator *accum)
Definition: ginbulk.c:257
void ginInitBA(BuildAccumulator *accum)
Definition: ginbulk.c:109
ItemPointerData * ginGetBAEntry(BuildAccumulator *accum, OffsetNumber *attnum, Datum *key, GinNullCategory *category, uint32 *n)
Definition: ginbulk.c:268
void ginEntryInsert(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gininsert.c:179
static void ginBuildCallback(Relation index, ItemPointer tid, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition: gininsert.c:280
void GinInitBuffer(Buffer b, uint32 f)
Definition: ginutil.c:357
void GinInitMetabuffer(Buffer b)
Definition: ginutil.c:363
void ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
Definition: ginutil.c:657
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:387
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
uint16 OffsetNumber
Definition: off.h:24
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
int16 attnum
Definition: pg_attribute.h:74
uintptr_t Datum
Definition: postgres.h:64
#define RelationGetRelationName(relation)
Definition: rel.h:537
@ MAIN_FORKNUM
Definition: relpath.h:50
GinState * ginstate
Definition: gin_private.h:432
double indtuples
Definition: gininsert.c:33
GinState ginstate
Definition: gininsert.c:32
MemoryContext tmpCtx
Definition: gininsert.c:35
GinStatsData buildStats
Definition: gininsert.c:34
MemoryContext funcCtx
Definition: gininsert.c:36
BuildAccumulator accum
Definition: gininsert.c:37
BlockNumber nEntryPages
Definition: gin.h:46
BlockNumber nTotalPages
Definition: gin.h:45
double heap_tuples
Definition: genam.h:32
double index_tuples
Definition: genam.h:33
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:1782
void log_newpage_range(Relation rel, ForkNumber forknum, BlockNumber startblk, BlockNumber endblk, bool page_std)
Definition: xloginsert.c:1224

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, GinStatsData::nTotalPages, palloc(), RelationGetNumberOfBlocks, RelationGetRelationName, RelationNeedsWAL, START_CRIT_SECTION, table_index_build_scan(), GinBuildState::tmpCtx, and UnlockReleaseBuffer().

Referenced by ginhandler().

◆ ginbuildempty()

void ginbuildempty ( Relation  index)

Definition at line 437 of file gininsert.c.

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 LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4226
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:751
#define P_NEW
Definition: bufmgr.h:105
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:112
@ RBM_NORMAL
Definition: bufmgr.h:44
@ INIT_FORKNUM
Definition: relpath.h:53
XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std)
Definition: xloginsert.c:1191

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

◆ ginbulkdelete()

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

Definition at line 565 of file ginvacuum.c.

567 {
568  Relation index = info->index;
569  BlockNumber blkno = GIN_ROOT_BLKNO;
570  GinVacuumState gvs;
571  Buffer buffer;
572  BlockNumber rootOfPostingTree[BLCKSZ / (sizeof(IndexTupleData) + sizeof(ItemId))];
573  uint32 nRoot;
574 
576  "Gin vacuum temporary context",
578  gvs.index = index;
579  gvs.callback = callback;
580  gvs.callback_state = callback_state;
581  gvs.strategy = info->strategy;
582  initGinState(&gvs.ginstate, index);
583 
584  /* first time through? */
585  if (stats == NULL)
586  {
587  /* Yes, so initialize stats to zeroes */
589 
590  /*
591  * and cleanup any pending inserts
592  */
594  false, true, stats);
595  }
596 
597  /* we'll re-count the tuples each time */
598  stats->num_index_tuples = 0;
599  gvs.result = stats;
600 
601  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
602  RBM_NORMAL, info->strategy);
603 
604  /* find leaf page */
605  for (;;)
606  {
607  Page page = BufferGetPage(buffer);
608  IndexTuple itup;
609 
610  LockBuffer(buffer, GIN_SHARE);
611 
612  Assert(!GinPageIsData(page));
613 
614  if (GinPageIsLeaf(page))
615  {
616  LockBuffer(buffer, GIN_UNLOCK);
617  LockBuffer(buffer, GIN_EXCLUSIVE);
618 
619  if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page))
620  {
621  LockBuffer(buffer, GIN_UNLOCK);
622  continue; /* check it one more */
623  }
624  break;
625  }
626 
628 
629  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber));
630  blkno = GinGetDownlink(itup);
631  Assert(blkno != InvalidBlockNumber);
632 
633  UnlockReleaseBuffer(buffer);
634  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
635  RBM_NORMAL, info->strategy);
636  }
637 
638  /* right now we found leftmost page in entry's BTree */
639 
640  for (;;)
641  {
642  Page page = BufferGetPage(buffer);
643  Page resPage;
644  uint32 i;
645 
646  Assert(!GinPageIsData(page));
647 
648  resPage = ginVacuumEntryPage(&gvs, buffer, rootOfPostingTree, &nRoot);
649 
650  blkno = GinPageGetOpaque(page)->rightlink;
651 
652  if (resPage)
653  {
655  PageRestoreTempPage(resPage, page);
656  MarkBufferDirty(buffer);
657  xlogVacuumPage(gvs.index, buffer);
658  UnlockReleaseBuffer(buffer);
660  }
661  else
662  {
663  UnlockReleaseBuffer(buffer);
664  }
665 
667 
668  for (i = 0; i < nRoot; i++)
669  {
670  ginVacuumPostingTree(&gvs, rootOfPostingTree[i]);
672  }
673 
674  if (blkno == InvalidBlockNumber) /* rightmost page */
675  break;
676 
677  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
678  RBM_NORMAL, info->strategy);
679  LockBuffer(buffer, GIN_EXCLUSIVE);
680  }
681 
683 
684  return gvs.result;
685 }
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3324
static Item PageGetItem(Page page, ItemId itemId)
Definition: bufpage.h:351
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:240
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:369
#define GIN_UNLOCK
Definition: gin_private.h:48
#define GIN_EXCLUSIVE
Definition: gin_private.h:50
#define GIN_SHARE
Definition: gin_private.h:49
#define GIN_ROOT_BLKNO
Definition: ginblock.h:52
#define GinGetDownlink(itup)
Definition: ginblock.h:257
#define GinPageIsData(page)
Definition: ginblock.h:115
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition: ginfast.c:774
static void xlogVacuumPage(Relation index, Buffer buffer)
Definition: ginvacuum.c:90
static void ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
Definition: ginvacuum.c:409
static Page ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
Definition: ginvacuum.c:456
int i
Definition: isn.c:73
IndexTupleData * IndexTuple
Definition: itup.h:53
struct IndexTupleData IndexTupleData
void * palloc0(Size size)
Definition: mcxt.c:1241
#define FirstOffsetNumber
Definition: off.h:27
MemoryContext tmpCxt
Definition: ginvacuum.c:36
BufferAccessStrategy strategy
Definition: ginvacuum.c:35
IndexBulkDeleteCallback callback
Definition: ginvacuum.c:32
IndexBulkDeleteResult * result
Definition: ginvacuum.c:31
void * callback_state
Definition: ginvacuum.c:33
GinState ginstate
Definition: ginvacuum.c:34
Relation index
Definition: ginvacuum.c:30
double num_index_tuples
Definition: genam.h:78
Relation index
Definition: genam.h:46
BufferAccessStrategy strategy
Definition: genam.h:52
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:46
void vacuum_delay_point(void)
Definition: vacuum.c:2211

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

◆ ginCompareAttEntries()

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

Definition at line 417 of file ginutil.c.

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

References a, b, and ginCompareEntries().

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

◆ ginCompareEntries()

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

Definition at line 395 of file ginutil.c.

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

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

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

◆ ginCompareItemPointers()

static int ginCompareItemPointers ( ItemPointer  a,
ItemPointer  b 
)
inlinestatic

Definition at line 487 of file gin_private.h.

488 {
489  uint64 ia = (uint64) GinItemPointerGetBlockNumber(a) << 32 | GinItemPointerGetOffsetNumber(a);
490  uint64 ib = (uint64) GinItemPointerGetBlockNumber(b) << 32 | GinItemPointerGetOffsetNumber(b);
491 
492  if (ia == ib)
493  return 0;
494  else if (ia > ib)
495  return 1;
496  else
497  return -1;
498 }
#define GinItemPointerGetOffsetNumber(pointer)
Definition: ginblock.h:146
#define GinItemPointerGetBlockNumber(pointer)
Definition: ginblock.h:143

References a, b, GinItemPointerGetBlockNumber, and GinItemPointerGetOffsetNumber.

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

◆ ginCompressPostingList()

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

Definition at line 197 of file ginpostinglist.c.

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 }
#define SHORTALIGN_DOWN(LEN)
Definition: c.h:803
#define SHORTALIGN(LEN)
Definition: c.h:791
static uint64 itemptr_to_uint64(const ItemPointer iptr)
static void encode_varbyte(uint64 val, unsigned char **ptr)
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded_out)
#define MaxBytesPerInteger
long val
Definition: informix.c:664
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
static char * buf
Definition: pg_test_fsync.c:67
ItemPointerData first
Definition: ginblock.h:337
unsigned char bytes[FLEXIBLE_ARRAY_MEMBER]
Definition: ginblock.h:339
uint16 nbytes
Definition: ginblock.h:338

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

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

◆ ginDataFillRoot()

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

Definition at line 1343 of file gindatapage.c.

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 GinDataPageGetRightBound(page)
Definition: ginblock.h:288
#define PostingItemSetBlockNumber(pointer, blockNumber)
Definition: ginblock.h:192
void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset)
Definition: gindatapage.c:380
#define InvalidOffsetNumber
Definition: off.h:26
ItemPointerData key
Definition: ginblock.h:186

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

Referenced by ginPrepareDataScan().

◆ GinDataLeafPageGetItems()

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

Definition at line 135 of file gindatapage.c.

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

References dataLeafPageGetUncompressed(), ginCompareItemPointers(), GinDataLeafPageGetPostingList, GinDataLeafPageGetPostingListSize, GinNextPostingListSegment, GinPageIsCompressed, ginPostingListDecodeAllSegments(), ItemPointerIsValid(), len, next, nitems, and palloc().

Referenced by entryLoadMoreItems(), and startScanEntry().

◆ GinDataLeafPageGetItemsToTbm()

int GinDataLeafPageGetItemsToTbm ( Page  page,
TIDBitmap tbm 
)

Definition at line 182 of file gindatapage.c.

183 {
184  ItemPointer uncompressed;
185  int nitems;
186 
187  if (GinPageIsCompressed(page))
188  {
191 
193  }
194  else
195  {
196  uncompressed = dataLeafPageGetUncompressed(page, &nitems);
197 
198  if (nitems > 0)
199  tbm_add_tuples(tbm, uncompressed, nitems, false);
200  }
201 
202  return nitems;
203 }
int ginPostingListDecodeAllSegmentsToTbm(GinPostingList *ptr, int len, TIDBitmap *tbm)
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:376

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

Referenced by scanPostingTree().

◆ GinDataPageAddPostingItem()

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

Definition at line 380 of file gindatapage.c.

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

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

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

◆ ginendscan()

void ginendscan ( IndexScanDesc  scan)

Definition at line 458 of file ginscan.c.

459 {
460  GinScanOpaque so = (GinScanOpaque) scan->opaque;
461 
462  ginFreeScanKeys(so);
463 
466 
467  pfree(so);
468 }
void ginFreeScanKeys(GinScanOpaque so)
Definition: ginscan.c:233

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

Referenced by ginhandler().

◆ ginEntryFillRoot()

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

Definition at line 721 of file ginentrypage.c.

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 }
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:468
static IndexTuple getRightMostTuple(Page page)
Definition: ginentrypage.c:236
static IndexTuple GinFormInteriorTuple(IndexTuple itup, Page page, BlockNumber childblk)
Definition: ginentrypage.c:202
Pointer Item
Definition: item.h:17
#define IndexTupleSize(itup)
Definition: itup.h:70

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

Referenced by ginPrepareEntryScan().

◆ 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.

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 GinIsPostingTree(itup)
Definition: ginblock.h:231
#define GinGetPostingTree(itup)
Definition: ginblock.h:233
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:194
void ginInsertValue(GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
Definition: ginbtree.c:775
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, bool rootConflictCheck, Snapshot snapshot)
Definition: ginbtree.c:80
void ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum, Datum key, GinNullCategory category, GinState *ginstate)
Definition: ginentrypage.c:745
static IndexTuple addItemPointersToLeafTuple(GinState *ginstate, IndexTuple old, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats, Buffer buffer)
Definition: gininsert.c:49
static IndexTuple buildFreshLeafTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats, Buffer buffer)
Definition: gininsert.c:129
void CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno)
Definition: predicate.c:4270
bool(* findItem)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:155
OffsetNumber off
Definition: gin_private.h:132
Relation index
Definition: gin_private.h:58
int64 nEntries
Definition: gin.h:48

References addItemPointersToLeafTuple(), attnum, 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, sort-test::key, LockBuffer(), GinStatsData::nEntries, GinBtreeStack::off, PageGetItem(), PageGetItemId(), and pfree().

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

◆ ginExtractEntries()

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

Definition at line 490 of file ginutil.c.

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

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

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

◆ ginFindLeafPage()

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

Definition at line 80 of file ginbtree.c.

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 }
Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, BlockNumber blockNum)
Definition: bufmgr.c:1684
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:704
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:307
#define GinPageIsIncompleteSplit(page)
Definition: ginblock.h:127
int ginTraverseLock(Buffer buffer, bool searchMode)
Definition: ginbtree.c:36
static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack, GinStatsData *buildStats)
Definition: ginbtree.c:666
Buffer ginStepRight(Buffer buffer, Relation index, int lockmode)
Definition: ginbtree.c:173
short access
Definition: preproc-type.c:36
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:152
bool(* isMoveRight)(GinBtree, Page)
Definition: gin_private.h:154
Relation index
Definition: gin_private.h:166
BlockNumber rootBlkno
Definition: gin_private.h:167
uint32 predictNumber
Definition: gin_private.h:135
BlockNumber blkno
Definition: gin_private.h:130

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

◆ 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.

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 MAXALIGN(LEN)
Definition: c.h:795
#define Max(x, y)
Definition: c.h:982
#define GinCategoryOffset(itup, ginstate)
Definition: ginblock.h:217
#define GinGetPosting(itup)
Definition: ginblock.h:238
#define GinSetNPosting(itup, n)
Definition: ginblock.h:229
#define GinSetPostingOffset(itup, n)
Definition: ginblock.h:237
#define GinSetNullCategory(itup, ginstate, c)
Definition: ginblock.h:222
#define GinMaxItemSize
Definition: ginblock.h:248
IndexTuple index_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: indextuple.c:44
#define IndexTupleHasNulls(itup)
Definition: itup.h:71
#define INDEX_SIZE_MASK
Definition: itup.h:65
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1456
static Datum UInt16GetDatum(uint16 X)
Definition: postgres.h:192
bool oneCol
Definition: gin_private.h:59
TupleDesc tupdesc[INDEX_MAX_KEYS]
Definition: gin_private.h:73
unsigned short t_info
Definition: itup.h:49

References Assert(), attnum, data, 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().

◆ ginFreeScanKeys()

void ginFreeScanKeys ( GinScanOpaque  so)

Definition at line 233 of file ginscan.c.

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 }
#define MemoryContextResetAndDeleteChildren(ctx)
Definition: memutils.h:70
TIDBitmap * matchBitmap
Definition: gin_private.h:353
ItemPointerData * list
Definition: gin_private.h:358
TBMIterator * matchIterator
Definition: gin_private.h:354
GinScanEntry * entries
Definition: gin_private.h:376
void tbm_free(TIDBitmap *tbm)
Definition: tidbitmap.c:321
void tbm_end_iterate(TBMIterator *iterator)
Definition: tidbitmap.c:1145

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

◆ ginGetBAEntry()

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

Definition at line 268 of file ginbulk.c.

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 }
static int qsortCompareItemPointers(const void *a, const void *b)
Definition: ginbulk.c:246
#define qsort(a, b, c, d)
Definition: port.h:445
RBTNode * rbt_iterate(RBTreeIterator *iter)
Definition: rbtree.c:826
OffsetNumber attnum
Definition: gin_private.h:423
ItemPointerData * list
Definition: gin_private.h:425
GinNullCategory category
Definition: gin_private.h:422

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

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

◆ gingetbitmap()

int64 gingetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

Definition at line 1918 of file ginget.c.

1919 {
1920  GinScanOpaque so = (GinScanOpaque) scan->opaque;
1921  int64 ntids;
1922  ItemPointerData iptr;
1923  bool recheck;
1924 
1925  /*
1926  * Set up the scan keys, and check for unsatisfiable query.
1927  */
1928  ginFreeScanKeys(so); /* there should be no keys yet, but just to be
1929  * sure */
1930  ginNewScanKey(scan);
1931 
1932  if (GinIsVoidRes(scan))
1933  return 0;
1934 
1935  ntids = 0;
1936 
1937  /*
1938  * First, scan the pending list and collect any matching entries into the
1939  * bitmap. After we scan a pending item, some other backend could post it
1940  * into the main index, and so we might visit it a second time during the
1941  * main scan. This is okay because we'll just re-set the same bit in the
1942  * bitmap. (The possibility of duplicate visits is a major reason why GIN
1943  * can't support the amgettuple API, however.) Note that it would not do
1944  * to scan the main index before the pending list, since concurrent
1945  * cleanup could then make us miss entries entirely.
1946  */
1947  scanPendingInsert(scan, tbm, &ntids);
1948 
1949  /*
1950  * Now scan the main index.
1951  */
1952  startScan(scan);
1953 
1954  ItemPointerSetMin(&iptr);
1955 
1956  for (;;)
1957  {
1959 
1960  if (!scanGetItem(scan, iptr, &iptr, &recheck))
1961  break;
1962 
1963  if (ItemPointerIsLossyPage(&iptr))
1965  else
1966  tbm_add_tuples(tbm, &iptr, 1, recheck);
1967  ntids++;
1968  }
1969 
1970  return ntids;
1971 }
#define ItemPointerIsLossyPage(p)
Definition: ginblock.h:175
#define ItemPointerSetMin(p)
Definition: ginblock.h:166
static void scanPendingInsert(IndexScanDesc scan, TIDBitmap *tbm, int64 *ntids)
Definition: ginget.c:1823
static void startScan(IndexScanDesc scan)
Definition: ginget.c:601
#define GinIsVoidRes(s)
Definition: ginget.c:1915
static bool scanGetItem(IndexScanDesc scan, ItemPointerData advancePast, ItemPointerData *item, bool *recheck)
Definition: ginget.c:1285
void ginNewScanKey(IndexScanDesc scan)
Definition: ginscan.c:263
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition: itemptr.h:103
void tbm_add_page(TIDBitmap *tbm, BlockNumber pageno)
Definition: tidbitmap.c:442

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

◆ ginHeapTupleFastCollect()

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

Definition at line 477 of file ginfast.c.

481 {
482  Datum *entries;
483  GinNullCategory *categories;
484  int32 i,
485  nentries;
486 
487  /*
488  * Extract the key values that need to be inserted in the index
489  */
490  entries = ginExtractEntries(ginstate, attnum, value, isNull,
491  &nentries, &categories);
492 
493  /*
494  * Protect against integer overflow in allocation calculations
495  */
496  if (nentries < 0 ||
497  collector->ntuples + nentries > MaxAllocSize / sizeof(IndexTuple))
498  elog(ERROR, "too many entries for GIN index");
499 
500  /*
501  * Allocate/reallocate memory for storing collected tuples
502  */
503  if (collector->tuples == NULL)
504  {
505  /*
506  * Determine the number of elements to allocate in the tuples array
507  * initially. Make it a power of 2 to avoid wasting memory when
508  * resizing (since palloc likes powers of 2).
509  */
510  collector->lentuples = pg_nextpower2_32(Max(16, nentries));
511  collector->tuples = palloc_array(IndexTuple, collector->lentuples);
512  }
513  else if (collector->lentuples < collector->ntuples + nentries)
514  {
515  /*
516  * Advance lentuples to the next suitable power of 2. This won't
517  * overflow, though we could get to a value that exceeds
518  * MaxAllocSize/sizeof(IndexTuple), causing an error in repalloc.
519  */
520  collector->lentuples = pg_nextpower2_32(collector->ntuples + nentries);
521  collector->tuples = repalloc_array(collector->tuples,
522  IndexTuple, collector->lentuples);
523  }
524 
525  /*
526  * Build an index tuple for each key value, and add to array. In pending
527  * tuples we just stick the heap TID into t_tid.
528  */
529  for (i = 0; i < nentries; i++)
530  {
531  IndexTuple itup;
532 
533  itup = GinFormTuple(ginstate, attnum, entries[i], categories[i],
534  NULL, 0, 0, true);
535  itup->t_tid = *ht_ctid;
536  collector->tuples[collector->ntuples++] = itup;
537  collector->sumsize += IndexTupleSize(itup);
538  }
539 }
#define repalloc_array(pointer, type, count)
Definition: fe_memutils.h:66
#define palloc_array(type, count)
Definition: fe_memutils.h:64
IndexTuple GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, Pointer data, Size dataSize, int nipd, bool errorTooBig)
Definition: ginentrypage.c:45
Datum * ginExtractEntries(GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, int32 *nentries, GinNullCategory **categories)
Definition: ginutil.c:490
#define MaxAllocSize
Definition: memutils.h:40
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:185
IndexTuple * tuples
Definition: gin_private.h:454
ItemPointerData t_tid
Definition: itup.h:37

References attnum, elog(), ERROR, ginExtractEntries(), GinFormTuple(), i, IndexTupleSize, GinTupleCollector::lentuples, Max, MaxAllocSize, GinTupleCollector::ntuples, palloc_array, pg_nextpower2_32(), repalloc_array, GinTupleCollector::sumsize, IndexTupleData::t_tid, GinTupleCollector::tuples, and value.

Referenced by gininsert().

◆ ginHeapTupleFastInsert()

void ginHeapTupleFastInsert ( GinState ginstate,
GinTupleCollector collector 
)

Definition at line 219 of file ginfast.c.

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

References Assert(), BufferGetPage(), CheckForSerializableConflictIn(), data, 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(), GinMetaPageData::nPendingHeapTuples, GinMetaPageData::nPendingPages, GinTupleCollector::ntuples, OffsetNumberNext, PageAddItem, PageGetExactFreeSpace(), PageGetMaxOffsetNumber(), PageIsEmpty(), PageSetLSN(), palloc(), 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().

◆ ginInitBA()

void ginInitBA ( BuildAccumulator accum)

Definition at line 109 of file ginbulk.c.

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 }
static void ginCombineData(RBTNode *existing, const RBTNode *newdata, void *arg)
Definition: ginbulk.c:30
static int cmpEntryAccumulator(const RBTNode *a, const RBTNode *b, void *arg)
Definition: ginbulk.c:72
static RBTNode * ginAllocEntryAccumulator(void *arg)
Definition: ginbulk.c:85
RBTree * rbt_create(Size node_size, rbt_comparator comparator, rbt_combiner combiner, rbt_allocfunc allocfunc, rbt_freefunc freefunc, void *arg)
Definition: rbtree.c:102
GinEntryAccumulator * entryallocator
Definition: gin_private.h:434

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

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

◆ GinInitBuffer()

void GinInitBuffer ( Buffer  b,
uint32  f 
)

Definition at line 357 of file ginutil.c.

358 {
360 }
static Size BufferGetPageSize(Buffer buffer)
Definition: bufmgr.h:270

References b, BufferGetPage(), BufferGetPageSize(), and GinInitPage().

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

◆ ginInitConsistentFunction()

void ginInitConsistentFunction ( GinState ginstate,
GinScanKey  key 
)

Definition at line 223 of file ginlogic.c.

224 {
225  if (key->searchMode == GIN_SEARCH_MODE_EVERYTHING)
226  {
227  key->boolConsistentFn = trueConsistentFn;
228  key->triConsistentFn = trueTriConsistentFn;
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))
237  key->boolConsistentFn = directBoolConsistentFn;
238  else
239  key->boolConsistentFn = shimBoolConsistentFn;
240 
241  if (OidIsValid(ginstate->triConsistentFn[key->attnum - 1].fn_oid))
242  key->triConsistentFn = directTriConsistentFn;
243  else
244  key->triConsistentFn = shimTriConsistentFn;
245  }
246 }
#define OidIsValid(objectId)
Definition: c.h:759
#define GIN_SEARCH_MODE_EVERYTHING
Definition: gin.h:37
static GinTernaryValue trueTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:62
static GinTernaryValue shimTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:152
static GinTernaryValue directTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:95
static bool trueConsistentFn(GinScanKey key)
Definition: ginlogic.c:56
static bool directBoolConsistentFn(GinScanKey key)
Definition: ginlogic.c:71
static bool shimBoolConsistentFn(GinScanKey key)
Definition: ginlogic.c:114
Oid fn_oid
Definition: fmgr.h:59
FmgrInfo triConsistentFn[INDEX_MAX_KEYS]
Definition: gin_private.h:82
FmgrInfo consistentFn[INDEX_MAX_KEYS]
Definition: gin_private.h:81

References GinState::consistentFn, directBoolConsistentFn(), directTriConsistentFn(), FmgrInfo::fn_oid, GIN_SEARCH_MODE_EVERYTHING, sort-test::key, OidIsValid, shimBoolConsistentFn(), shimTriConsistentFn(), GinState::supportCollation, GinState::triConsistentFn, trueConsistentFn(), and trueTriConsistentFn().

Referenced by ginFillScanKey().

◆ GinInitMetabuffer()

void GinInitMetabuffer ( Buffer  b)

Definition at line 363 of file ginutil.c.

364 {
365  GinMetaPageData *metadata;
366  Page page = BufferGetPage(b);
367 
369 
370  metadata = GinPageGetMeta(page);
371 
372  metadata->head = metadata->tail = InvalidBlockNumber;
373  metadata->tailFreeSize = 0;
374  metadata->nPendingPages = 0;
375  metadata->nPendingHeapTuples = 0;
376  metadata->nTotalPages = 0;
377  metadata->nEntryPages = 0;
378  metadata->nDataPages = 0;
379  metadata->nEntries = 0;
380  metadata->ginVersion = GIN_CURRENT_VERSION;
381 
382  /*
383  * Set pd_lower just past the end of the metadata. This is essential,
384  * because without doing so, metadata will be lost if xlog.c compresses
385  * the page.
386  */
387  ((PageHeader) page)->pd_lower =
388  ((char *) metadata + sizeof(GinMetaPageData)) - (char *) page;
389 }
#define GIN_CURRENT_VERSION
Definition: ginblock.h:102
#define GIN_META
Definition: ginblock.h:44
int64 nEntries
Definition: ginblock.h:82
int32 ginVersion
Definition: ginblock.h:99
BlockNumber nEntryPages
Definition: ginblock.h:80
BlockNumber nTotalPages
Definition: ginblock.h:79
BlockNumber nDataPages
Definition: ginblock.h:81

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

◆ GinInitPage()

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

Definition at line 345 of file ginutil.c.

346 {
347  GinPageOpaque opaque;
348 
349  PageInit(page, pageSize, sizeof(GinPageOpaqueData));
350 
351  opaque = GinPageGetOpaque(page);
352  opaque->flags = f;
353  opaque->rightlink = InvalidBlockNumber;
354 }
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:42
BlockNumber rightlink
Definition: ginblock.h:32

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

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

◆ gininsert()

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

Definition at line 488 of file gininsert.c.

493 {
494  GinState *ginstate = (GinState *) indexInfo->ii_AmCache;
495  MemoryContext oldCtx;
496  MemoryContext insertCtx;
497  int i;
498 
499  /* Initialize GinState cache if first call in this statement */
500  if (ginstate == NULL)
501  {
502  oldCtx = MemoryContextSwitchTo(indexInfo->ii_Context);
503  ginstate = (GinState *) palloc(sizeof(GinState));
504  initGinState(ginstate, index);
505  indexInfo->ii_AmCache = (void *) ginstate;
506  MemoryContextSwitchTo(oldCtx);
507  }
508 
510  "Gin insert temporary context",
512 
513  oldCtx = MemoryContextSwitchTo(insertCtx);
514 
516  {
517  GinTupleCollector collector;
518 
519  memset(&collector, 0, sizeof(GinTupleCollector));
520 
521  for (i = 0; i < ginstate->origTupdesc->natts; i++)
522  ginHeapTupleFastCollect(ginstate, &collector,
523  (OffsetNumber) (i + 1),
524  values[i], isnull[i],
525  ht_ctid);
526 
527  ginHeapTupleFastInsert(ginstate, &collector);
528  }
529  else
530  {
531  for (i = 0; i < ginstate->origTupdesc->natts; i++)
532  ginHeapTupleInsert(ginstate, (OffsetNumber) (i + 1),
533  values[i], isnull[i],
534  ht_ctid);
535  }
536 
537  MemoryContextSwitchTo(oldCtx);
538  MemoryContextDelete(insertCtx);
539 
540  return false;
541 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define GinGetUseFastUpdate(relation)
Definition: gin_private.h:33
void ginHeapTupleFastCollect(GinState *ginstate, GinTupleCollector *collector, OffsetNumber attnum, Datum value, bool isNull, ItemPointer ht_ctid)
Definition: ginfast.c:477
void ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
Definition: ginfast.c:219
static void ginHeapTupleInsert(GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, ItemPointer item)
Definition: gininsert.c:470
TupleDesc origTupdesc
Definition: gin_private.h:72
void * ii_AmCache
Definition: execnodes.h:201
MemoryContext ii_Context
Definition: execnodes.h:202

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

Referenced by ginhandler().

◆ ginInsertBAEntries()

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

Definition at line 210 of file ginbulk.c.

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 }
static void ginInsertBAEntry(BuildAccumulator *accum, ItemPointer heapptr, OffsetNumber attnum, Datum key, GinNullCategory category)
Definition: ginbulk.c:148

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

Referenced by ginHeapTupleBulkInsert(), and processPendingPage().

◆ ginInsertCleanup()

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

Definition at line 774 of file ginfast.c.

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

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

◆ ginInsertItemPointers()

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

Definition at line 1902 of file gindatapage.c.

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 }
static void ginPrepareDataScan(GinBtree btree, Relation index, BlockNumber rootBlkno)
Definition: gindatapage.c:1876
ItemPointerData * items
Definition: gin_private.h:194
ItemPointerData itemptr
Definition: gin_private.h:178

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

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

◆ ginInsertValue()

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

Definition at line 775 of file ginbtree.c.

777 {
778  bool done;
779 
780  /* If the leaf page was incompletely split, finish the split first */
782  ginFinishSplit(btree, stack, false, buildStats);
783 
784  done = ginPlaceToPage(btree, stack,
785  insertdata, InvalidBlockNumber,
786  InvalidBuffer, buildStats);
787  if (done)
788  {
789  LockBuffer(stack->buffer, GIN_UNLOCK);
790  freeGinBtreeStack(stack);
791  }
792  else
793  ginFinishSplit(btree, stack, true, buildStats);
794 }
static bool ginPlaceToPage(GinBtree btree, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, Buffer childbuf, GinStatsData *buildStats)
Definition: ginbtree.c:329

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

Referenced by ginEntryInsert(), and ginInsertItemPointers().

◆ ginMergeItemPointers()

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

Definition at line 378 of file ginpostinglist.c.

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 cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:747

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

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

◆ GinNewBuffer()

Buffer GinNewBuffer ( Relation  index)

Definition at line 299 of file ginutil.c.

300 {
301  Buffer buffer;
302  bool needLock;
303 
304  /* First, try to get a page from FSM */
305  for (;;)
306  {
308 
309  if (blkno == InvalidBlockNumber)
310  break;
311 
312  buffer = ReadBuffer(index, blkno);
313 
314  /*
315  * We have to guard against the possibility that someone else already
316  * recycled this page; the buffer may be locked if so.
317  */
318  if (ConditionalLockBuffer(buffer))
319  {
320  if (GinPageIsRecyclable(BufferGetPage(buffer)))
321  return buffer; /* OK to use */
322 
323  LockBuffer(buffer, GIN_UNLOCK);
324  }
325 
326  /* Can't use it, so release buffer and try again */
327  ReleaseBuffer(buffer);
328  }
329 
330  /* Must extend the file */
331  needLock = !RELATION_IS_LOCAL(index);
332  if (needLock)
334 
335  buffer = ReadBuffer(index, P_NEW);
336  LockBuffer(buffer, GIN_EXCLUSIVE);
337 
338  if (needLock)
340 
341  return buffer;
342 }
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:4252
bool GinPageIsRecyclable(Page page)
Definition: ginvacuum.c:802
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:431
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:481
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:648

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

◆ ginNewScanKey()

void ginNewScanKey ( IndexScanDesc  scan)

Definition at line 263 of file ginscan.c.

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 }
int errhint(const char *fmt,...)
Definition: elog.c:1316
Datum FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7)
Definition: fmgr.c:1256
#define GIN_SEARCH_MODE_ALL
Definition: gin.h:36
#define GIN_SEARCH_MODE_DEFAULT
Definition: gin.h:34
struct GinScanKeyData GinScanKeyData
struct GinScanKeyData * GinScanKey
Definition: gin_private.h:263
#define GIN_CAT_EMPTY_QUERY
Definition: ginblock.h:212
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
static void ginScanKeyAddHiddenEntry(GinScanOpaque so, GinScanKey key, GinNullCategory queryCategory)
Definition: ginscan.c:137
void ginGetStats(Relation index, GinStatsData *stats)
Definition: ginutil.c:630
#define INDEX_MAX_KEYS
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:615
#define SK_ISNULL
Definition: skey.h:115
#define InvalidStrategy
Definition: stratnum.h:24
int32 ginVersion
Definition: gin.h:49
struct ScanKeyData * keyData
Definition: relscan.h:122
int sk_flags
Definition: skey.h:66
Datum sk_argument
Definition: skey.h:72
StrategyNumber sk_strategy
Definition: skey.h:68
AttrNumber sk_attno
Definition: skey.h:67

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

Referenced by gingetbitmap().

◆ ginoptions()

bytea* ginoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 609 of file ginutil.c.

610 {
611  static const relopt_parse_elt tab[] = {
612  {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)},
613  {"gin_pending_list_limit", RELOPT_TYPE_INT, offsetof(GinOptions,
614  pendingListCleanupSize)}
615  };
616 
617  return (bytea *) build_reloptions(reloptions, validate,
619  sizeof(GinOptions),
620  tab, lengthof(tab));
621 }
#define lengthof(array)
Definition: c.h:772
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:1910
@ RELOPT_KIND_GIN
Definition: reloptions.h:46
@ RELOPT_TYPE_INT
Definition: reloptions.h:32
@ RELOPT_TYPE_BOOL
Definition: reloptions.h:31
Definition: c.h:671

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

Referenced by ginhandler().

◆ GinPageDeletePostingItem()

void GinPageDeletePostingItem ( Page  page,
OffsetNumber  offset 
)

Definition at line 417 of file gindatapage.c.

418 {
419  OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
420 
421  Assert(!GinPageIsLeaf(page));
422  Assert(offset >= FirstOffsetNumber && offset <= maxoff);
423 
424  if (offset != maxoff)
425  memmove(GinDataPageGetPostingItem(page, offset),
426  GinDataPageGetPostingItem(page, offset + 1),
427  sizeof(PostingItem) * (maxoff - offset));
428 
429  maxoff--;
430  GinPageGetOpaque(page)->maxoff = maxoff;
431 
432  GinDataPageSetDataSize(page, maxoff * sizeof(PostingItem));
433 }

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

Referenced by ginDeletePage(), and ginRedoDeletePage().

◆ ginPostingListDecode()

◆ ginPostingListDecodeAllSegments()

ItemPointer ginPostingListDecodeAllSegments ( GinPostingList segment,
int  len,
int *  ndecoded_out 
)

Definition at line 297 of file ginpostinglist.c.

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)
static void uint64_to_itemptr(uint64 val, ItemPointer iptr)
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
Definition: itemptr.h:124
#define OffsetNumberIsValid(offsetNumber)
Definition: off.h:39

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

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

◆ ginPostingListDecodeAllSegmentsToTbm()

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

Definition at line 358 of file ginpostinglist.c.

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 }

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

Referenced by GinDataLeafPageGetItemsToTbm().

◆ ginPrepareEntryScan()

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

Definition at line 745 of file ginentrypage.c.

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 }
void ginEntryFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
Definition: ginentrypage.c:721
static bool entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack)
Definition: ginentrypage.c:347
static bool entryIsMoveRight(GinBtree btree, Page page)
Definition: ginentrypage.c:244
static BlockNumber entryGetLeftMostPage(GinBtree btree, Page page)
Definition: ginentrypage.c:447
static void * entryPrepareDownlink(GinBtree btree, Buffer lbuf)
Definition: ginentrypage.c:700
static OffsetNumber entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
Definition: ginentrypage.c:406
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
static BlockNumber entryLocateEntry(GinBtree btree, GinBtreeStack *stack)
Definition: ginentrypage.c:271
Datum entryKey
Definition: gin_private.h:174
GinState * ginstate
Definition: gin_private.h:168
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
Definition: gin_private.h:160
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:153
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
Definition: gin_private.h:159
GinNullCategory entryCategory
Definition: gin_private.h:175
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:161
OffsetNumber entryAttnum
Definition: gin_private.h:173
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:158
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
Definition: gin_private.h:162

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

◆ ginReadTuple()

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

Definition at line 163 of file ginentrypage.c.

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 }
#define GinItupIsCompressed(itup)
Definition: ginblock.h:239
#define GinGetNPosting(itup)
Definition: ginblock.h:228

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

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

◆ ginrescan()

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

Definition at line 442 of file ginscan.c.

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 }

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

Referenced by ginhandler().

◆ ginScanBeginPostingTree()

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

Definition at line 1930 of file gindatapage.c.

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 }

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

Referenced by scanPostingTree(), and startScanEntry().

◆ ginStepRight()

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

Definition at line 173 of file ginbtree.c.

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 }

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

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

◆ ginTraverseLock()

int ginTraverseLock ( Buffer  buffer,
bool  searchMode 
)

Definition at line 36 of file ginbtree.c.

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
60  }
61  }
62 
63  return access;
64 }

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

Referenced by ginFindLeafPage().

◆ gintuple_get_attrnum()

OffsetNumber gintuple_get_attrnum ( GinState ginstate,
IndexTuple  tuple 
)

Definition at line 225 of file ginutil.c.

226 {
227  OffsetNumber colN;
228 
229  if (ginstate->oneCol)
230  {
231  /* column number is not stored explicitly */
232  colN = FirstOffsetNumber;
233  }
234  else
235  {
236  Datum res;
237  bool isnull;
238 
239  /*
240  * First attribute is always int16, so we can safely use any tuple
241  * descriptor to obtain first attribute of tuple
242  */
243  res = index_getattr(tuple, FirstOffsetNumber, ginstate->tupdesc[0],
244  &isnull);
245  Assert(!isnull);
246 
247  colN = DatumGetUInt16(res);
248  Assert(colN >= FirstOffsetNumber && colN <= ginstate->origTupdesc->natts);
249  }
250 
251  return colN;
252 }
static Datum index_getattr(IndexTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: itup.h:117
static uint16 DatumGetUInt16(Datum X)
Definition: postgres.h:182

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

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

◆ gintuple_get_key()

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

Definition at line 258 of file ginutil.c.

260 {
261  Datum res;
262  bool isnull;
263 
264  if (ginstate->oneCol)
265  {
266  /*
267  * Single column index doesn't store attribute numbers in tuples
268  */
269  res = index_getattr(tuple, FirstOffsetNumber, ginstate->origTupdesc,
270  &isnull);
271  }
272  else
273  {
274  /*
275  * Since the datum type depends on which index column it's from, we
276  * must be careful to use the right tuple descriptor here.
277  */
278  OffsetNumber colN = gintuple_get_attrnum(ginstate, tuple);
279 
281  ginstate->tupdesc[colN - 1],
282  &isnull);
283  }
284 
285  if (isnull)
286  *category = GinGetNullCategory(tuple, ginstate);
287  else
288  *category = GIN_CAT_NORM_KEY;
289 
290  return res;
291 }
#define GinGetNullCategory(itup, ginstate)
Definition: ginblock.h:220
OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple)
Definition: ginutil.c:225

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

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

◆ ginvacuumcleanup()

IndexBulkDeleteResult* ginvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)

Definition at line 688 of file ginvacuum.c.

689 {
690  Relation index = info->index;
691  bool needLock;
692  BlockNumber npages,
693  blkno;
694  BlockNumber totFreePages;
695  GinState ginstate;
696  GinStatsData idxStat;
697 
698  /*
699  * In an autovacuum analyze, we want to clean up pending insertions.
700  * Otherwise, an ANALYZE-only call is a no-op.
701  */
702  if (info->analyze_only)
703  {
705  {
706  initGinState(&ginstate, index);
707  ginInsertCleanup(&ginstate, false, true, true, stats);
708  }
709  return stats;
710  }
711 
712  /*
713  * Set up all-zero stats and cleanup pending inserts if ginbulkdelete
714  * wasn't called
715  */
716  if (stats == NULL)
717  {
719  initGinState(&ginstate, index);
721  false, true, stats);
722  }
723 
724  memset(&idxStat, 0, sizeof(idxStat));
725 
726  /*
727  * XXX we always report the heap tuple count as the number of index
728  * entries. This is bogus if the index is partial, but it's real hard to
729  * tell how many distinct heap entries are referenced by a GIN index.
730  */
731  stats->num_index_tuples = Max(info->num_heap_tuples, 0);
732  stats->estimated_count = info->estimated_count;
733 
734  /*
735  * Need lock unless it's local to this backend.
736  */
737  needLock = !RELATION_IS_LOCAL(index);
738 
739  if (needLock)
742  if (needLock)
744 
745  totFreePages = 0;
746 
747  for (blkno = GIN_ROOT_BLKNO; blkno < npages; blkno++)
748  {
749  Buffer buffer;
750  Page page;
751 
753 
754  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
755  RBM_NORMAL, info->strategy);
756  LockBuffer(buffer, GIN_SHARE);
757  page = (Page) BufferGetPage(buffer);
758 
759  if (GinPageIsRecyclable(page))
760  {
761  Assert(blkno != GIN_ROOT_BLKNO);
762  RecordFreeIndexPage(index, blkno);
763  totFreePages++;
764  }
765  else if (GinPageIsData(page))
766  {
767  idxStat.nDataPages++;
768  }
769  else if (!GinPageIsList(page))
770  {
771  idxStat.nEntryPages++;
772 
773  if (GinPageIsLeaf(page))
774  idxStat.nEntries += PageGetMaxOffsetNumber(page);
775  }
776 
777  UnlockReleaseBuffer(buffer);
778  }
779 
780  /* Update the metapage with accurate page and entry counts */
781  idxStat.nTotalPages = npages;
782  ginUpdateStats(info->index, &idxStat, false);
783 
784  /* Finally, vacuum the FSM */
786 
787  stats->pages_free = totFreePages;
788 
789  if (needLock)
792  if (needLock)
794 
795  return stats;
796 }
#define GinPageIsList(page)
Definition: ginblock.h:117
void RecordFreeIndexPage(Relation rel, BlockNumber freeBlock)
Definition: indexfsm.c:52
bool estimated_count
Definition: genam.h:77
BlockNumber pages_free
Definition: genam.h:82
BlockNumber num_pages
Definition: genam.h:76
double num_heap_tuples
Definition: genam.h:51
bool analyze_only
Definition: genam.h:47
bool estimated_count
Definition: genam.h:49

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(), ginUpdateStats(), IndexVacuumInfo::index, IndexFreeSpaceMapVacuum(), initGinState(), IsAutoVacuumWorkerProcess(), LockBuffer(), LockRelationForExtension(), MAIN_FORKNUM, Max, 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().

◆ ginVacuumItemPointers()

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

Definition at line 48 of file ginvacuum.c.

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:79

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

Referenced by ginVacuumEntryPage(), and ginVacuumPostingTreeLeaf().

◆ ginVacuumPostingTreeLeaf()

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

Definition at line 735 of file gindatapage.c.

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 != GIN_SEGMENT_UNMODIFIED)
827  modified = true;
828  if (modified && seginfo->action != GIN_SEGMENT_DELETE)
829  {
830  int segsize = SizeOfGinPostingList(seginfo->seg);
831  GinPostingList *tmp = (GinPostingList *) palloc(segsize);
832 
833  memcpy(tmp, seginfo->seg, segsize);
834  seginfo->seg = tmp;
835  }
836  }
837 
838  if (RelationNeedsWAL(indexrel))
840 
841  /* Apply changes to page */
843 
844  dataPlaceToPageLeafRecompress(buffer, leaf);
845 
846  MarkBufferDirty(buffer);
847 
848  if (RelationNeedsWAL(indexrel))
849  {
850  XLogRecPtr recptr;
851 
852  XLogBeginInsert();
854  XLogRegisterBufData(0, leaf->walinfo, leaf->walinfolen);
855  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_VACUUM_DATA_LEAF_PAGE);
856  PageSetLSN(page, recptr);
857  }
858 
860  }
861 }
static void dataPlaceToPageLeafRecompress(Buffer buf, disassembledLeaf *leaf)
Definition: gindatapage.c:975
static void computeLeafRecompressWALData(disassembledLeaf *leaf)
Definition: gindatapage.c:869
static disassembledLeaf * disassembleLeaf(Page page)
Definition: gindatapage.c:1364
ItemPointer ginVacuumItemPointers(GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining)
Definition: ginvacuum.c:48
#define GIN_SEGMENT_DELETE
Definition: ginxlog.h:92
#define XLOG_GIN_VACUUM_DATA_LEAF_PAGE
Definition: ginxlog.h:141
#define GIN_SEGMENT_UNMODIFIED
Definition: ginxlog.h:91
#define GIN_SEGMENT_REPLACE
Definition: ginxlog.h:94
#define dlist_foreach(iter, lhead)
Definition: ilist.h:623
#define dlist_container(type, membername, ptr)
Definition: ilist.h:593
dlist_head segments
Definition: gindatapage.c:50
dlist_node * cur
Definition: ilist.h:179
ItemPointer items
Definition: gindatapage.c:101
GinPostingList * seg
Definition: gindatapage.c:100

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

◆ ginvalidate()

bool ginvalidate ( Oid  opclassoid)

Definition at line 33 of file ginvalidate.c.

34 {
35  bool result = true;
36  HeapTuple classtup;
37  Form_pg_opclass classform;
38  Oid opfamilyoid;
39  Oid opcintype;
40  Oid opckeytype;
41  char *opclassname;
42  HeapTuple familytup;
43  Form_pg_opfamily familyform;
44  char *opfamilyname;
45  CatCList *proclist,
46  *oprlist;
47  List *grouplist;
48  OpFamilyOpFuncGroup *opclassgroup;
49  int i;
50  ListCell *lc;
51 
52  /* Fetch opclass information */
53  classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
54  if (!HeapTupleIsValid(classtup))
55  elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
56  classform = (Form_pg_opclass) GETSTRUCT(classtup);
57 
58  opfamilyoid = classform->opcfamily;
59  opcintype = classform->opcintype;
60  opckeytype = classform->opckeytype;
61  if (!OidIsValid(opckeytype))
62  opckeytype = opcintype;
63  opclassname = NameStr(classform->opcname);
64 
65  /* Fetch opfamily information */
66  familytup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyoid));
67  if (!HeapTupleIsValid(familytup))
68  elog(ERROR, "cache lookup failed for operator family %u", opfamilyoid);
69  familyform = (Form_pg_opfamily) GETSTRUCT(familytup);
70 
71  opfamilyname = NameStr(familyform->opfname);
72 
73  /* Fetch all operators and support functions of the opfamily */
74  oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
75  proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
76 
77  /* Check individual support functions */
78  for (i = 0; i < proclist->n_members; i++)
79  {
80  HeapTuple proctup = &proclist->members[i]->tuple;
81  Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
82  bool ok;
83 
84  /*
85  * All GIN support functions should be registered with matching
86  * left/right types
87  */
88  if (procform->amproclefttype != procform->amprocrighttype)
89  {
90  ereport(INFO,
91  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
92  errmsg("operator family \"%s\" of access method %s contains support function %s with different left and right input types",
93  opfamilyname, "gin",
94  format_procedure(procform->amproc))));
95  result = false;
96  }
97 
98  /*
99  * We can't check signatures except within the specific opclass, since
100  * we need to know the associated opckeytype in many cases.
101  */
102  if (procform->amproclefttype != opcintype)
103  continue;
104 
105  /* Check procedure numbers and function signatures */
106  switch (procform->amprocnum)
107  {
108  case GIN_COMPARE_PROC:
109  ok = check_amproc_signature(procform->amproc, INT4OID, false,
110  2, 2, opckeytype, opckeytype);
111  break;
113  /* Some opclasses omit nullFlags */
114  ok = check_amproc_signature(procform->amproc, INTERNALOID, false,
115  2, 3, opcintype, INTERNALOID,
116  INTERNALOID);
117  break;
119  /* Some opclasses omit nullFlags and searchMode */
120  ok = check_amproc_signature(procform->amproc, INTERNALOID, false,
121  5, 7, opcintype, INTERNALOID,
122  INT2OID, INTERNALOID, INTERNALOID,
123  INTERNALOID, INTERNALOID);
124  break;
125  case GIN_CONSISTENT_PROC:
126  /* Some opclasses omit queryKeys and nullFlags */
127  ok = check_amproc_signature(procform->amproc, BOOLOID, false,
128  6, 8, INTERNALOID, INT2OID,
129  opcintype, INT4OID,
130  INTERNALOID, INTERNALOID,
131  INTERNALOID, INTERNALOID);
132  break;
134  ok = check_amproc_signature(procform->amproc, INT4OID, false,
135  4, 4, opckeytype, opckeytype,
136  INT2OID, INTERNALOID);
137  break;
139  ok = check_amproc_signature(procform->amproc, CHAROID, false,
140  7, 7, INTERNALOID, INT2OID,
141  opcintype, INT4OID,
142  INTERNALOID, INTERNALOID,
143  INTERNALOID);
144  break;
145  case GIN_OPTIONS_PROC:
146  ok = check_amoptsproc_signature(procform->amproc);
147  break;
148  default:
149  ereport(INFO,
150  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
151  errmsg("operator family \"%s\" of access method %s contains function %s with invalid support number %d",
152  opfamilyname, "gin",
153  format_procedure(procform->amproc),
154  procform->amprocnum)));
155  result = false;
156  continue; /* don't want additional message */
157  }
158 
159  if (!ok)
160  {
161  ereport(INFO,
162  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
163  errmsg("operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d",
164  opfamilyname, "gin",
165  format_procedure(procform->amproc),
166  procform->amprocnum)));
167  result = false;
168  }
169  }
170 
171  /* Check individual operators */
172  for (i = 0; i < oprlist->n_members; i++)
173  {
174  HeapTuple oprtup = &oprlist->members[i]->tuple;
175  Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
176 
177  /* TODO: Check that only allowed strategy numbers exist */
178  if (oprform->amopstrategy < 1 || oprform->amopstrategy > 63)
179  {
180  ereport(INFO,
181  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
182  errmsg("operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
183  opfamilyname, "gin",
184  format_operator(oprform->amopopr),
185  oprform->amopstrategy)));
186  result = false;
187  }
188 
189  /* gin doesn't support ORDER BY operators */
190  if (oprform->amoppurpose != AMOP_SEARCH ||
191  OidIsValid(oprform->amopsortfamily))
192  {
193  ereport(INFO,
194  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
195  errmsg("operator family \"%s\" of access method %s contains invalid ORDER BY specification for operator %s",
196  opfamilyname, "gin",
197  format_operator(oprform->amopopr))));
198  result = false;
199  }
200 
201  /* Check operator signature --- same for all gin strategies */
202  if (!check_amop_signature(oprform->amopopr, BOOLOID,
203  oprform->amoplefttype,
204  oprform->amoprighttype))
205  {
206  ereport(INFO,
207  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
208  errmsg("operator family \"%s\" of access method %s contains operator %s with wrong signature",
209  opfamilyname, "gin",
210  format_operator(oprform->amopopr))));
211  result = false;
212  }
213  }
214 
215  /* Now check for inconsistent groups of operators/functions */
216  grouplist = identify_opfamily_groups(oprlist, proclist);
217  opclassgroup = NULL;
218  foreach(lc, grouplist)
219  {
220  OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
221 
222  /* Remember the group exactly matching the test opclass */
223  if (thisgroup->lefttype == opcintype &&
224  thisgroup->righttype == opcintype)
225  opclassgroup = thisgroup;
226 
227  /*
228  * There is not a lot we can do to check the operator sets, since each
229  * GIN opclass is more or less a law unto itself, and some contain
230  * only operators that are binary-compatible with the opclass datatype
231  * (meaning that empty operator sets can be OK). That case also means
232  * that we shouldn't insist on nonempty function sets except for the
233  * opclass's own group.
234  */
235  }
236 
237  /* Check that the originally-named opclass is complete */
238  for (i = 1; i <= GINNProcs; i++)
239  {
240  if (opclassgroup &&
241  (opclassgroup->functionset & (((uint64) 1) << i)) != 0)
242  continue; /* got it */
244  i == GIN_OPTIONS_PROC)
245  continue; /* optional method */
247  continue; /* don't need both, see check below loop */
248  ereport(INFO,
249  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
250  errmsg("operator class \"%s\" of access method %s is missing support function %d",
251  opclassname, "gin", i)));
252  result = false;
253  }
254  if (!opclassgroup ||
255  ((opclassgroup->functionset & (1 << GIN_CONSISTENT_PROC)) == 0 &&
256  (opclassgroup->functionset & (1 << GIN_TRICONSISTENT_PROC)) == 0))
257  {
258  ereport(INFO,
259  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
260  errmsg("operator class \"%s\" of access method %s is missing support function %d or %d",
261  opclassname, "gin",
263  result = false;
264  }
265 
266 
267  ReleaseCatCacheList(proclist);
268  ReleaseCatCacheList(oprlist);
269  ReleaseSysCache(familytup);
270  ReleaseSysCache(classtup);
271 
272  return result;
273 }
bool check_amproc_signature(Oid funcid, Oid restype, bool exact, int minargs, int maxargs,...)
Definition: amvalidate.c:152
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
Definition: amvalidate.c:206
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
Definition: amvalidate.c:43
bool check_amoptsproc_signature(Oid funcid)
Definition: amvalidate.c:192
#define NameStr(name)
Definition: c.h:730
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1776
#define INFO
Definition: elog.h:34
#define GINNProcs
Definition: gin.h:29
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
FormData_pg_amop * Form_pg_amop
Definition: pg_amop.h:88
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:68
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:51
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
unsigned int Oid
Definition: postgres_ext.h:31
char * format_operator(Oid operator_oid)
Definition: regproc.c:793
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:299
Definition: pg_list.h:54
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:178
int n_members
Definition: catcache.h:176
HeapTupleData tuple
Definition: catcache.h:121
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:866
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:818
@ OPFAMILYOID
Definition: syscache.h:74
@ CLAOID
Definition: syscache.h:48
@ AMPROCNUM
Definition: syscache.h:39
@ AMOPSTRATEGY
Definition: syscache.h:38
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:218

References AMOPSTRATEGY, AMPROCNUM, check_amop_signature(), check_amoptsproc_signature(), check_amproc_signature(), CLAOID, elog(), ereport, errcode(), errmsg(), ERROR, format_operator(), format_procedure(), OpFamilyOpFuncGroup::functionset, GETSTRUCT, GIN_COMPARE_PARTIAL_PROC, GIN_COMPARE_PROC, GIN_CONSISTENT_PROC, GIN_EXTRACTQUERY_PROC, GIN_EXTRACTVALUE_PROC, GIN_OPTIONS_PROC, GIN_TRICONSISTENT_PROC, GINNProcs, HeapTupleIsValid, i, identify_opfamily_groups(), INFO, OpFamilyOpFuncGroup::lefttype, lfirst, catclist::members, catclist::n_members, NameStr, ObjectIdGetDatum(), OidIsValid, OPFAMILYOID, ReleaseCatCacheList(), ReleaseSysCache(), OpFamilyOpFuncGroup::righttype, SearchSysCache1(), SearchSysCacheList1, and catctup::tuple.

Referenced by ginhandler().

◆ initGinState()

void initGinState ( GinState state,
Relation  index 
)

Definition at line 96 of file ginutil.c.

97 {
98  TupleDesc origTupdesc = RelationGetDescr(index);
99  int i;
100 
101  MemSet(state, 0, sizeof(GinState));
102 
103  state->index = index;
104  state->oneCol = (origTupdesc->natts == 1);
105  state->origTupdesc = origTupdesc;
106 
107  for (i = 0; i < origTupdesc->natts; i++)
108  {
109  Form_pg_attribute attr = TupleDescAttr(origTupdesc, i);
110 
111  if (state->oneCol)
112  state->tupdesc[i] = state->origTupdesc;
113  else
114  {
115  state->tupdesc[i] = CreateTemplateTupleDesc(2);
116 
117  TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 1, NULL,
118  INT2OID, -1, 0);
119  TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 2, NULL,
120  attr->atttypid,
121  attr->atttypmod,
122  attr->attndims);
124  attr->attcollation);
125  }
126 
127  /*
128  * If the compare proc isn't specified in the opclass definition, look
129  * up the index key type's default btree comparator.
130  */
132  {
133  fmgr_info_copy(&(state->compareFn[i]),
136  }
137  else
138  {
139  TypeCacheEntry *typentry;
140 
141  typentry = lookup_type_cache(attr->atttypid,
143  if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
144  ereport(ERROR,
145  (errcode(ERRCODE_UNDEFINED_FUNCTION),
146  errmsg("could not identify a comparison function for type %s",
147  format_type_be(attr->atttypid))));
148  fmgr_info_copy(&(state->compareFn[i]),
149  &(typentry->cmp_proc_finfo),
151  }
152 
153  /* Opclass must always provide extract procs */
154  fmgr_info_copy(&(state->extractValueFn[i]),
157  fmgr_info_copy(&(state->extractQueryFn[i]),
160 
161  /*
162  * Check opclass capability to do tri-state or binary logic consistent
163  * check.
164  */
166  {
167  fmgr_info_copy(&(state->triConsistentFn[i]),
170  }
171 
173  {
174  fmgr_info_copy(&(state->consistentFn[i]),
177  }
178 
179  if (state->consistentFn[i].fn_oid == InvalidOid &&
180  state->triConsistentFn[i].fn_oid == InvalidOid)
181  {
182  elog(ERROR, "missing GIN support function (%d or %d) for attribute %d of index \"%s\"",
185  }
186 
187  /*
188  * Check opclass capability to do partial match.
189  */
191  {
192  fmgr_info_copy(&(state->comparePartialFn[i]),
195  state->canPartialMatch[i] = true;
196  }
197  else
198  {
199  state->canPartialMatch[i] = false;
200  }
201 
202  /*
203  * If the index column has a specified collation, we should honor that
204  * while doing comparisons. However, we may have a collatable storage
205  * type for a noncollatable indexed data type (for instance, hstore
206  * uses text index entries). If there's no index collation then
207  * specify default collation in case the support functions need
208  * collation. This is harmless if the support functions don't care
209  * about collation, so we just do it unconditionally. (We could
210  * alternatively call get_typcollation, but that seems like expensive
211  * overkill --- there aren't going to be any cases where a GIN storage
212  * type has a nondefault collation.)
213  */
214  if (OidIsValid(index->rd_indcollation[i]))
215  state->supportCollation[i] = index->rd_indcollation[i];
216  else
217  state->supportCollation[i] = DEFAULT_COLLATION_OID;
218  }
219 }
int16 AttrNumber
Definition: attnum.h:21
#define MemSet(start, val, len)
Definition: c.h:1004
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition: fmgr.c:580
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:811
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:777
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationGetDescr(relation)
Definition: rel.h:529
FmgrInfo cmp_proc_finfo
Definition: typcache.h:76
Definition: regguts.h:318
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:45
void TupleDescInitEntryCollation(TupleDesc desc, AttrNumber attributeNumber, Oid collationid)
Definition: tupdesc.c:767
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:583
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:339
#define TYPECACHE_CMP_PROC_FINFO
Definition: typcache.h:142

References TypeCacheEntry::cmp_proc_finfo, CreateTemplateTupleDesc(), CurrentMemoryContext, elog(), ereport, errcode(), errmsg(), ERROR, fmgr_info_copy(), FmgrInfo::fn_oid, format_type_be(), GIN_COMPARE_PARTIAL_PROC, GIN_COMPARE_PROC, GIN_CONSISTENT_PROC, GIN_EXTRACTQUERY_PROC, GIN_EXTRACTVALUE_PROC, GIN_TRICONSISTENT_PROC, i, index_getprocid(), index_getprocinfo(), InvalidOid, lookup_type_cache(), MemSet, TupleDescData::natts, OidIsValid, RelationGetDescr, RelationGetRelationName, TupleDescAttr, TupleDescInitEntry(), TupleDescInitEntryCollation(), and TYPECACHE_CMP_PROC_FINFO.

Referenced by gin_clean_pending_list(), ginbeginscan(), ginbuild(), ginbulkdelete(), gininsert(), and ginvacuumcleanup().