PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gin_private.h File Reference
#include "access/amapi.h"
#include "access/gin.h"
#include "access/ginblock.h"
#include "access/itup.h"
#include "common/int.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)
 
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)
 
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 33 of file gin_private.h.

◆ GIN_EXCLUSIVE

#define GIN_EXCLUSIVE   BUFFER_LOCK_EXCLUSIVE

Definition at line 51 of file gin_private.h.

◆ GIN_SHARE

#define GIN_SHARE   BUFFER_LOCK_SHARE

Definition at line 50 of file gin_private.h.

◆ GIN_UNLOCK

#define GIN_UNLOCK   BUFFER_LOCK_UNLOCK

Definition at line 49 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:838
int gin_pending_list_limit
Definition: ginfast.c:39

Definition at line 39 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:33

Definition at line 34 of file gin_private.h.

Typedef Documentation

◆ GinBtree

typedef struct GinBtreeData* GinBtree

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

◆ GinScanEntryData

◆ GinScanKey

typedef struct GinScanKeyData* GinScanKey

Definition at line 264 of file gin_private.h.

◆ GinScanKeyData

◆ GinScanOpaque

Definition at line 386 of file gin_private.h.

◆ GinScanOpaqueData

◆ GinState

typedef struct GinState GinState

◆ GinTupleCollector

◆ GinVacuumState

Definition at line 235 of file gin_private.h.

Enumeration Type Documentation

◆ GinPlaceToPageRC

Enumerator
GPTP_NO_WORK 
GPTP_INSERT 
GPTP_SPLIT 

Definition at line 143 of file gin_private.h.

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

Function Documentation

◆ createPostingTree()

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

Definition at line 1775 of file gindatapage.c.

1777 {
1778  BlockNumber blkno;
1779  Buffer buffer;
1780  Page tmppage;
1781  Page page;
1782  Pointer ptr;
1783  int nrootitems;
1784  int rootsize;
1785  bool is_build = (buildStats != NULL);
1786 
1787  /* Construct the new root page in memory first. */
1788  tmppage = (Page) palloc(BLCKSZ);
1789  GinInitPage(tmppage, GIN_DATA | GIN_LEAF | GIN_COMPRESSED, BLCKSZ);
1790  GinPageGetOpaque(tmppage)->rightlink = InvalidBlockNumber;
1791 
1792  /*
1793  * Write as many of the items to the root page as fit. In segments of max
1794  * GinPostingListSegmentMaxSize bytes each.
1795  */
1796  nrootitems = 0;
1797  rootsize = 0;
1798  ptr = (Pointer) GinDataLeafPageGetPostingList(tmppage);
1799  while (nrootitems < nitems)
1800  {
1801  GinPostingList *segment;
1802  int npacked;
1803  int segsize;
1804 
1805  segment = ginCompressPostingList(&items[nrootitems],
1806  nitems - nrootitems,
1808  &npacked);
1809  segsize = SizeOfGinPostingList(segment);
1810  if (rootsize + segsize > GinDataPageMaxDataSize)
1811  break;
1812 
1813  memcpy(ptr, segment, segsize);
1814  ptr += segsize;
1815  rootsize += segsize;
1816  nrootitems += npacked;
1817  pfree(segment);
1818  }
1819  GinDataPageSetDataSize(tmppage, rootsize);
1820 
1821  /*
1822  * All set. Get a new physical page, and copy the in-memory page to it.
1823  */
1824  buffer = GinNewBuffer(index);
1825  page = BufferGetPage(buffer);
1826  blkno = BufferGetBlockNumber(buffer);
1827 
1828  /*
1829  * Copy any predicate locks from the entry tree leaf (containing posting
1830  * list) to the posting tree.
1831  */
1832  PredicateLockPageSplit(index, BufferGetBlockNumber(entrybuffer), blkno);
1833 
1835 
1836  PageRestoreTempPage(tmppage, page);
1837  MarkBufferDirty(buffer);
1838 
1839  if (RelationNeedsWAL(index) && !is_build)
1840  {
1841  XLogRecPtr recptr;
1843 
1844  data.size = rootsize;
1845 
1846  XLogBeginInsert();
1847  XLogRegisterData((char *) &data, sizeof(ginxlogCreatePostingTree));
1848 
1850  rootsize);
1852 
1853  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_PTREE);
1854  PageSetLSN(page, recptr);
1855  }
1856 
1857  UnlockReleaseBuffer(buffer);
1858 
1859  END_CRIT_SECTION();
1860 
1861  /* During index build, count the newly-added data page */
1862  if (buildStats)
1863  buildStats->nDataPages++;
1864 
1865  elog(DEBUG2, "created GIN posting tree with %d items", nrootitems);
1866 
1867  /*
1868  * Add any remaining TIDs to the newly-created posting tree.
1869  */
1870  if (nitems > nrootitems)
1871  {
1873  items + nrootitems,
1874  nitems - nrootitems,
1875  buildStats);
1876  }
1877 
1878  return blkno;
1879 }
uint32 BlockNumber
Definition: block.h:31
#define InvalidBlockNumber
Definition: block.h:33
int Buffer
Definition: buf.h:23
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:3724
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4941
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2532
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:400
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:413
Pointer Page
Definition: bufpage.h:81
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:391
char * Pointer
Definition: c.h:472
#define DEBUG2
Definition: elog.h:29
#define elog(elevel,...)
Definition: elog.h:225
#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:1908
GinPostingList * ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:339
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:301
#define XLOG_GIN_CREATE_PTREE
Definition: ginxlog.h:19
#define nitems(x)
Definition: indent.h:31
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
#define START_CRIT_SECTION()
Definition: miscadmin.h:149
#define END_CRIT_SECTION()
Definition: miscadmin.h:151
const void * data
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3134
#define RelationNeedsWAL(relation)
Definition: rel.h:628
BlockNumber nDataPages
Definition: gin.h:47
Definition: type.h:96
static ItemArray items
Definition: test_tidstore.c:48
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogRegisterData(const char *data, uint32 len)
Definition: xloginsert.c:364
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:242
void XLogBeginInsert(void)
Definition: xloginsert.c:149
#define REGBUF_WILL_INIT
Definition: xloginsert.h: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, items, MarkBufferDirty(), GinStatsData::nDataPages, nitems, PageRestoreTempPage(), PageSetLSN(), palloc(), pfree(), PredicateLockPageSplit(), REGBUF_WILL_INIT, RelationNeedsWAL, SizeOfGinPostingList, START_CRIT_SECTION, UnlockReleaseBuffer(), XLOG_GIN_CREATE_PTREE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by addItemPointersToLeafTuple(), and buildFreshLeafTuple().

◆ freeGinBtreeStack()

void freeGinBtreeStack ( GinBtreeStack stack)

Definition at line 198 of file ginbtree.c.

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

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 277 of file ginvalidate.c.

281 {
282  ListCell *lc;
283 
284  /*
285  * Operator members of a GIN opfamily should never have hard dependencies,
286  * since their connection to the opfamily depends only on what the support
287  * functions think, and that can be altered. For consistency, we make all
288  * soft dependencies point to the opfamily, though a soft dependency on
289  * the opclass would work as well in the CREATE OPERATOR CLASS case.
290  */
291  foreach(lc, operators)
292  {
293  OpFamilyMember *op = (OpFamilyMember *) lfirst(lc);
294 
295  op->ref_is_hard = false;
296  op->ref_is_family = true;
297  op->refobjid = opfamilyoid;
298  }
299 
300  /*
301  * Required support functions should have hard dependencies. Preferably
302  * those are just dependencies on the opclass, but if we're in ALTER
303  * OPERATOR FAMILY, we leave the dependency pointing at the whole
304  * opfamily. (Given that GIN opclasses generally don't share opfamilies,
305  * it seems unlikely to be worth working harder.)
306  */
307  foreach(lc, functions)
308  {
309  OpFamilyMember *op = (OpFamilyMember *) lfirst(lc);
310 
311  switch (op->number)
312  {
315  /* Required support function */
316  op->ref_is_hard = true;
317  break;
318  case GIN_COMPARE_PROC:
319  case GIN_CONSISTENT_PROC:
322  case GIN_OPTIONS_PROC:
323  /* Optional, so force it to be a soft family dependency */
324  op->ref_is_hard = false;
325  op->ref_is_family = true;
326  op->refobjid = opfamilyoid;
327  break;
328  default:
329  ereport(ERROR,
330  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
331  errmsg("support function number %d is invalid for access method %s",
332  op->number, "gin")));
333  break;
334  }
335  }
336 }
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#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:358
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:438

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 }
#define Assert(condition)
Definition: c.h:837
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:80
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:386
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:98
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
GinScanKey keys
Definition: gin_private.h:374
MemoryContext keyCtx
Definition: gin_private.h:381
MemoryContext tempCtx
Definition: gin_private.h:371
Relation indexRelation
Definition: relscan.h:141

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 317 of file gininsert.c.

318 {
319  IndexBuildResult *result;
320  double reltuples;
321  GinBuildState buildstate;
322  Buffer RootBuffer,
323  MetaBuffer;
325  Datum key;
326  GinNullCategory category;
327  uint32 nlist;
328  MemoryContext oldCtx;
330 
332  elog(ERROR, "index \"%s\" already contains data",
334 
335  initGinState(&buildstate.ginstate, index);
336  buildstate.indtuples = 0;
337  memset(&buildstate.buildStats, 0, sizeof(GinStatsData));
338 
339  /* initialize the meta page */
340  MetaBuffer = GinNewBuffer(index);
341 
342  /* initialize the root page */
343  RootBuffer = GinNewBuffer(index);
344 
346  GinInitMetabuffer(MetaBuffer);
347  MarkBufferDirty(MetaBuffer);
348  GinInitBuffer(RootBuffer, GIN_LEAF);
349  MarkBufferDirty(RootBuffer);
350 
351 
352  UnlockReleaseBuffer(MetaBuffer);
353  UnlockReleaseBuffer(RootBuffer);
355 
356  /* count the root as first entry page */
357  buildstate.buildStats.nEntryPages++;
358 
359  /*
360  * create a temporary memory context that is used to hold data not yet
361  * dumped out to the index
362  */
364  "Gin build temporary context",
366 
367  /*
368  * create a temporary memory context that is used for calling
369  * ginExtractEntries(), and can be reset after each tuple
370  */
372  "Gin build temporary context for user-defined function",
374 
375  buildstate.accum.ginstate = &buildstate.ginstate;
376  ginInitBA(&buildstate.accum);
377 
378  /*
379  * Do the heap scan. We disallow sync scan here because dataPlaceToPage
380  * prefers to receive tuples in TID order.
381  */
382  reltuples = table_index_build_scan(heap, index, indexInfo, false, true,
383  ginBuildCallback, &buildstate, NULL);
384 
385  /* dump remaining entries to the index */
386  oldCtx = MemoryContextSwitchTo(buildstate.tmpCtx);
387  ginBeginBAScan(&buildstate.accum);
388  while ((list = ginGetBAEntry(&buildstate.accum,
389  &attnum, &key, &category, &nlist)) != NULL)
390  {
391  /* there could be many entries, so be willing to abort here */
393  ginEntryInsert(&buildstate.ginstate, attnum, key, category,
394  list, nlist, &buildstate.buildStats);
395  }
396  MemoryContextSwitchTo(oldCtx);
397 
398  MemoryContextDelete(buildstate.funcCtx);
399  MemoryContextDelete(buildstate.tmpCtx);
400 
401  /*
402  * Update metapage stats
403  */
405  ginUpdateStats(index, &buildstate.buildStats, true);
406 
407  /*
408  * We didn't write WAL records as we built the index, so if WAL-logging is
409  * required, write all pages to the WAL now.
410  */
411  if (RelationNeedsWAL(index))
412  {
415  true);
416  }
417 
418  /*
419  * Return statistics
420  */
421  result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
422 
423  result->heap_tuples = reltuples;
424  result->index_tuples = buildstate.indtuples;
425 
426  return result;
427 }
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:273
unsigned int uint32
Definition: c.h:492
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:176
static void ginBuildCallback(Relation index, ItemPointer tid, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition: gininsert.c:277
void GinInitBuffer(Buffer b, uint32 f)
Definition: ginutil.c:351
void GinInitMetabuffer(Buffer b)
Definition: ginutil.c:357
void ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
Definition: ginutil.c:651
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
uint16 OffsetNumber
Definition: off.h:24
int16 attnum
Definition: pg_attribute.h:74
uintptr_t Datum
Definition: postgres.h:64
MemoryContextSwitchTo(old_ctx)
#define RelationGetRelationName(relation)
Definition: rel.h:539
@ MAIN_FORKNUM
Definition: relpath.h:58
GinState * ginstate
Definition: gin_private.h:433
double indtuples
Definition: gininsert.c:30
GinState ginstate
Definition: gininsert.c:29
MemoryContext tmpCtx
Definition: gininsert.c:32
GinStatsData buildStats
Definition: gininsert.c:31
MemoryContext funcCtx
Definition: gininsert.c:33
BuildAccumulator accum
Definition: gininsert.c:34
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:1784
void log_newpage_range(Relation rel, ForkNumber forknum, BlockNumber startblk, BlockNumber endblk, bool page_std)
Definition: xloginsert.c:1270

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 433 of file gininsert.c.

434 {
435  Buffer RootBuffer,
436  MetaBuffer;
437 
438  /* An empty GIN index has two pages. */
439  MetaBuffer = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM, NULL,
441  RootBuffer = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM, NULL,
443 
444  /* Initialize and xlog metabuffer and root buffer. */
446  GinInitMetabuffer(MetaBuffer);
447  MarkBufferDirty(MetaBuffer);
448  log_newpage_buffer(MetaBuffer, true);
449  GinInitBuffer(RootBuffer, GIN_LEAF);
450  MarkBufferDirty(RootBuffer);
451  log_newpage_buffer(RootBuffer, false);
453 
454  /* Unlock and release the buffers. */
455  UnlockReleaseBuffer(MetaBuffer);
456  UnlockReleaseBuffer(RootBuffer);
457 }
Buffer ExtendBufferedRel(BufferManagerRelation bmr, ForkNumber forkNum, BufferAccessStrategy strategy, uint32 flags)
Definition: bufmgr.c:846
@ EB_SKIP_EXTENSION_LOCK
Definition: bufmgr.h:74
@ EB_LOCK_FIRST
Definition: bufmgr.h:86
#define BMR_REL(p_rel)
Definition: bufmgr.h:107
@ INIT_FORKNUM
Definition: relpath.h:61
XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std)
Definition: xloginsert.c:1237

References BMR_REL, EB_LOCK_FIRST, EB_SKIP_EXTENSION_LOCK, END_CRIT_SECTION, ExtendBufferedRel(), GIN_LEAF, GinInitBuffer(), GinInitMetabuffer(), INIT_FORKNUM, log_newpage_buffer(), MarkBufferDirty(), START_CRIT_SECTION, and UnlockReleaseBuffer().

Referenced by ginhandler().

◆ ginbulkdelete()

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

Definition at line 564 of file ginvacuum.c.

566 {
567  Relation index = info->index;
568  BlockNumber blkno = GIN_ROOT_BLKNO;
569  GinVacuumState gvs;
570  Buffer buffer;
571  BlockNumber rootOfPostingTree[BLCKSZ / (sizeof(IndexTupleData) + sizeof(ItemId))];
572  uint32 nRoot;
573 
575  "Gin vacuum temporary context",
577  gvs.index = index;
578  gvs.callback = callback;
579  gvs.callback_state = callback_state;
580  gvs.strategy = info->strategy;
581  initGinState(&gvs.ginstate, index);
582 
583  /* first time through? */
584  if (stats == NULL)
585  {
586  /* Yes, so initialize stats to zeroes */
588 
589  /*
590  * and cleanup any pending inserts
591  */
593  false, true, stats);
594  }
595 
596  /* we'll re-count the tuples each time */
597  stats->num_index_tuples = 0;
598  gvs.result = stats;
599 
600  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
601  RBM_NORMAL, info->strategy);
602 
603  /* find leaf page */
604  for (;;)
605  {
606  Page page = BufferGetPage(buffer);
607  IndexTuple itup;
608 
609  LockBuffer(buffer, GIN_SHARE);
610 
611  Assert(!GinPageIsData(page));
612 
613  if (GinPageIsLeaf(page))
614  {
615  LockBuffer(buffer, GIN_UNLOCK);
616  LockBuffer(buffer, GIN_EXCLUSIVE);
617 
618  if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page))
619  {
620  LockBuffer(buffer, GIN_UNLOCK);
621  continue; /* check it one more */
622  }
623  break;
624  }
625 
627 
628  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber));
629  blkno = GinGetDownlink(itup);
630  Assert(blkno != InvalidBlockNumber);
631 
632  UnlockReleaseBuffer(buffer);
633  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
634  RBM_NORMAL, info->strategy);
635  }
636 
637  /* right now we found leftmost page in entry's BTree */
638 
639  for (;;)
640  {
641  Page page = BufferGetPage(buffer);
642  Page resPage;
643  uint32 i;
644 
645  Assert(!GinPageIsData(page));
646 
647  resPage = ginVacuumEntryPage(&gvs, buffer, rootOfPostingTree, &nRoot);
648 
649  blkno = GinPageGetOpaque(page)->rightlink;
650 
651  if (resPage)
652  {
654  PageRestoreTempPage(resPage, page);
655  MarkBufferDirty(buffer);
656  xlogVacuumPage(gvs.index, buffer);
657  UnlockReleaseBuffer(buffer);
659  }
660  else
661  {
662  UnlockReleaseBuffer(buffer);
663  }
664 
666 
667  for (i = 0; i < nRoot; i++)
668  {
669  ginVacuumPostingTree(&gvs, rootOfPostingTree[i]);
671  }
672 
673  if (blkno == InvalidBlockNumber) /* rightmost page */
674  break;
675 
676  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
677  RBM_NORMAL, info->strategy);
678  LockBuffer(buffer, GIN_EXCLUSIVE);
679  }
680 
682 
683  return gvs.result;
684 }
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:5158
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:793
@ RBM_NORMAL
Definition: bufmgr.h:45
static Item PageGetItem(Page page, ItemId itemId)
Definition: bufpage.h:354
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:243
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:372
#define GIN_UNLOCK
Definition: gin_private.h:49
#define GIN_EXCLUSIVE
Definition: gin_private.h:51
#define GIN_SHARE
Definition: gin_private.h:50
#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:780
static void xlogVacuumPage(Relation index, Buffer buffer)
Definition: ginvacuum.c:89
static void ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
Definition: ginvacuum.c:408
static Page ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
Definition: ginvacuum.c:455
int i
Definition: isn.c:72
IndexTupleData * IndexTuple
Definition: itup.h:53
struct IndexTupleData IndexTupleData
void * palloc0(Size size)
Definition: mcxt.c:1347
#define AmAutoVacuumWorkerProcess()
Definition: miscadmin.h:373
#define FirstOffsetNumber
Definition: off.h:27
MemoryContext tmpCxt
Definition: ginvacuum.c:35
BufferAccessStrategy strategy
Definition: ginvacuum.c:34
IndexBulkDeleteCallback callback
Definition: ginvacuum.c:31
IndexBulkDeleteResult * result
Definition: ginvacuum.c:30
void * callback_state
Definition: ginvacuum.c:32
GinState ginstate
Definition: ginvacuum.c:33
Relation index
Definition: ginvacuum.c:29
double num_index_tuples
Definition: genam.h:79
Relation index
Definition: genam.h:46
BufferAccessStrategy strategy
Definition: genam.h:53
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:46
void vacuum_delay_point(void)
Definition: vacuum.c:2362

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, AmAutoVacuumWorkerProcess, 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, 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 411 of file ginutil.c.

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

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 389 of file ginutil.c.

392 {
393  /* if not of same null category, sort by that first */
394  if (categorya != categoryb)
395  return (categorya < categoryb) ? -1 : 1;
396 
397  /* all null items in same category are equal */
398  if (categorya != GIN_CAT_NORM_KEY)
399  return 0;
400 
401  /* both not null, so safe to call the compareFn */
402  return DatumGetInt32(FunctionCall2Coll(&ginstate->compareFn[attnum - 1],
403  ginstate->supportCollation[attnum - 1],
404  a, b));
405 }
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1149
#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:88
FmgrInfo compareFn[INDEX_MAX_KEYS]
Definition: gin_private.h:79

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

489 {
490  uint64 ia = (uint64) GinItemPointerGetBlockNumber(a) << 32 | GinItemPointerGetOffsetNumber(a);
491  uint64 ib = (uint64) GinItemPointerGetBlockNumber(b) << 32 | GinItemPointerGetOffsetNumber(b);
492 
493  return pg_cmp_u64(ia, ib);
494 }
#define GinItemPointerGetOffsetNumber(pointer)
Definition: ginblock.h:146
#define GinItemPointerGetBlockNumber(pointer)
Definition: ginblock.h:143
static int pg_cmp_u64(uint64 a, uint64 b)
Definition: int.h:616

References a, b, GinItemPointerGetBlockNumber, GinItemPointerGetOffsetNumber, and pg_cmp_u64().

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:798
#define SHORTALIGN(LEN)
Definition: c.h:786
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:689
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
static char * buf
Definition: pg_test_fsync.c:72
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 1349 of file gindatapage.c.

1350 {
1351  PostingItem li,
1352  ri;
1353 
1354  li.key = *GinDataPageGetRightBound(lpage);
1355  PostingItemSetBlockNumber(&li, lblkno);
1357 
1358  ri.key = *GinDataPageGetRightBound(rpage);
1359  PostingItemSetBlockNumber(&ri, rblkno);
1361 }
#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
tree ctl root
Definition: radixtree.h:1886
ItemPointerData key
Definition: ginblock.h:186

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

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:584
static int ginCompareItemPointers(ItemPointer a, ItemPointer b)
Definition: gin_private.h:488
#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:377

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 455 of file ginscan.c.

456 {
457  GinScanOpaque so = (GinScanOpaque) scan->opaque;
458 
459  ginFreeScanKeys(so);
460 
463 
464  pfree(so);
465 }
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 723 of file ginentrypage.c.

726 {
727  IndexTuple itup;
728 
729  itup = GinFormInteriorTuple(getRightMostTuple(lpage), lpage, lblkno);
730  if (PageAddItem(root, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
731  elog(ERROR, "failed to add item to index root page");
732  pfree(itup);
733 
734  itup = GinFormInteriorTuple(getRightMostTuple(rpage), rpage, rblkno);
735  if (PageAddItem(root, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
736  elog(ERROR, "failed to add item to index root page");
737  pfree(itup);
738 }
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:471
static IndexTuple getRightMostTuple(Page page)
Definition: ginentrypage.c:235
static IndexTuple GinFormInteriorTuple(IndexTuple itup, Page page, BlockNumber childblk)
Definition: ginentrypage.c:201
Pointer Item
Definition: item.h:17
#define IndexTupleSize(itup)
Definition: itup.h:70

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

Referenced by ginPrepareEntryScan().

◆ ginEntryInsert()

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

Definition at line 176 of file gininsert.c.

180 {
181  GinBtreeData btree;
182  GinBtreeEntryInsertData insertdata;
183  GinBtreeStack *stack;
184  IndexTuple itup;
185  Page page;
186 
187  insertdata.isDelete = false;
188 
189  ginPrepareEntryScan(&btree, attnum, key, category, ginstate);
190  btree.isBuild = (buildStats != NULL);
191 
192  stack = ginFindLeafPage(&btree, false, false);
193  page = BufferGetPage(stack->buffer);
194 
195  if (btree.findItem(&btree, stack))
196  {
197  /* found pre-existing entry */
198  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off));
199 
200  if (GinIsPostingTree(itup))
201  {
202  /* add entries to existing posting tree */
203  BlockNumber rootPostingTree = GinGetPostingTree(itup);
204 
205  /* release all stack */
206  LockBuffer(stack->buffer, GIN_UNLOCK);
207  freeGinBtreeStack(stack);
208 
209  /* insert into posting tree */
210  ginInsertItemPointers(ginstate->index, rootPostingTree,
211  items, nitem,
212  buildStats);
213  return;
214  }
215 
216  CheckForSerializableConflictIn(ginstate->index, NULL,
217  BufferGetBlockNumber(stack->buffer));
218  /* modify an existing leaf entry */
219  itup = addItemPointersToLeafTuple(ginstate, itup,
220  items, nitem, buildStats, stack->buffer);
221 
222  insertdata.isDelete = true;
223  }
224  else
225  {
226  CheckForSerializableConflictIn(ginstate->index, NULL,
227  BufferGetBlockNumber(stack->buffer));
228  /* no match, so construct a new leaf entry */
229  itup = buildFreshLeafTuple(ginstate, attnum, key, category,
230  items, nitem, buildStats, stack->buffer);
231 
232  /*
233  * nEntries counts leaf tuples, so increment it only when we make a
234  * new one.
235  */
236  if (buildStats)
237  buildStats->nEntries++;
238  }
239 
240  /* Insert the new or modified leaf tuple */
241  insertdata.entry = itup;
242  ginInsertValue(&btree, stack, &insertdata, buildStats);
243  pfree(itup);
244 }
#define GinIsPostingTree(itup)
Definition: ginblock.h:231
#define GinGetPostingTree(itup)
Definition: ginblock.h:233
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:198
void ginInsertValue(GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
Definition: ginbtree.c:816
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, bool rootConflictCheck)
Definition: ginbtree.c:83
void ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum, Datum key, GinNullCategory category, GinState *ginstate)
Definition: ginentrypage.c:747
static IndexTuple addItemPointersToLeafTuple(GinState *ginstate, IndexTuple old, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats, Buffer buffer)
Definition: gininsert.c:46
static IndexTuple buildFreshLeafTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats, Buffer buffer)
Definition: gininsert.c:126
void CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno)
Definition: predicate.c:4326
bool(* findItem)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:156
OffsetNumber off
Definition: gin_private.h:133
Relation index
Definition: gin_private.h:59
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, items, 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 484 of file ginutil.c.

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

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 
)

Definition at line 83 of file ginbtree.c.

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

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

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 44 of file ginentrypage.c.

48 {
49  Datum datums[2];
50  bool isnull[2];
51  IndexTuple itup;
52  uint32 newsize;
53 
54  /* Build the basic tuple: optional column number, plus key datum */
55  if (ginstate->oneCol)
56  {
57  datums[0] = key;
58  isnull[0] = (category != GIN_CAT_NORM_KEY);
59  }
60  else
61  {
62  datums[0] = UInt16GetDatum(attnum);
63  isnull[0] = false;
64  datums[1] = key;
65  isnull[1] = (category != GIN_CAT_NORM_KEY);
66  }
67 
68  itup = index_form_tuple(ginstate->tupdesc[attnum - 1], datums, isnull);
69 
70  /*
71  * Determine and store offset to the posting list, making sure there is
72  * room for the category byte if needed.
73  *
74  * Note: because index_form_tuple MAXALIGNs the tuple size, there may well
75  * be some wasted pad space. Is it worth recomputing the data length to
76  * prevent that? That would also allow us to Assert that the real data
77  * doesn't overlap the GinNullCategory byte, which this code currently
78  * takes on faith.
79  */
80  newsize = IndexTupleSize(itup);
81 
82  if (IndexTupleHasNulls(itup))
83  {
84  uint32 minsize;
85 
86  Assert(category != GIN_CAT_NORM_KEY);
87  minsize = GinCategoryOffset(itup, ginstate) + sizeof(GinNullCategory);
88  newsize = Max(newsize, minsize);
89  }
90 
91  newsize = SHORTALIGN(newsize);
92 
93  GinSetPostingOffset(itup, newsize);
94  GinSetNPosting(itup, nipd);
95 
96  /*
97  * Add space needed for posting list, if any. Then check that the tuple
98  * won't be too big to store.
99  */
100  newsize += dataSize;
101 
102  newsize = MAXALIGN(newsize);
103 
104  if (newsize > GinMaxItemSize)
105  {
106  if (errorTooBig)
107  ereport(ERROR,
108  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
109  errmsg("index row size %zu exceeds maximum %zu for index \"%s\"",
110  (Size) newsize, (Size) GinMaxItemSize,
111  RelationGetRelationName(ginstate->index))));
112  pfree(itup);
113  return NULL;
114  }
115 
116  /*
117  * Resize tuple if needed
118  */
119  if (newsize != IndexTupleSize(itup))
120  {
121  itup = repalloc(itup, newsize);
122 
123  /*
124  * PostgreSQL 9.3 and earlier did not clear this new space, so we
125  * might find uninitialized padding when reading tuples from disk.
126  */
127  memset((char *) itup + IndexTupleSize(itup),
128  0, newsize - IndexTupleSize(itup));
129  /* set new size in tuple header */
130  itup->t_info &= ~INDEX_SIZE_MASK;
131  itup->t_info |= newsize;
132  }
133 
134  /*
135  * Copy in the posting list, if provided
136  */
137  if (data)
138  {
139  char *ptr = GinGetPosting(itup);
140 
141  memcpy(ptr, data, dataSize);
142  }
143 
144  /*
145  * Insert category byte, if needed
146  */
147  if (category != GIN_CAT_NORM_KEY)
148  {
149  Assert(IndexTupleHasNulls(itup));
150  GinSetNullCategory(itup, ginstate, category);
151  }
152  return itup;
153 }
#define MAXALIGN(LEN)
Definition: c.h:790
#define Max(x, y)
Definition: c.h:977
#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, const Datum *values, const 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:1541
static Datum UInt16GetDatum(uint16 X)
Definition: postgres.h:192
bool oneCol
Definition: gin_private.h:60
TupleDesc tupdesc[INDEX_MAX_KEYS]
Definition: gin_private.h:74
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 }
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
TIDBitmap * matchBitmap
Definition: gin_private.h:354
ItemPointerData * list
Definition: gin_private.h:359
TBMIterator * matchIterator
Definition: gin_private.h:355
GinScanEntry * entries
Definition: gin_private.h:377
void tbm_free(TIDBitmap *tbm)
Definition: tidbitmap.c:322
void tbm_end_iterate(TBMIterator *iterator)
Definition: tidbitmap.c:1146

References GinScanEntryData::buffer, GinScanOpaqueData::entries, i, InvalidBuffer, GinScanOpaqueData::keyCtx, GinScanOpaqueData::keys, GinScanEntryData::list, GinScanEntryData::matchBitmap, GinScanEntryData::matchIterator, MemoryContextReset(), 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:447
RBTNode * rbt_iterate(RBTreeIterator *iter)
Definition: rbtree.c:826
OffsetNumber attnum
Definition: gin_private.h:424
ItemPointerData * list
Definition: gin_private.h:426
GinNullCategory category
Definition: gin_private.h:423

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 1914 of file ginget.c.

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

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 483 of file ginfast.c.

487 {
488  Datum *entries;
489  GinNullCategory *categories;
490  int32 i,
491  nentries;
492 
493  /*
494  * Extract the key values that need to be inserted in the index
495  */
496  entries = ginExtractEntries(ginstate, attnum, value, isNull,
497  &nentries, &categories);
498 
499  /*
500  * Protect against integer overflow in allocation calculations
501  */
502  if (nentries < 0 ||
503  collector->ntuples + nentries > MaxAllocSize / sizeof(IndexTuple))
504  elog(ERROR, "too many entries for GIN index");
505 
506  /*
507  * Allocate/reallocate memory for storing collected tuples
508  */
509  if (collector->tuples == NULL)
510  {
511  /*
512  * Determine the number of elements to allocate in the tuples array
513  * initially. Make it a power of 2 to avoid wasting memory when
514  * resizing (since palloc likes powers of 2).
515  */
516  collector->lentuples = pg_nextpower2_32(Max(16, nentries));
517  collector->tuples = palloc_array(IndexTuple, collector->lentuples);
518  }
519  else if (collector->lentuples < collector->ntuples + nentries)
520  {
521  /*
522  * Advance lentuples to the next suitable power of 2. This won't
523  * overflow, though we could get to a value that exceeds
524  * MaxAllocSize/sizeof(IndexTuple), causing an error in repalloc.
525  */
526  collector->lentuples = pg_nextpower2_32(collector->ntuples + nentries);
527  collector->tuples = repalloc_array(collector->tuples,
528  IndexTuple, collector->lentuples);
529  }
530 
531  /*
532  * Build an index tuple for each key value, and add to array. In pending
533  * tuples we just stick the heap TID into t_tid.
534  */
535  for (i = 0; i < nentries; i++)
536  {
537  IndexTuple itup;
538 
539  itup = GinFormTuple(ginstate, attnum, entries[i], categories[i],
540  NULL, 0, 0, true);
541  itup->t_tid = *ht_ctid;
542  collector->tuples[collector->ntuples++] = itup;
543  collector->sumsize += IndexTupleSize(itup);
544  }
545 }
#define MaxAllocSize
Definition: fe_memutils.h:22
#define repalloc_array(pointer, type, count)
Definition: fe_memutils.h:78
#define palloc_array(type, count)
Definition: fe_memutils.h:76
IndexTuple GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, Pointer data, Size dataSize, int nipd, bool errorTooBig)
Definition: ginentrypage.c:44
Datum * ginExtractEntries(GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, int32 *nentries, GinNullCategory **categories)
Definition: ginutil.c:484
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:189
IndexTuple * tuples
Definition: gin_private.h:455
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. Therefore we'll
249  * check for conflicts in, but not until we have the page locked and are
250  * ready to modify the page.
251  */
252 
253  if (collector->sumsize + collector->ntuples * sizeof(ItemIdData) > GinListPageSize)
254  {
255  /*
256  * Total size is greater than one page => make sublist
257  */
258  separateList = true;
259  }
260  else
261  {
262  LockBuffer(metabuffer, GIN_EXCLUSIVE);
263  metadata = GinPageGetMeta(metapage);
264 
265  if (metadata->head == InvalidBlockNumber ||
266  collector->sumsize + collector->ntuples * sizeof(ItemIdData) > metadata->tailFreeSize)
267  {
268  /*
269  * Pending list is empty or total size is greater than freespace
270  * on tail page => make sublist
271  *
272  * We unlock metabuffer to keep high concurrency
273  */
274  separateList = true;
275  LockBuffer(metabuffer, GIN_UNLOCK);
276  }
277  }
278 
279  if (separateList)
280  {
281  /*
282  * We should make sublist separately and append it to the tail
283  */
284  GinMetaPageData sublist;
285 
286  memset(&sublist, 0, sizeof(GinMetaPageData));
287  makeSublist(index, collector->tuples, collector->ntuples, &sublist);
288 
289  /*
290  * metapage was unlocked, see above
291  */
292  LockBuffer(metabuffer, GIN_EXCLUSIVE);
293  metadata = GinPageGetMeta(metapage);
294 
296 
297  if (metadata->head == InvalidBlockNumber)
298  {
299  /*
300  * Main list is empty, so just insert sublist as main list
301  */
303 
304  metadata->head = sublist.head;
305  metadata->tail = sublist.tail;
306  metadata->tailFreeSize = sublist.tailFreeSize;
307 
308  metadata->nPendingPages = sublist.nPendingPages;
309  metadata->nPendingHeapTuples = sublist.nPendingHeapTuples;
310 
311  if (needWal)
312  XLogBeginInsert();
313  }
314  else
315  {
316  /*
317  * Merge lists
318  */
319  data.prevTail = metadata->tail;
320  data.newRightlink = sublist.head;
321 
322  buffer = ReadBuffer(index, metadata->tail);
323  LockBuffer(buffer, GIN_EXCLUSIVE);
324  page = BufferGetPage(buffer);
325 
326  Assert(GinPageGetOpaque(page)->rightlink == InvalidBlockNumber);
327 
329 
330  GinPageGetOpaque(page)->rightlink = sublist.head;
331 
332  MarkBufferDirty(buffer);
333 
334  metadata->tail = sublist.tail;
335  metadata->tailFreeSize = sublist.tailFreeSize;
336 
337  metadata->nPendingPages += sublist.nPendingPages;
338  metadata->nPendingHeapTuples += sublist.nPendingHeapTuples;
339 
340  if (needWal)
341  {
342  XLogBeginInsert();
344  }
345  }
346  }
347  else
348  {
349  /*
350  * Insert into tail page. Metapage is already locked
351  */
352  OffsetNumber l,
353  off;
354  int i,
355  tupsize;
356  char *ptr;
357  char *collectordata;
358 
360 
361  buffer = ReadBuffer(index, metadata->tail);
362  LockBuffer(buffer, GIN_EXCLUSIVE);
363  page = BufferGetPage(buffer);
364 
365  off = (PageIsEmpty(page)) ? FirstOffsetNumber :
367 
368  collectordata = ptr = (char *) palloc(collector->sumsize);
369 
370  data.ntuples = collector->ntuples;
371 
373 
374  if (needWal)
375  XLogBeginInsert();
376 
377  /*
378  * Increase counter of heap tuples
379  */
380  Assert(GinPageGetOpaque(page)->maxoff <= metadata->nPendingHeapTuples);
381  GinPageGetOpaque(page)->maxoff++;
382  metadata->nPendingHeapTuples++;
383 
384  for (i = 0; i < collector->ntuples; i++)
385  {
386  tupsize = IndexTupleSize(collector->tuples[i]);
387  l = PageAddItem(page, (Item) collector->tuples[i], tupsize, off, false, false);
388 
389  if (l == InvalidOffsetNumber)
390  elog(ERROR, "failed to add item to index page in \"%s\"",
392 
393  memcpy(ptr, collector->tuples[i], tupsize);
394  ptr += tupsize;
395 
396  off++;
397  }
398 
399  Assert((ptr - collectordata) <= collector->sumsize);
400 
401  MarkBufferDirty(buffer);
402 
403  if (needWal)
404  {
406  XLogRegisterBufData(1, collectordata, collector->sumsize);
407  }
408 
409  metadata->tailFreeSize = PageGetExactFreeSpace(page);
410  }
411 
412  /*
413  * Set pd_lower just past the end of the metadata. This is essential,
414  * because without doing so, metadata will be lost if xlog.c compresses
415  * the page. (We must do this here because pre-v11 versions of PG did not
416  * set the metapage's pd_lower correctly, so a pg_upgraded index might
417  * contain the wrong value.)
418  */
419  ((PageHeader) metapage)->pd_lower =
420  ((char *) metadata + sizeof(GinMetaPageData)) - (char *) metapage;
421 
422  /*
423  * Write metabuffer, make xlog entry
424  */
425  MarkBufferDirty(metabuffer);
426 
427  if (needWal)
428  {
429  XLogRecPtr recptr;
430 
431  memcpy(&data.metadata, metadata, sizeof(GinMetaPageData));
432 
434  XLogRegisterData((char *) &data, sizeof(ginxlogUpdateMeta));
435 
436  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_UPDATE_META_PAGE);
437  PageSetLSN(metapage, recptr);
438 
439  if (buffer != InvalidBuffer)
440  {
441  PageSetLSN(page, recptr);
442  }
443  }
444 
445  if (buffer != InvalidBuffer)
446  UnlockReleaseBuffer(buffer);
447 
448  /*
449  * Force pending list cleanup when it becomes too long. And,
450  * ginInsertCleanup could take significant amount of time, so we prefer to
451  * call it when it can do all the work in a single collection cycle. In
452  * non-vacuum mode, it shouldn't require maintenance_work_mem, so fire it
453  * while pending list is still small enough to fit into
454  * gin_pending_list_limit.
455  *
456  * ginInsertCleanup() should not be called inside our CRIT_SECTION.
457  */
458  cleanupSize = GinGetPendingListCleanupSize(index);
459  if (metadata->nPendingPages * GIN_PAGE_FREESIZE > cleanupSize * 1024L)
460  needCleanup = true;
461 
462  UnlockReleaseBuffer(metabuffer);
463 
465 
466  /*
467  * Since it could contend with concurrent cleanup process we cleanup
468  * pending list not forcibly.
469  */
470  if (needCleanup)
471  ginInsertCleanup(ginstate, false, true, false, NULL);
472 }
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:947
PageHeaderData * PageHeader
Definition: bufpage.h:173
static bool PageIsEmpty(Page page)
Definition: bufpage.h:223
#define GinGetPendingListCleanupSize(relation)
Definition: gin_private.h:39
#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, const char *data, uint32 len)
Definition: xloginsert.c:405
#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  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:435

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 351 of file ginutil.c.

352 {
354 }
static Size BufferGetPageSize(Buffer buffer)
Definition: bufmgr.h:389

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 217 of file ginlogic.c.

218 {
219  if (key->searchMode == GIN_SEARCH_MODE_EVERYTHING)
220  {
221  key->boolConsistentFn = trueConsistentFn;
222  key->triConsistentFn = trueTriConsistentFn;
223  }
224  else
225  {
226  key->consistentFmgrInfo = &ginstate->consistentFn[key->attnum - 1];
227  key->triConsistentFmgrInfo = &ginstate->triConsistentFn[key->attnum - 1];
228  key->collation = ginstate->supportCollation[key->attnum - 1];
229 
230  if (OidIsValid(ginstate->consistentFn[key->attnum - 1].fn_oid))
231  key->boolConsistentFn = directBoolConsistentFn;
232  else
233  key->boolConsistentFn = shimBoolConsistentFn;
234 
235  if (OidIsValid(ginstate->triConsistentFn[key->attnum - 1].fn_oid))
236  key->triConsistentFn = directTriConsistentFn;
237  else
238  key->triConsistentFn = shimTriConsistentFn;
239  }
240 }
#define OidIsValid(objectId)
Definition: c.h:754
#define GIN_SEARCH_MODE_EVERYTHING
Definition: gin.h:37
static GinTernaryValue trueTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:56
static GinTernaryValue shimTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:146
static GinTernaryValue directTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:89
static bool trueConsistentFn(GinScanKey key)
Definition: ginlogic.c:50
static bool directBoolConsistentFn(GinScanKey key)
Definition: ginlogic.c:65
static bool shimBoolConsistentFn(GinScanKey key)
Definition: ginlogic.c:108
Oid fn_oid
Definition: fmgr.h:59
FmgrInfo triConsistentFn[INDEX_MAX_KEYS]
Definition: gin_private.h:83
FmgrInfo consistentFn[INDEX_MAX_KEYS]
Definition: gin_private.h:82

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 357 of file ginutil.c.

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

340 {
341  GinPageOpaque opaque;
342 
343  PageInit(page, pageSize, sizeof(GinPageOpaqueData));
344 
345  opaque = GinPageGetOpaque(page);
346  opaque->flags = f;
347  opaque->rightlink = InvalidBlockNumber;
348 }
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 482 of file gininsert.c.

487 {
488  GinState *ginstate = (GinState *) indexInfo->ii_AmCache;
489  MemoryContext oldCtx;
490  MemoryContext insertCtx;
491  int i;
492 
493  /* Initialize GinState cache if first call in this statement */
494  if (ginstate == NULL)
495  {
496  oldCtx = MemoryContextSwitchTo(indexInfo->ii_Context);
497  ginstate = (GinState *) palloc(sizeof(GinState));
498  initGinState(ginstate, index);
499  indexInfo->ii_AmCache = ginstate;
500  MemoryContextSwitchTo(oldCtx);
501  }
502 
504  "Gin insert temporary context",
506 
507  oldCtx = MemoryContextSwitchTo(insertCtx);
508 
510  {
511  GinTupleCollector collector;
512 
513  memset(&collector, 0, sizeof(GinTupleCollector));
514 
515  for (i = 0; i < ginstate->origTupdesc->natts; i++)
516  ginHeapTupleFastCollect(ginstate, &collector,
517  (OffsetNumber) (i + 1),
518  values[i], isnull[i],
519  ht_ctid);
520 
521  ginHeapTupleFastInsert(ginstate, &collector);
522  }
523  else
524  {
525  for (i = 0; i < ginstate->origTupdesc->natts; i++)
526  ginHeapTupleInsert(ginstate, (OffsetNumber) (i + 1),
527  values[i], isnull[i],
528  ht_ctid);
529  }
530 
531  MemoryContextSwitchTo(oldCtx);
532  MemoryContextDelete(insertCtx);
533 
534  return false;
535 }
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define GinGetUseFastUpdate(relation)
Definition: gin_private.h:34
void ginHeapTupleFastCollect(GinState *ginstate, GinTupleCollector *collector, OffsetNumber attnum, Datum value, bool isNull, ItemPointer ht_ctid)
Definition: ginfast.c:483
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:464
TupleDesc origTupdesc
Definition: gin_private.h:73
void * ii_AmCache
Definition: execnodes.h:210
MemoryContext ii_Context
Definition: execnodes.h:211

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 780 of file ginfast.c.

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

References BuildAccumulator::allocatedMemory, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, AmAutoVacuumWorkerProcess, 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, 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 1908 of file gindatapage.c.

1911 {
1912  GinBtreeData btree;
1913  GinBtreeDataLeafInsertData insertdata;
1914  GinBtreeStack *stack;
1915 
1916  ginPrepareDataScan(&btree, index, rootBlkno);
1917  btree.isBuild = (buildStats != NULL);
1918  insertdata.items = items;
1919  insertdata.nitem = nitem;
1920  insertdata.curitem = 0;
1921 
1922  while (insertdata.curitem < insertdata.nitem)
1923  {
1924  /* search for the leaf page where the first item should go to */
1925  btree.itemptr = insertdata.items[insertdata.curitem];
1926  stack = ginFindLeafPage(&btree, false, true);
1927 
1928  ginInsertValue(&btree, stack, &insertdata, buildStats);
1929  }
1930 }
static void ginPrepareDataScan(GinBtree btree, Relation index, BlockNumber rootBlkno)
Definition: gindatapage.c:1882
ItemPointerData * items
Definition: gin_private.h:195
ItemPointerData itemptr
Definition: gin_private.h:179

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

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

◆ ginInsertValue()

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

Definition at line 816 of file ginbtree.c.

818 {
819  bool done;
820 
821  /* If the leaf page was incompletely split, finish the split first */
823  ginFinishOldSplit(btree, stack, buildStats, GIN_EXCLUSIVE);
824 
825  done = ginPlaceToPage(btree, stack,
826  insertdata, InvalidBlockNumber,
827  InvalidBuffer, buildStats);
828  if (done)
829  {
830  LockBuffer(stack->buffer, GIN_UNLOCK);
831  freeGinBtreeStack(stack);
832  }
833  else
834  ginFinishSplit(btree, stack, true, buildStats);
835 }
static bool ginPlaceToPage(GinBtree btree, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, Buffer childbuf, GinStatsData *buildStats)
Definition: ginbtree.c:337
static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack, GinStatsData *buildStats)
Definition: ginbtree.c:672

References GinBtreeStack::buffer, BufferGetPage(), freeGinBtreeStack(), GIN_EXCLUSIVE, GIN_UNLOCK, ginFinishOldSplit(), 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:743

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

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

◆ GinNewBuffer()

Buffer GinNewBuffer ( Relation  index)

Definition at line 301 of file ginutil.c.

302 {
303  Buffer buffer;
304 
305  /* First, try to get a page from FSM */
306  for (;;)
307  {
309 
310  if (blkno == InvalidBlockNumber)
311  break;
312 
313  buffer = ReadBuffer(index, blkno);
314 
315  /*
316  * We have to guard against the possibility that someone else already
317  * recycled this page; the buffer may be locked if so.
318  */
319  if (ConditionalLockBuffer(buffer))
320  {
321  if (GinPageIsRecyclable(BufferGetPage(buffer)))
322  return buffer; /* OK to use */
323 
324  LockBuffer(buffer, GIN_UNLOCK);
325  }
326 
327  /* Can't use it, so release buffer and try again */
328  ReleaseBuffer(buffer);
329  }
330 
331  /* Must extend the file */
332  buffer = ExtendBufferedRel(BMR_REL(index), MAIN_FORKNUM, NULL,
333  EB_LOCK_FIRST);
334 
335  return buffer;
336 }
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:5184
bool GinPageIsRecyclable(Page page)
Definition: ginvacuum.c:801
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38

References BMR_REL, BufferGetPage(), ConditionalLockBuffer(), EB_LOCK_FIRST, ExtendBufferedRel(), GetFreeIndexPage(), GIN_UNLOCK, GinPageIsRecyclable(), InvalidBlockNumber, LockBuffer(), MAIN_FORKNUM, ReadBuffer(), and ReleaseBuffer().

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:1317
Datum FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7)
Definition: fmgr.c:1284
#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:264
#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:624
#define INDEX_MAX_KEYS
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:664
#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:145
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 603 of file ginutil.c.

604 {
605  static const relopt_parse_elt tab[] = {
606  {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)},
607  {"gin_pending_list_limit", RELOPT_TYPE_INT, offsetof(GinOptions,
608  pendingListCleanupSize)}
609  };
610 
611  return (bytea *) build_reloptions(reloptions, validate,
613  sizeof(GinOptions),
614  tab, lengthof(tab));
615 }
#define lengthof(array)
Definition: c.h:767
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:1908
@ RELOPT_KIND_GIN
Definition: reloptions.h:46
@ RELOPT_TYPE_INT
Definition: reloptions.h:32
@ RELOPT_TYPE_BOOL
Definition: reloptions.h:31
Definition: c.h:666

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;
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(), items, 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 747 of file ginentrypage.c.

750 {
751  memset(btree, 0, sizeof(GinBtreeData));
752 
753  btree->index = ginstate->index;
754  btree->rootBlkno = GIN_ROOT_BLKNO;
755  btree->ginstate = ginstate;
756 
759  btree->isMoveRight = entryIsMoveRight;
764  btree->fillRoot = ginEntryFillRoot;
766 
767  btree->isData = false;
768  btree->fullScan = false;
769  btree->isBuild = false;
770 
771  btree->entryAttnum = attnum;
772  btree->entryKey = key;
773  btree->entryCategory = category;
774 }
void ginEntryFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
Definition: ginentrypage.c:723
static bool entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack)
Definition: ginentrypage.c:346
static bool entryIsMoveRight(GinBtree btree, Page page)
Definition: ginentrypage.c:243
static BlockNumber entryGetLeftMostPage(GinBtree btree, Page page)
Definition: ginentrypage.c:446
static void * entryPrepareDownlink(GinBtree btree, Buffer lbuf)
Definition: ginentrypage.c:702
static OffsetNumber entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
Definition: ginentrypage.c:405
static GinPlaceToPageRC entryBeginPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertPayload, BlockNumber updateblkno, void **ptp_workspace, Page *newlpage, Page *newrpage)
Definition: ginentrypage.c:527
static void entryExecPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertPayload, BlockNumber updateblkno, void *ptp_workspace)
Definition: ginentrypage.c:554
static BlockNumber entryLocateEntry(GinBtree btree, GinBtreeStack *stack)
Definition: ginentrypage.c:270
Datum entryKey
Definition: gin_private.h:175
GinState * ginstate
Definition: gin_private.h:169
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
Definition: gin_private.h:161
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:154
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
Definition: gin_private.h:160
GinNullCategory entryCategory
Definition: gin_private.h:176
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:162
OffsetNumber entryAttnum
Definition: gin_private.h:174
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:159
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
Definition: gin_private.h:163

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 162 of file ginentrypage.c.

164 {
165  Pointer ptr = GinGetPosting(itup);
166  int nipd = GinGetNPosting(itup);
167  ItemPointer ipd;
168  int ndecoded;
169 
170  if (GinItupIsCompressed(itup))
171  {
172  if (nipd > 0)
173  {
174  ipd = ginPostingListDecode((GinPostingList *) ptr, &ndecoded);
175  if (nipd != ndecoded)
176  elog(ERROR, "number of items mismatch in GIN entry tuple, %d in tuple header, %d decoded",
177  nipd, ndecoded);
178  }
179  else
180  {
181  ipd = palloc(0);
182  }
183  }
184  else
185  {
186  ipd = (ItemPointer) palloc(sizeof(ItemPointerData) * nipd);
187  memcpy(ipd, ptr, sizeof(ItemPointerData) * nipd);
188  }
189  *nitems = nipd;
190  return ipd;
191 }
#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  memcpy(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData));
451 }

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

Referenced by ginhandler().

◆ ginScanBeginPostingTree()

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

Definition at line 1936 of file gindatapage.c.

1937 {
1938  GinBtreeStack *stack;
1939 
1940  ginPrepareDataScan(btree, index, rootBlkno);
1941 
1942  btree->fullScan = true;
1943 
1944  stack = ginFindLeafPage(btree, true, false);
1945 
1946  return stack;
1947 }

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

Referenced by scanPostingTree(), and startScanEntry().

◆ ginStepRight()

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

Definition at line 177 of file ginbtree.c.

178 {
179  Buffer nextbuffer;
180  Page page = BufferGetPage(buffer);
181  bool isLeaf = GinPageIsLeaf(page);
182  bool isData = GinPageIsData(page);
183  BlockNumber blkno = GinPageGetOpaque(page)->rightlink;
184 
185  nextbuffer = ReadBuffer(index, blkno);
186  LockBuffer(nextbuffer, lockmode);
187  UnlockReleaseBuffer(buffer);
188 
189  /* Sanity check that the page we stepped to is of similar kind. */
190  page = BufferGetPage(nextbuffer);
191  if (isLeaf != GinPageIsLeaf(page) || isData != GinPageIsData(page))
192  elog(ERROR, "right sibling of GIN page is of different type");
193 
194  return nextbuffer;
195 }

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 39 of file ginbtree.c.

40 {
41  Page page;
42  int access = GIN_SHARE;
43 
44  LockBuffer(buffer, GIN_SHARE);
45  page = BufferGetPage(buffer);
46  if (GinPageIsLeaf(page))
47  {
48  if (searchMode == false)
49  {
50  /* we should relock our page */
51  LockBuffer(buffer, GIN_UNLOCK);
52  LockBuffer(buffer, GIN_EXCLUSIVE);
53 
54  /* But root can become non-leaf during relock */
55  if (!GinPageIsLeaf(page))
56  {
57  /* restore old lock type (very rare) */
58  LockBuffer(buffer, GIN_UNLOCK);
59  LockBuffer(buffer, GIN_SHARE);
60  }
61  else
63  }
64  }
65 
66  return access;
67 }

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 227 of file ginutil.c.

228 {
229  OffsetNumber colN;
230 
231  if (ginstate->oneCol)
232  {
233  /* column number is not stored explicitly */
234  colN = FirstOffsetNumber;
235  }
236  else
237  {
238  Datum res;
239  bool isnull;
240 
241  /*
242  * First attribute is always int16, so we can safely use any tuple
243  * descriptor to obtain first attribute of tuple
244  */
245  res = index_getattr(tuple, FirstOffsetNumber, ginstate->tupdesc[0],
246  &isnull);
247  Assert(!isnull);
248 
249  colN = DatumGetUInt16(res);
250  Assert(colN >= FirstOffsetNumber && colN <= ginstate->origTupdesc->natts);
251  }
252 
253  return colN;
254 }
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 260 of file ginutil.c.

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

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 687 of file ginvacuum.c.

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

References AmAutoVacuumWorkerProcess, 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(), 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 47 of file ginvacuum.c.

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

References GinVacuumState::callback, GinVacuumState::callback_state, i, items, 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 738 of file gindatapage.c.

739 {
740  Page page = BufferGetPage(buffer);
741  disassembledLeaf *leaf;
742  bool removedsomething = false;
743  dlist_iter iter;
744 
745  leaf = disassembleLeaf(page);
746 
747  /* Vacuum each segment. */
748  dlist_foreach(iter, &leaf->segments)
749  {
750  leafSegmentInfo *seginfo = dlist_container(leafSegmentInfo, node, iter.cur);
751  int oldsegsize;
752  ItemPointer cleaned;
753  int ncleaned;
754 
755  if (!seginfo->items)
756  seginfo->items = ginPostingListDecode(seginfo->seg,
757  &seginfo->nitems);
758  if (seginfo->seg)
759  oldsegsize = SizeOfGinPostingList(seginfo->seg);
760  else
761  oldsegsize = GinDataPageMaxDataSize;
762 
763  cleaned = ginVacuumItemPointers(gvs,
764  seginfo->items,
765  seginfo->nitems,
766  &ncleaned);
767  pfree(seginfo->items);
768  seginfo->items = NULL;
769  seginfo->nitems = 0;
770  if (cleaned)
771  {
772  if (ncleaned > 0)
773  {
774  int npacked;
775 
776  seginfo->seg = ginCompressPostingList(cleaned,
777  ncleaned,
778  oldsegsize,
779  &npacked);
780  /* Removing an item never increases the size of the segment */
781  if (npacked != ncleaned)
782  elog(ERROR, "could not fit vacuumed posting list");
783  seginfo->action = GIN_SEGMENT_REPLACE;
784  }
785  else
786  {
787  seginfo->seg = NULL;
788  seginfo->items = NULL;
789  seginfo->action = GIN_SEGMENT_DELETE;
790  }
791  seginfo->nitems = ncleaned;
792 
793  removedsomething = true;
794  }
795  }
796 
797  /*
798  * If we removed any items, reconstruct the page from the pieces.
799  *
800  * We don't try to re-encode the segments here, even though some of them
801  * might be really small now that we've removed some items from them. It
802  * seems like a waste of effort, as there isn't really any benefit from
803  * larger segments per se; larger segments only help to pack more items in
804  * the same space. We might as well delay doing that until the next
805  * insertion, which will need to re-encode at least part of the page
806  * anyway.
807  *
808  * Also note if the page was in uncompressed, pre-9.4 format before, it is
809  * now represented as one huge segment that contains all the items. It
810  * might make sense to split that, to speed up random access, but we don't
811  * bother. You'll have to REINDEX anyway if you want the full gain of the
812  * new tighter index format.
813  */
814  if (removedsomething)
815  {
816  bool modified;
817 
818  /*
819  * Make sure we have a palloc'd copy of all segments, after the first
820  * segment that is modified. (dataPlaceToPageLeafRecompress requires
821  * this).
822  */
823  modified = false;
824  dlist_foreach(iter, &leaf->segments)
825  {
827  iter.cur);
828 
829  if (seginfo->action != GIN_SEGMENT_UNMODIFIED)
830  modified = true;
831  if (modified && seginfo->action != GIN_SEGMENT_DELETE)
832  {
833  int segsize = SizeOfGinPostingList(seginfo->seg);
834  GinPostingList *tmp = (GinPostingList *) palloc(segsize);
835 
836  memcpy(tmp, seginfo->seg, segsize);
837  seginfo->seg = tmp;
838  }
839  }
840 
841  if (RelationNeedsWAL(indexrel))
843 
844  /* Apply changes to page */
846 
847  dataPlaceToPageLeafRecompress(buffer, leaf);
848 
849  MarkBufferDirty(buffer);
850 
851  if (RelationNeedsWAL(indexrel))
852  {
853  XLogRecPtr recptr;
854 
855  XLogBeginInsert();
857  XLogRegisterBufData(0, leaf->walinfo, leaf->walinfolen);
858  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_VACUUM_DATA_LEAF_PAGE);
859  PageSetLSN(page, recptr);
860  }
861 
863  }
864 }
static void dataPlaceToPageLeafRecompress(Buffer buf, disassembledLeaf *leaf)
Definition: gindatapage.c:978
static void computeLeafRecompressWALData(disassembledLeaf *leaf)
Definition: gindatapage.c:872
static disassembledLeaf * disassembleLeaf(Page page)
Definition: gindatapage.c:1370
ItemPointer ginVacuumItemPointers(GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining)
Definition: ginvacuum.c:47
#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 31 of file ginvalidate.c.

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

References check_amop_signature(), check_amoptsproc_signature(), check_amproc_signature(), 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, ReleaseCatCacheList(), ReleaseSysCache(), OpFamilyOpFuncGroup::righttype, SearchSysCache1(), SearchSysCacheList1, and catctup::tuple.

Referenced by ginhandler().

◆ initGinState()

void initGinState ( GinState state,
Relation  index 
)

Definition at line 98 of file ginutil.c.

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

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