PostgreSQL Source Code git master
Loading...
Searching...
No Matches
gin_private.h File Reference
#include "access/amapi.h"
#include "access/gin.h"
#include "access/ginblock.h"
#include "access/htup_details.h"
#include "access/itup.h"
#include "common/int.h"
#include "catalog/pg_am_d.h"
#include "fmgr.h"
#include "lib/rbtree.h"
#include "nodes/tidbitmap.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)
 
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)
 
charginbuildphasename (int64 phasenum)
 
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 ItemPointerData *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 (const ItemPointerData *a, const ItemPointerData *b)
 
static int ginCompareEntries (GinState *ginstate, OffsetNumber attnum, Datum a, GinNullCategory categorya, Datum b, GinNullCategory categoryb)
 
static int ginCompareAttEntries (GinState *ginstate, OffsetNumber attnuma, Datum a, GinNullCategory categorya, OffsetNumber attnumb, Datum b, GinNullCategory categoryb)
 
int ginTraverseLock (Buffer buffer, bool searchMode)
 

Macro Definition Documentation

◆ GIN_DEFAULT_USE_FASTUPDATE

#define GIN_DEFAULT_USE_FASTUPDATE   true

Definition at line 35 of file gin_private.h.

◆ GIN_EXCLUSIVE

#define GIN_EXCLUSIVE   BUFFER_LOCK_EXCLUSIVE

Definition at line 53 of file gin_private.h.

◆ GIN_SHARE

#define GIN_SHARE   BUFFER_LOCK_SHARE

Definition at line 52 of file gin_private.h.

◆ GIN_UNLOCK

#define GIN_UNLOCK   BUFFER_LOCK_UNLOCK

Definition at line 51 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:946
int gin_pending_list_limit
Definition ginfast.c:39
static int fb(int x)

Definition at line 41 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:35

Definition at line 36 of file gin_private.h.

Typedef Documentation

◆ GinBtree

Definition at line 137 of file gin_private.h.

◆ GinBtreeData

◆ GinBtreeStack

◆ GinEntryAccumulator

◆ GinOptions

◆ GinScanEntry

Definition at line 263 of file gin_private.h.

◆ GinScanEntryData

◆ GinScanKey

Definition at line 261 of file gin_private.h.

◆ GinScanKeyData

◆ GinScanOpaque

◆ GinScanOpaqueData

◆ GinState

◆ GinTupleCollector

◆ GinVacuumState

Definition at line 239 of file gin_private.h.

Enumeration Type Documentation

◆ GinPlaceToPageRC

Enumerator
GPTP_NO_WORK 
GPTP_INSERT 
GPTP_SPLIT 

Definition at line 140 of file gin_private.h.

141{
GinPlaceToPageRC
@ GPTP_INSERT
@ GPTP_SPLIT
@ GPTP_NO_WORK

Function Documentation

◆ createPostingTree()

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

Definition at line 1775 of file gindatapage.c.

1777{
1778 BlockNumber blkno;
1779 Buffer buffer;
1780 Page tmppage;
1781 Page page;
1782 char *ptr;
1783 int nrootitems;
1784 int rootsize;
1785 bool is_build = (buildStats != NULL);
1786
1787 /* Construct the new root page in memory first. */
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 = (char *) GinDataLeafPageGetPostingList(tmppage);
1799 while (nrootitems < nitems)
1800 {
1801 GinPostingList *segment;
1802 int npacked;
1803 int segsize;
1804
1808 &npacked);
1809 segsize = SizeOfGinPostingList(segment);
1811 break;
1812
1813 memcpy(ptr, segment, segsize);
1814 ptr += segsize;
1815 rootsize += segsize;
1817 pfree(segment);
1818 }
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 */
1833
1835
1837 MarkBufferDirty(buffer);
1838
1839 if (RelationNeedsWAL(index) && !is_build)
1840 {
1843
1844 data.size = rootsize;
1845
1848
1850 rootsize);
1852
1854 PageSetLSN(page, recptr);
1855 }
1856
1858
1859 UnlockReleaseBuffer(buffer);
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,
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:4357
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5522
void MarkBufferDirty(Buffer buffer)
Definition bufmgr.c:3063
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:470
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition bufpage.c:423
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition bufpage.h:417
PageData * Page
Definition bufpage.h:81
#define DEBUG2
Definition elog.h:29
#define elog(elevel,...)
Definition elog.h:226
#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)
GinPostingList * ginCompressPostingList(const ItemPointerData *ipd, int nipd, int maxsize, int *nwritten)
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition ginutil.c:345
Buffer GinNewBuffer(Relation index)
Definition ginutil.c:307
#define XLOG_GIN_CREATE_PTREE
Definition ginxlog.h:19
#define nitems(x)
Definition indent.h:31
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc(Size size)
Definition mcxt.c:1387
#define START_CRIT_SECTION()
Definition miscadmin.h:150
#define END_CRIT_SECTION()
Definition miscadmin.h:152
const void * data
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition predicate.c:3153
#define RelationNeedsWAL(relation)
Definition rel.h:637
BlockNumber nDataPages
Definition gin.h:60
Definition type.h:96
static ItemArray items
uint64 XLogRecPtr
Definition xlogdefs.h:21
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition xloginsert.c:479
void XLogRegisterData(const void *data, uint32 len)
Definition xloginsert.c:369
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition xloginsert.c:246
void XLogBeginInsert(void)
Definition xloginsert.c:153
#define REGBUF_WILL_INIT
Definition xloginsert.h:34

References BufferGetBlockNumber(), BufferGetPage(), data, DEBUG2, elog, END_CRIT_SECTION, fb(), 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, ginxlogCreatePostingTree::size, SizeOfGinPostingList, START_CRIT_SECTION, UnlockReleaseBuffer(), XLOG_GIN_CREATE_PTREE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by addItemPointersToLeafTuple(), and buildFreshLeafTuple().

◆ freeGinBtreeStack()

void freeGinBtreeStack ( GinBtreeStack stack)
extern

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:5505
struct GinBtreeStack * parent

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 
)
extern

Definition at line 269 of file ginvalidate.c.

273{
274 ListCell *lc;
275
276 /*
277 * Operator members of a GIN opfamily should never have hard dependencies,
278 * since their connection to the opfamily depends only on what the support
279 * functions think, and that can be altered. For consistency, we make all
280 * soft dependencies point to the opfamily, though a soft dependency on
281 * the opclass would work as well in the CREATE OPERATOR CLASS case.
282 */
283 foreach(lc, operators)
284 {
286
287 op->ref_is_hard = false;
288 op->ref_is_family = true;
289 op->refobjid = opfamilyoid;
290 }
291
292 /*
293 * Required support functions should have hard dependencies. Preferably
294 * those are just dependencies on the opclass, but if we're in ALTER
295 * OPERATOR FAMILY, we leave the dependency pointing at the whole
296 * opfamily. (Given that GIN opclasses generally don't share opfamilies,
297 * it seems unlikely to be worth working harder.)
298 */
299 foreach(lc, functions)
300 {
302
303 switch (op->number)
304 {
307 /* Required support function */
308 op->ref_is_hard = true;
309 break;
310 case GIN_COMPARE_PROC:
314 case GIN_OPTIONS_PROC:
315 /* Optional, so force it to be a soft family dependency */
316 op->ref_is_hard = false;
317 op->ref_is_family = true;
318 op->refobjid = opfamilyoid;
319 break;
320 default:
323 errmsg("support function number %d is invalid for access method %s",
324 op->number, "gin")));
325 break;
326 }
327 }
328}
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
#define GIN_COMPARE_PROC
Definition gin.h:24
#define GIN_CONSISTENT_PROC
Definition gin.h:27
#define GIN_EXTRACTQUERY_PROC
Definition gin.h:26
#define GIN_EXTRACTVALUE_PROC
Definition gin.h:25
#define GIN_TRICONSISTENT_PROC
Definition gin.h:29
#define GIN_COMPARE_PARTIAL_PROC
Definition gin.h:28
#define GIN_OPTIONS_PROC
Definition gin.h:30
static char * errmsg
#define lfirst(lc)
Definition pg_list.h:172
static const struct fns functions
Definition regcomp.c:358
Oid refobjid
Definition amapi.h:98
bool ref_is_family
Definition amapi.h:97
bool ref_is_hard
Definition amapi.h:96

References ereport, errcode(), errmsg, ERROR, fb(), 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)
extern

Definition at line 256 of file ginbulk.c.

257{
259}
void rbt_begin_iterate(RBTree *rbt, RBTOrderControl ctrl, RBTreeIterator *iter)
Definition rbtree.c:802
@ LeftRightWalk
Definition rbtree.h:37
RBTreeIterator tree_walk

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

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

◆ ginbeginscan()

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

Definition at line 26 of file ginscan.c.

27{
28 IndexScanDesc scan;
30
31 /* no order by operators allowed */
32 Assert(norderbys == 0);
33
34 scan = RelationGetIndexScan(rel, nkeys, norderbys);
35
36 /* allocate private workspace */
38 so->keys = NULL;
39 so->nkeys = 0;
41 "Gin scan temporary context",
44 "Gin scan key context",
46 initGinState(&so->ginstate, scan->indexRelation);
47
48 scan->opaque = so;
49
50 return scan;
51}
#define Assert(condition)
Definition c.h:945
#define palloc_object(type)
Definition fe_memutils.h:74
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition genam.c:80
GinScanOpaqueData * GinScanOpaque
void initGinState(GinState *state, Relation index)
Definition ginutil.c:103
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
Relation indexRelation
Definition relscan.h:138

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, CurrentMemoryContext, fb(), IndexScanDescData::indexRelation, initGinState(), IndexScanDescData::opaque, palloc_object, and RelationGetIndexScan().

Referenced by ginhandler().

◆ ginbuild()

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

Definition at line 618 of file gininsert.c.

619{
620 IndexBuildResult *result;
621 double reltuples;
627 Datum key;
628 GinNullCategory category;
629 uint32 nlist;
632
634 elog(ERROR, "index \"%s\" already contains data",
636
637 initGinState(&buildstate.ginstate, index);
638 buildstate.indtuples = 0;
639 memset(&buildstate.buildStats, 0, sizeof(GinStatsData));
640
641 /* Initialize fields for parallel build too. */
642 buildstate.bs_numtuples = 0;
643 buildstate.bs_reltuples = 0;
644 buildstate.bs_leader = NULL;
645 memset(&buildstate.tid, 0, sizeof(ItemPointerData));
646
647 /* initialize the meta page */
649
650 /* initialize the root page */
652
658
659
663
664 /* count the root as first entry page */
665 buildstate.buildStats.nEntryPages++;
666
667 /*
668 * create a temporary memory context that is used to hold data not yet
669 * dumped out to the index
670 */
672 "Gin build temporary context",
674
675 /*
676 * create a temporary memory context that is used for calling
677 * ginExtractEntries(), and can be reset after each tuple
678 */
680 "Gin build temporary context for user-defined function",
682
683 buildstate.accum.ginstate = &buildstate.ginstate;
684 ginInitBA(&buildstate.accum);
685
686 /* Report table scan phase started */
689
690 /*
691 * Attempt to launch parallel worker scan when required
692 *
693 * XXX plan_create_index_workers makes the number of workers dependent on
694 * maintenance_work_mem, requiring 32MB for each worker. For GIN that's
695 * reasonable too, because we sort the data just like btree. It does
696 * ignore the memory used to accumulate data in memory (set by work_mem),
697 * but there is no way to communicate that to plan_create_index_workers.
698 */
699 if (indexInfo->ii_ParallelWorkers > 0)
700 _gin_begin_parallel(state, heap, index, indexInfo->ii_Concurrent,
701 indexInfo->ii_ParallelWorkers);
702
703 /*
704 * If parallel build requested and at least one worker process was
705 * successfully launched, set up coordination state, wait for workers to
706 * complete. Then read all tuples from the shared tuplesort and insert
707 * them into the index.
708 *
709 * In serial mode, simply scan the table and build the index one index
710 * tuple at a time.
711 */
712 if (state->bs_leader)
713 {
715
717 coordinate->isWorker = false;
718 coordinate->nParticipants =
719 state->bs_leader->nparticipanttuplesorts;
720 coordinate->sharedsort = state->bs_leader->sharedsort;
721
722 /*
723 * Begin leader tuplesort.
724 *
725 * In cases where parallelism is involved, the leader receives the
726 * same share of maintenance_work_mem as a serial sort (it is
727 * generally treated in the same way as a serial sort once we return).
728 * Parallel worker Tuplesortstates will have received only a fraction
729 * of maintenance_work_mem, though.
730 *
731 * We rely on the lifetime of the Leader Tuplesortstate almost not
732 * overlapping with any worker Tuplesortstate's lifetime. There may
733 * be some small overlap, but that's okay because we rely on leader
734 * Tuplesortstate only allocating a small, fixed amount of memory
735 * here. When its tuplesort_performsort() is called (by our caller),
736 * and significant amounts of memory are likely to be used, all
737 * workers must have already freed almost all memory held by their
738 * Tuplesortstates (they are about to go away completely, too). The
739 * overall effect is that maintenance_work_mem always represents an
740 * absolute high watermark on the amount of memory used by a CREATE
741 * INDEX operation, regardless of the use of parallelism or any other
742 * factor.
743 */
744 state->bs_sortstate =
748
749 /* scan the relation in parallel and merge per-worker results */
750 reltuples = _gin_parallel_merge(state);
751
752 _gin_end_parallel(state->bs_leader, state);
753 }
754 else /* no parallel index build */
755 {
756 /*
757 * Do the heap scan. We disallow sync scan here because
758 * dataPlaceToPage prefers to receive tuples in TID order.
759 */
760 reltuples = table_index_build_scan(heap, index, indexInfo, false, true,
762
763 /* dump remaining entries to the index */
766 while ((list = ginGetBAEntry(&buildstate.accum,
767 &attnum, &key, &category, &nlist)) != NULL)
768 {
769 /* there could be many entries, so be willing to abort here */
771 ginEntryInsert(&buildstate.ginstate, attnum, key, category,
772 list, nlist, &buildstate.buildStats);
773 }
775 }
776
779
780 /*
781 * Update metapage stats
782 */
783 buildstate.buildStats.nTotalPages = RelationGetNumberOfBlocks(index);
784 ginUpdateStats(index, &buildstate.buildStats, true);
785
786 /*
787 * We didn't write WAL records as we built the index, so if WAL-logging is
788 * required, write all pages to the WAL now.
789 */
791 {
794 true);
795 }
796
797 /*
798 * Return statistics
799 */
801
802 result->heap_tuples = reltuples;
803 result->index_tuples = buildstate.indtuples;
804
805 return result;
806}
void pgstat_progress_update_param(int index, int64 val)
#define RelationGetNumberOfBlocks(reln)
Definition bufmgr.h:307
uint32_t uint32
Definition c.h:618
#define palloc0_object(type)
Definition fe_memutils.h:75
#define PROGRESS_GIN_PHASE_INDEXBUILD_TABLESCAN
Definition gin.h:46
signed char GinNullCategory
Definition ginblock.h:206
void ginBeginBAScan(BuildAccumulator *accum)
Definition ginbulk.c:256
ItemPointerData * ginGetBAEntry(BuildAccumulator *accum, OffsetNumber *attnum, Datum *key, GinNullCategory *category, uint32 *n)
Definition ginbulk.c:267
void ginInitBA(BuildAccumulator *accum)
Definition ginbulk.c:109
void ginEntryInsert(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition gininsert.c:351
static void _gin_end_parallel(GinLeader *ginleader, GinBuildState *state)
Definition gininsert.c:1116
static void _gin_begin_parallel(GinBuildState *buildstate, Relation heap, Relation index, bool isconcurrent, int request)
Definition gininsert.c:937
static double _gin_parallel_merge(GinBuildState *state)
Definition gininsert.c:1648
static void ginBuildCallback(Relation index, ItemPointer tid, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition gininsert.c:452
void GinInitBuffer(Buffer b, uint32 f)
Definition ginutil.c:357
void GinInitMetabuffer(Buffer b)
Definition ginutil.c:363
void ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
Definition ginutil.c:619
int maintenance_work_mem
Definition globals.c:133
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
uint16 OffsetNumber
Definition off.h:24
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
int16 attnum
uint64_t Datum
Definition postgres.h:70
#define PROGRESS_CREATEIDX_SUBPHASE
Definition progress.h:111
#define RelationGetRelationName(relation)
Definition rel.h:548
@ MAIN_FORKNUM
Definition relpath.h:58
double heap_tuples
Definition genam.h:40
double index_tuples
Definition genam.h:41
int ii_ParallelWorkers
Definition execnodes.h:229
bool ii_Concurrent
Definition execnodes.h:221
static double table_index_build_scan(Relation table_rel, Relation index_rel, IndexInfo *index_info, bool allow_sync, bool progress, IndexBuildCallback callback, void *callback_state, TableScanDesc scan)
Definition tableam.h:1765
#define TUPLESORT_NONE
Definition tuplesort.h:67
Tuplesortstate * tuplesort_begin_index_gin(Relation heapRel, Relation indexRel, int workMem, SortCoordinate coordinate, int sortopt)
void log_newpage_range(Relation rel, ForkNumber forknum, BlockNumber startblk, BlockNumber endblk, bool page_std)

References _gin_begin_parallel(), _gin_end_parallel(), _gin_parallel_merge(), ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, attnum, CHECK_FOR_INTERRUPTS, CurrentMemoryContext, elog, END_CRIT_SECTION, ERROR, fb(), GIN_LEAF, ginBeginBAScan(), ginBuildCallback(), ginEntryInsert(), ginGetBAEntry(), ginInitBA(), GinInitBuffer(), GinInitMetabuffer(), GinNewBuffer(), ginUpdateStats(), IndexBuildResult::heap_tuples, IndexInfo::ii_Concurrent, IndexInfo::ii_ParallelWorkers, IndexBuildResult::index_tuples, initGinState(), log_newpage_range(), MAIN_FORKNUM, maintenance_work_mem, MarkBufferDirty(), MemoryContextDelete(), MemoryContextSwitchTo(), palloc0_object, palloc_object, pgstat_progress_update_param(), PROGRESS_CREATEIDX_SUBPHASE, PROGRESS_GIN_PHASE_INDEXBUILD_TABLESCAN, RelationGetNumberOfBlocks, RelationGetRelationName, RelationNeedsWAL, START_CRIT_SECTION, table_index_build_scan(), tuplesort_begin_index_gin(), TUPLESORT_NONE, and UnlockReleaseBuffer().

Referenced by ginhandler().

◆ ginbuildempty()

void ginbuildempty ( Relation  index)
extern

Definition at line 812 of file gininsert.c.

813{
816
817 /* An empty GIN index has two pages. */
822
823 /* Initialize and xlog metabuffer and root buffer. */
832
833 /* Unlock and release the buffers. */
836}
Buffer ExtendBufferedRel(BufferManagerRelation bmr, ForkNumber forkNum, BufferAccessStrategy strategy, uint32 flags)
Definition bufmgr.c:974
@ EB_SKIP_EXTENSION_LOCK
Definition bufmgr.h:75
@ EB_LOCK_FIRST
Definition bufmgr.h:87
#define BMR_REL(p_rel)
Definition bufmgr.h:114
@ INIT_FORKNUM
Definition relpath.h:61
XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std)

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

Referenced by ginhandler().

◆ ginbuildphasename()

char * ginbuildphasename ( int64  phasenum)
extern

Definition at line 676 of file ginutil.c.

677{
678 switch (phasenum)
679 {
681 return "initializing";
683 return "scanning table";
685 return "sorting tuples (workers)";
687 return "merging tuples (workers)";
689 return "sorting tuples";
691 return "merging tuples";
692 default:
693 return NULL;
694 }
695}
#define PROGRESS_GIN_PHASE_PERFORMSORT_2
Definition gin.h:49
#define PROGRESS_GIN_PHASE_MERGE_1
Definition gin.h:48
#define PROGRESS_GIN_PHASE_PERFORMSORT_1
Definition gin.h:47
#define PROGRESS_GIN_PHASE_MERGE_2
Definition gin.h:50
#define PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE
Definition progress.h:132

References fb(), PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE, PROGRESS_GIN_PHASE_INDEXBUILD_TABLESCAN, PROGRESS_GIN_PHASE_MERGE_1, PROGRESS_GIN_PHASE_MERGE_2, PROGRESS_GIN_PHASE_PERFORMSORT_1, and PROGRESS_GIN_PHASE_PERFORMSORT_2.

Referenced by ginhandler().

◆ ginbulkdelete()

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

Definition at line 602 of file ginvacuum.c.

604{
605 Relation index = info->index;
608 Buffer buffer;
611
613 "Gin vacuum temporary context",
615 gvs.index = index;
616 gvs.callback = callback;
617 gvs.callback_state = callback_state;
618 gvs.strategy = info->strategy;
619 initGinState(&gvs.ginstate, index);
620
621 /* first time through? */
622 if (stats == NULL)
623 {
624 /* Yes, so initialize stats to zeroes */
626
627 /*
628 * and cleanup any pending inserts
629 */
631 false, true, stats);
632 }
633
634 /* we'll re-count the tuples each time */
635 stats->num_index_tuples = 0;
636 gvs.result = stats;
637
638 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
639 RBM_NORMAL, info->strategy);
640
641 /* find leaf page */
642 for (;;)
643 {
644 Page page = BufferGetPage(buffer);
645 IndexTuple itup;
646
647 LockBuffer(buffer, GIN_SHARE);
648
649 Assert(!GinPageIsData(page));
650
651 if (GinPageIsLeaf(page))
652 {
653 LockBuffer(buffer, GIN_UNLOCK);
654 LockBuffer(buffer, GIN_EXCLUSIVE);
655
656 if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page))
657 {
658 LockBuffer(buffer, GIN_UNLOCK);
659 continue; /* check it one more */
660 }
661 break;
662 }
663
665
667 blkno = GinGetDownlink(itup);
668 Assert(blkno != InvalidBlockNumber);
669
670 UnlockReleaseBuffer(buffer);
671 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
672 RBM_NORMAL, info->strategy);
673 }
674
675 /* right now we found leftmost page in entry's BTree */
676
677 for (;;)
678 {
679 Page page = BufferGetPage(buffer);
681 uint32 i;
682
683 Assert(!GinPageIsData(page));
684
686
687 blkno = GinPageGetOpaque(page)->rightlink;
688
689 if (resPage)
690 {
693 MarkBufferDirty(buffer);
694 xlogVacuumPage(gvs.index, buffer);
696 UnlockReleaseBuffer(buffer);
697 }
698 else
699 {
700 UnlockReleaseBuffer(buffer);
701 }
702
703 vacuum_delay_point(false);
704
705 for (i = 0; i < nRoot; i++)
706 {
708 vacuum_delay_point(false);
709 }
710
711 if (blkno == InvalidBlockNumber) /* rightmost page */
712 break;
713
714 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
715 RBM_NORMAL, info->strategy);
716 LockBuffer(buffer, GIN_EXCLUSIVE);
717 }
718
719 MemoryContextDelete(gvs.tmpCxt);
720
721 return gvs.result;
722}
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition bufmgr.c:921
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:332
@ RBM_NORMAL
Definition bufmgr.h:46
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition bufpage.h:269
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition bufpage.h:379
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition bufpage.h:397
#define GIN_UNLOCK
Definition gin_private.h:51
#define GIN_EXCLUSIVE
Definition gin_private.h:53
#define GIN_SHARE
Definition gin_private.h:52
#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:90
static void ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
Definition ginvacuum.c:442
static Page ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
Definition ginvacuum.c:493
int i
Definition isn.c:77
IndexTupleData * IndexTuple
Definition itup.h:53
#define AmAutoVacuumWorkerProcess()
Definition miscadmin.h:383
#define FirstOffsetNumber
Definition off.h:27
MemoryContext tmpCxt
Definition ginvacuum.c:36
double num_index_tuples
Definition genam.h:87
Relation index
Definition genam.h:54
BufferAccessStrategy strategy
Definition genam.h:61
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
void vacuum_delay_point(bool is_analyze)
Definition vacuum.c:2431

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

Referenced by ginhandler().

◆ ginCompareAttEntries()

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

Definition at line 526 of file gin_private.h.

529{
530 /* attribute number is the first sort key */
531 if (attnuma != attnumb)
532 return (attnuma < attnumb) ? -1 : 1;
533
534 return ginCompareEntries(ginstate, attnuma, a, categorya, b, categoryb);
535
536}
static int ginCompareEntries(GinState *ginstate, OffsetNumber attnum, Datum a, GinNullCategory categorya, Datum b, GinNullCategory categoryb)
int b
Definition isn.c:74
int a
Definition isn.c:73

References a, b, fb(), and ginCompareEntries().

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

◆ ginCompareEntries()

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

Definition at line 504 of file gin_private.h.

507{
508 /* if not of same null category, sort by that first */
509 if (categorya != categoryb)
510 return (categorya < categoryb) ? -1 : 1;
511
512 /* all null items in same category are equal */
514 return 0;
515
516 /* both not null, so safe to call the compareFn */
517 return DatumGetInt32(FunctionCall2Coll(&ginstate->compareFn[attnum - 1],
518 ginstate->supportCollation[attnum - 1],
519 a, b));
520}
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition fmgr.c:1151
#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:90
FmgrInfo compareFn[INDEX_MAX_KEYS]
Definition gin_private.h:81

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

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

◆ ginCompareItemPointers()

◆ ginCompressPostingList()

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

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
208
209 result = palloc(maxsize);
210
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;
222 {
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)
259
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;
269
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:906
#define SHORTALIGN(LEN)
Definition c.h:894
static uint64 itemptr_to_uint64(const ItemPointerData *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
static char buf[DEFAULT_XLOG_SEG_SIZE]
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(), fb(), GinPostingList::first, ginPostingListDecode(), itemptr_to_uint64(), MaxBytesPerInteger, GinPostingList::nbytes, palloc(), pfree(), SHORTALIGN, SHORTALIGN_DOWN, SizeOfGinPostingList, and val.

Referenced by _gin_build_tuple(), 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 
)
extern

Definition at line 1349 of file gindatapage.c.

1350{
1352 ri;
1353
1357
1361}
#define GinDataPageGetRightBound(page)
Definition ginblock.h:288
#define PostingItemSetBlockNumber(pointer, blockNumber)
Definition ginblock.h:192
void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset)
#define InvalidOffsetNumber
Definition off.h:26
tree ctl root
Definition radixtree.h:1857
ItemPointerData key
Definition ginblock.h:186

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

Referenced by ginPrepareDataScan().

◆ GinDataLeafPageGetItems()

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

Definition at line 135 of file gindatapage.c.

136{
137 ItemPointer result;
138
139 if (GinPageIsCompressed(page))
140 {
143 char *endptr = (char *) seg + len;
145
146 /* Skip to the segment containing advancePast+1 */
148 {
150 while ((char *) next < endptr &&
152 {
153 seg = next;
155 }
156 len = endptr - (char *) 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:225
size_t Size
Definition c.h:691
static int ginCompareItemPointers(const ItemPointerData *a, const ItemPointerData *b)
#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)
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(), fb(), ginCompareItemPointers(), GinDataLeafPageGetPostingList, GinDataLeafPageGetPostingListSize, GinNextPostingListSegment, GinPageIsCompressed, ginPostingListDecodeAllSegments(), ItemPointerIsValid(), len, next, nitems, and palloc().

Referenced by entryLoadMoreItems(), gin_check_posting_tree_parent_keys_consistency(), and startScanEntry().

◆ GinDataLeafPageGetItemsToTbm()

int GinDataLeafPageGetItemsToTbm ( Page  page,
TIDBitmap tbm 
)
extern

Definition at line 182 of file gindatapage.c.

183{
185 int nitems;
186
187 if (GinPageIsCompressed(page))
188 {
191
193 }
194 else
195 {
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 ItemPointerData *tids, int ntids, bool recheck)
Definition tidbitmap.c:367

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

Referenced by scanPostingTree().

◆ GinDataPageAddPostingItem()

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

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, fb(), GinDataPageGetPostingItem, GinDataPageSetDataSize, GinPageGetOpaque, GinPageIsLeaf, InvalidBlockNumber, InvalidOffsetNumber, and PostingItemGetBlockNumber.

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

◆ ginendscan()

void ginendscan ( IndexScanDesc  scan)
extern

Definition at line 504 of file ginscan.c.

505{
507
509
510 MemoryContextDelete(so->tempCtx);
511 MemoryContextDelete(so->keyCtx);
512
513 pfree(so);
514}
void ginFreeScanKeys(GinScanOpaque so)
Definition ginscan.c:237

References fb(), ginFreeScanKeys(), MemoryContextDelete(), IndexScanDescData::opaque, and pfree().

Referenced by ginhandler().

◆ ginEntryFillRoot()

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

Definition at line 723 of file ginentrypage.c.

726{
727 IndexTuple itup;
728
730 if (PageAddItem(root, itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
731 elog(ERROR, "failed to add item to index root page");
732 pfree(itup);
733
735 if (PageAddItem(root, 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:504
static IndexTuple getRightMostTuple(Page page)
static IndexTuple GinFormInteriorTuple(IndexTuple itup, Page page, BlockNumber childblk)
static Size IndexTupleSize(const IndexTupleData *itup)
Definition itup.h:71

References elog, ERROR, fb(), 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 
)
extern

Definition at line 351 of file gininsert.c.

355{
356 GinBtreeData btree;
358 GinBtreeStack *stack;
359 IndexTuple itup;
360 Page page;
361
362 insertdata.isDelete = false;
363
364 ginPrepareEntryScan(&btree, attnum, key, category, ginstate);
365 btree.isBuild = (buildStats != NULL);
366
367 stack = ginFindLeafPage(&btree, false, false);
368 page = BufferGetPage(stack->buffer);
369
370 if (btree.findItem(&btree, stack))
371 {
372 /* found pre-existing entry */
373 itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off));
374
375 if (GinIsPostingTree(itup))
376 {
377 /* add entries to existing posting tree */
379
380 /* release all stack */
382 freeGinBtreeStack(stack);
383
384 /* insert into posting tree */
386 items, nitem,
387 buildStats);
388 return;
389 }
390
393 /* modify an existing leaf entry */
394 itup = addItemPointersToLeafTuple(ginstate, itup,
395 items, nitem, buildStats, stack->buffer);
396
397 insertdata.isDelete = true;
398 }
399 else
400 {
403 /* no match, so construct a new leaf entry */
404 itup = buildFreshLeafTuple(ginstate, attnum, key, category,
405 items, nitem, buildStats, stack->buffer);
406
407 /*
408 * nEntries counts leaf tuples, so increment it only when we make a
409 * new one.
410 */
411 if (buildStats)
412 buildStats->nEntries++;
413 }
414
415 /* Insert the new or modified leaf tuple */
416 insertdata.entry = itup;
417 ginInsertValue(&btree, stack, &insertdata, buildStats);
418 pfree(itup);
419}
#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)
static IndexTuple addItemPointersToLeafTuple(GinState *ginstate, IndexTuple old, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats, Buffer buffer)
Definition gininsert.c:217
static IndexTuple buildFreshLeafTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats, Buffer buffer)
Definition gininsert.c:299
void CheckForSerializableConflictIn(Relation relation, const ItemPointerData *tid, BlockNumber blkno)
Definition predicate.c:4345
bool(* findItem)(GinBtree, GinBtreeStack *)
OffsetNumber off
Relation index
Definition gin_private.h:61
int64 nEntries
Definition gin.h:61

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

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

◆ ginExtractEntries()

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

Definition at line 452 of file ginutil.c.

455{
456 Datum *entries;
457 bool *nullFlags;
458 int32 i;
459
460 /*
461 * We don't call the extractValueFn on a null item. Instead generate a
462 * placeholder.
463 */
464 if (isNull)
465 {
466 *nentries = 1;
467 entries = palloc_object(Datum);
468 entries[0] = (Datum) 0;
469 *categories = palloc_object(GinNullCategory);
470 (*categories)[0] = GIN_CAT_NULL_ITEM;
471 return entries;
472 }
473
474 /* OK, call the opclass's extractValueFn */
475 nullFlags = NULL; /* in case extractValue doesn't set it */
476 entries = (Datum *)
478 ginstate->supportCollation[attnum - 1],
479 value,
480 PointerGetDatum(nentries),
482
483 /*
484 * Generate a placeholder if the item contained no keys.
485 */
486 if (entries == NULL || *nentries <= 0)
487 {
488 *nentries = 1;
489 entries = palloc_object(Datum);
490 entries[0] = (Datum) 0;
491 *categories = palloc_object(GinNullCategory);
492 (*categories)[0] = GIN_CAT_EMPTY_ITEM;
493 return entries;
494 }
495
496 /*
497 * If the extractValueFn didn't create a nullFlags array, create one,
498 * assuming that everything's non-null.
499 */
500 if (nullFlags == NULL)
501 nullFlags = (bool *) palloc0(*nentries * sizeof(bool));
502
503 /*
504 * If there's more than one key, sort and unique-ify.
505 *
506 * XXX Using qsort here is notationally painful, and the overhead is
507 * pretty bad too. For small numbers of keys it'd likely be better to use
508 * a simple insertion sort.
509 */
510 if (*nentries > 1)
511 {
514
515 keydata = palloc_array(keyEntryData, *nentries);
516 for (i = 0; i < *nentries; i++)
517 {
518 keydata[i].datum = entries[i];
519 keydata[i].isnull = nullFlags[i];
520 }
521
522 arg.cmpDatumFunc = &ginstate->compareFn[attnum - 1];
523 arg.collation = ginstate->supportCollation[attnum - 1];
524 arg.haveDups = false;
525 qsort_arg(keydata, *nentries, sizeof(keyEntryData),
526 cmpEntries, &arg);
527
528 if (arg.haveDups)
529 {
530 /* there are duplicates, must get rid of 'em */
531 int32 j;
532
533 entries[0] = keydata[0].datum;
534 nullFlags[0] = keydata[0].isnull;
535 j = 1;
536 for (i = 1; i < *nentries; i++)
537 {
538 if (cmpEntries(&keydata[i - 1], &keydata[i], &arg) != 0)
539 {
540 entries[j] = keydata[i].datum;
541 nullFlags[j] = keydata[i].isnull;
542 j++;
543 }
544 }
545 *nentries = j;
546 }
547 else
548 {
549 /* easy, no duplicates */
550 for (i = 0; i < *nentries; i++)
551 {
552 entries[i] = keydata[i].datum;
553 nullFlags[i] = keydata[i].isnull;
554 }
555 }
556
557 pfree(keydata);
558 }
559
560 /*
561 * Create GinNullCategory representation from nullFlags.
562 */
563 *categories = (GinNullCategory *) palloc0(*nentries * sizeof(GinNullCategory));
564 for (i = 0; i < *nentries; i++)
565 (*categories)[i] = (nullFlags[i] ? GIN_CAT_NULL_KEY : GIN_CAT_NORM_KEY);
566
567 return entries;
568}
int32_t int32
Definition c.h:614
Datum arg
Definition elog.c:1322
#define palloc_array(type, count)
Definition fe_memutils.h:76
Datum FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition fmgr.c:1173
#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:412
static struct @174 value
int j
Definition isn.c:78
void * palloc0(Size size)
Definition mcxt.c:1417
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:342
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
FmgrInfo extractValueFn[INDEX_MAX_KEYS]
Definition gin_private.h:82

References arg, attnum, cmpEntries(), GinState::compareFn, DatumGetPointer(), GinState::extractValueFn, fb(), FunctionCall3Coll(), GIN_CAT_EMPTY_ITEM, GIN_CAT_NORM_KEY, GIN_CAT_NULL_ITEM, GIN_CAT_NULL_KEY, i, j, palloc0(), palloc_array, palloc_object, pfree(), PointerGetDatum(), qsort_arg(), GinState::supportCollation, and value.

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

◆ ginFindLeafPage()

GinBtreeStack * ginFindLeafPage ( GinBtree  btree,
bool  searchMode,
bool  rootConflictCheck 
)
extern

Definition at line 83 of file ginbtree.c.

85{
86 GinBtreeStack *stack;
87
89 stack->blkno = btree->rootBlkno;
90 stack->buffer = ReadBuffer(btree->index, btree->rootBlkno);
91 stack->parent = NULL;
92 stack->predictNumber = 1;
93
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
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 {
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:3128
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition bufmgr.c:874
#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
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
bool(* isMoveRight)(GinBtree, Page)
Relation index
BlockNumber rootBlkno
uint32 predictNumber
BlockNumber blkno

References Assert, GinBtreeStack::blkno, GinBtreeStack::buffer, BufferGetPage(), CheckForSerializableConflictIn(), fb(), GinBtreeData::findChildPage, GinBtreeData::fullScan, GIN_UNLOCK, ginFinishOldSplit(), GinPageGetOpaque, GinPageIsIncompleteSplit, GinPageIsLeaf, ginStepRight(), ginTraverseLock(), GinBtreeData::index, InvalidBlockNumber, InvalidOffsetNumber, GinBtreeData::isMoveRight, LockBuffer(), GinBtreeStack::off, palloc_object, 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 
)
extern

Definition at line 44 of file ginentrypage.c.

48{
49 Datum datums[2];
50 bool isnull[2];
51 IndexTuple itup;
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 {
85
86 Assert(category != GIN_CAT_NORM_KEY);
87 minsize = GinCategoryOffset(itup, ginstate) + sizeof(GinNullCategory);
89 }
90
92
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
103
105 {
106 if (errorTooBig)
109 errmsg("index row size %zu exceeds maximum %zu for index \"%s\"",
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 {
150 GinSetNullCategory(itup, ginstate, category);
151 }
152 return itup;
153}
#define MAXALIGN(LEN)
Definition c.h:898
#define Max(x, y)
Definition c.h:1087
#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
static bool IndexTupleHasNulls(const IndexTupleData *itup)
Definition itup.h:77
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1632
static Datum UInt16GetDatum(uint16 X)
Definition postgres.h:192
bool oneCol
Definition gin_private.h:62
TupleDesc tupdesc[INDEX_MAX_KEYS]
Definition gin_private.h:76
unsigned short t_info
Definition itup.h:49

References Assert, attnum, data, ereport, errcode(), errmsg, ERROR, fb(), GIN_CAT_NORM_KEY, GinCategoryOffset, GinGetPosting, GinMaxItemSize, GinSetNPosting, GinSetNullCategory, GinSetPostingOffset, GinState::index, index_form_tuple(), IndexTupleHasNulls(), IndexTupleSize(), 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)
extern

Definition at line 237 of file ginscan.c.

238{
239 uint32 i;
240
241 if (so->keys == NULL)
242 return;
243
244 for (i = 0; i < so->totalentries; i++)
245 {
246 GinScanEntry entry = so->entries[i];
247
248 if (entry->buffer != InvalidBuffer)
249 ReleaseBuffer(entry->buffer);
250 if (entry->list)
251 pfree(entry->list);
252 if (entry->matchIterator)
254 if (entry->matchBitmap)
255 tbm_free(entry->matchBitmap);
256 }
257
258 MemoryContextReset(so->keyCtx);
259
260 so->keys = NULL;
261 so->nkeys = 0;
262 so->entries = NULL;
263 so->totalentries = 0;
264}
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
TIDBitmap * matchBitmap
ItemPointerData * list
TBMPrivateIterator * matchIterator
void tbm_free(TIDBitmap *tbm)
Definition tidbitmap.c:312
void tbm_end_private_iterate(TBMPrivateIterator *iterator)
Definition tidbitmap.c:1147

References GinScanEntryData::buffer, fb(), i, InvalidBuffer, GinScanEntryData::list, GinScanEntryData::matchBitmap, GinScanEntryData::matchIterator, MemoryContextReset(), pfree(), ReleaseBuffer(), tbm_end_private_iterate(), and tbm_free().

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

◆ ginGetBAEntry()

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

Definition at line 267 of file ginbulk.c.

270{
271 GinEntryAccumulator *entry;
273
274 entry = (GinEntryAccumulator *) rbt_iterate(&accum->tree_walk);
275
276 if (entry == NULL)
277 return NULL; /* no more entries */
278
279 *attnum = entry->attnum;
280 *key = entry->key;
281 *category = entry->category;
282 list = entry->list;
283 *n = entry->count;
284
285 Assert(list != NULL && entry->count > 0);
286
287 if (entry->shouldSort && entry->count > 1)
288 qsort(list, entry->count, sizeof(ItemPointerData),
290
291 return list;
292}
static int qsortCompareItemPointers(const void *a, const void *b)
Definition ginbulk.c:245
#define qsort(a, b, c, d)
Definition port.h:495
RBTNode * rbt_iterate(RBTreeIterator *iter)
Definition rbtree.c:826
OffsetNumber attnum
ItemPointerData * list
GinNullCategory category

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

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

◆ gingetbitmap()

int64 gingetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)
extern

Definition at line 1931 of file ginget.c.

1932{
1934 int64 ntids;
1935 ItemPointerData iptr;
1936 bool recheck;
1937
1938 /*
1939 * Set up the scan keys, and check for unsatisfiable query.
1940 */
1941 ginFreeScanKeys(so); /* there should be no keys yet, but just to be
1942 * sure */
1943 ginNewScanKey(scan);
1944
1945 if (GinIsVoidRes(scan))
1946 return 0;
1947
1948 ntids = 0;
1949
1950 /*
1951 * First, scan the pending list and collect any matching entries into the
1952 * bitmap. After we scan a pending item, some other backend could post it
1953 * into the main index, and so we might visit it a second time during the
1954 * main scan. This is okay because we'll just re-set the same bit in the
1955 * bitmap. (The possibility of duplicate visits is a major reason why GIN
1956 * can't support the amgettuple API, however.) Note that it would not do
1957 * to scan the main index before the pending list, since concurrent
1958 * cleanup could then make us miss entries entirely.
1959 */
1960 scanPendingInsert(scan, tbm, &ntids);
1961
1962 /*
1963 * Now scan the main index.
1964 */
1965 startScan(scan);
1966
1967 ItemPointerSetMin(&iptr);
1968
1969 for (;;)
1970 {
1971 if (!scanGetItem(scan, iptr, &iptr, &recheck))
1972 break;
1973
1974 if (ItemPointerIsLossyPage(&iptr))
1976 else
1977 tbm_add_tuples(tbm, &iptr, 1, recheck);
1978 ntids++;
1979 }
1980
1981 return ntids;
1982}
int64_t int64
Definition c.h:615
#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:1837
static void startScan(IndexScanDesc scan)
Definition ginget.c:605
#define GinIsVoidRes(s)
Definition ginget.c:1928
static bool scanGetItem(IndexScanDesc scan, ItemPointerData advancePast, ItemPointerData *item, bool *recheck)
Definition ginget.c:1300
void ginNewScanKey(IndexScanDesc scan)
Definition ginscan.c:267
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition itemptr.h:103
void tbm_add_page(TIDBitmap *tbm, BlockNumber pageno)
Definition tidbitmap.c:432

References fb(), 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 
)
extern

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
IndexTuple GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, Pointer data, Size dataSize, int nipd, bool errorTooBig)
Datum * ginExtractEntries(GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, int32 *nentries, GinNullCategory **categories)
Definition ginutil.c:452
static uint32 pg_nextpower2_32(uint32 num)
ItemPointerData t_tid
Definition itup.h:37

References attnum, elog, ERROR, fb(), ginExtractEntries(), GinFormTuple(), i, IndexTupleSize(), Max, MaxAllocSize, palloc_array, pg_nextpower2_32(), repalloc_array, IndexTupleData::t_tid, and value.

Referenced by gininsert().

◆ ginHeapTupleFastInsert()

void ginHeapTupleFastInsert ( GinState ginstate,
GinTupleCollector collector 
)
extern

Definition at line 219 of file ginfast.c.

220{
221 Relation index = ginstate->index;
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
237
238 data.locator = index->rd_locator;
239 data.ntuples = 0;
240 data.newRightlink = data.prevTail = InvalidBlockNumber;
241
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 {
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;
276 }
277 }
278
279 if (separateList)
280 {
281 /*
282 * We should make sublist separately and append it to the tail
283 */
285
286 memset(&sublist, 0, sizeof(GinMetaPageData));
287 makeSublist(index, collector->tuples, collector->ntuples, &sublist);
288
289 /*
290 * metapage was unlocked, see above
291 */
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)
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 {
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)
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, 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 {
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 */
426
427 if (needWal)
428 {
430
431 memcpy(&data.metadata, metadata, sizeof(GinMetaPageData));
432
435
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 */
459 if (metadata->nPendingPages * GIN_PAGE_FREESIZE > cleanupSize * (Size) 1024)
460 needCleanup = true;
461
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(const PageData *page)
Definition bufpage.c:957
static bool PageIsEmpty(const PageData *page)
Definition bufpage.h:249
PageHeaderData * PageHeader
Definition bufpage.h:199
#define GinGetPendingListCleanupSize(relation)
Definition gin_private.h:41
#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 void *data, uint32 len)
Definition xloginsert.c:410
#define REGBUF_STANDARD
Definition xloginsert.h:35

References Assert, BufferGetPage(), CheckForSerializableConflictIn(), data, elog, END_CRIT_SECTION, ERROR, fb(), 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, OffsetNumberNext, PageAddItem, PageGetExactFreeSpace(), PageGetMaxOffsetNumber(), PageIsEmpty(), PageSetLSN(), palloc(), ReadBuffer(), REGBUF_STANDARD, REGBUF_WILL_INIT, RelationGetRelationName, RelationNeedsWAL, START_CRIT_SECTION, GinMetaPageData::tail, GinMetaPageData::tailFreeSize, UnlockReleaseBuffer(), XLOG_GIN_UPDATE_META_PAGE, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by gininsert().

◆ ginInitBA()

void ginInitBA ( BuildAccumulator accum)
extern

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 RBTNode * ginAllocEntryAccumulator(void *arg)
Definition ginbulk.c:85
static int cmpEntryAccumulator(const RBTNode *a, const RBTNode *b, void *arg)
Definition ginbulk.c:72
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

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

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

◆ GinInitBuffer()

void GinInitBuffer ( Buffer  b,
uint32  f 
)
extern

Definition at line 357 of file ginutil.c.

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

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

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

◆ ginInitConsistentFunction()

void ginInitConsistentFunction ( GinState ginstate,
GinScanKey  key 
)
extern

Definition at line 227 of file ginlogic.c.

228{
229 if (key->searchMode == GIN_SEARCH_MODE_EVERYTHING)
230 {
231 key->boolConsistentFn = trueConsistentFn;
232 key->triConsistentFn = trueTriConsistentFn;
233 }
234 else
235 {
236 key->consistentFmgrInfo = &ginstate->consistentFn[key->attnum - 1];
237 key->triConsistentFmgrInfo = &ginstate->triConsistentFn[key->attnum - 1];
238 key->collation = ginstate->supportCollation[key->attnum - 1];
239
240 if (OidIsValid(ginstate->consistentFn[key->attnum - 1].fn_oid))
241 key->boolConsistentFn = directBoolConsistentFn;
242 else
243 key->boolConsistentFn = shimBoolConsistentFn;
244
245 if (OidIsValid(ginstate->triConsistentFn[key->attnum - 1].fn_oid))
246 key->triConsistentFn = directTriConsistentFn;
247 else
248 key->triConsistentFn = shimTriConsistentFn;
249 }
250}
#define OidIsValid(objectId)
Definition c.h:860
#define GIN_SEARCH_MODE_EVERYTHING
Definition gin.h:39
static GinTernaryValue trueTriConsistentFn(GinScanKey key)
Definition ginlogic.c:56
static GinTernaryValue shimTriConsistentFn(GinScanKey key)
Definition ginlogic.c:148
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:85
FmgrInfo consistentFn[INDEX_MAX_KEYS]
Definition gin_private.h:84

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

Referenced by ginFillScanKey().

◆ GinInitMetabuffer()

void GinInitMetabuffer ( Buffer  b)
extern

Definition at line 363 of file ginutil.c.

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

Definition at line 345 of file ginutil.c.

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

References fb(), 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 
)
extern

Definition at line 865 of file gininsert.c.

870{
871 GinState *ginstate = (GinState *) indexInfo->ii_AmCache;
874 int i;
875
876 /* Initialize GinState cache if first call in this statement */
877 if (ginstate == NULL)
878 {
880 ginstate = palloc_object(GinState);
881 initGinState(ginstate, index);
882 indexInfo->ii_AmCache = ginstate;
884 }
885
887 "Gin insert temporary context",
889
891
893 {
895
896 memset(&collector, 0, sizeof(GinTupleCollector));
897
898 for (i = 0; i < ginstate->origTupdesc->natts; i++)
900 (OffsetNumber) (i + 1),
901 values[i], isnull[i],
902 ht_ctid);
903
905 }
906 else
907 {
908 for (i = 0; i < ginstate->origTupdesc->natts; i++)
909 ginHeapTupleInsert(ginstate, (OffsetNumber) (i + 1),
910 values[i], isnull[i],
911 ht_ctid);
912 }
913
916
917 return false;
918}
static Datum values[MAXATTR]
Definition bootstrap.c:188
#define GinGetUseFastUpdate(relation)
Definition gin_private.h:36
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:843
void * ii_AmCache
Definition execnodes.h:234
MemoryContext ii_Context
Definition execnodes.h:237

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

Referenced by ginhandler().

◆ ginInsertBAEntries()

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

Definition at line 209 of file ginbulk.c.

213{
214 uint32 step = nentries;
215
216 if (nentries <= 0)
217 return;
218
220
221 /*
222 * step will contain largest power of 2 and <= nentries
223 */
224 step |= (step >> 1);
225 step |= (step >> 2);
226 step |= (step >> 4);
227 step |= (step >> 8);
228 step |= (step >> 16);
229 step >>= 1;
230 step++;
231
232 while (step > 0)
233 {
234 int i;
235
236 for (i = step - 1; i < nentries && i >= 0; i += step << 1 /* *2 */ )
238 entries[i], categories[i]);
239
240 step >>= 1; /* /2 */
241 }
242}
static void ginInsertBAEntry(BuildAccumulator *accum, ItemPointer heapptr, OffsetNumber attnum, Datum key, GinNullCategory category)
Definition ginbulk.c:148

References Assert, attnum, fb(), 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 
)
extern

Definition at line 780 of file ginfast.c.

783{
784 Relation index = ginstate->index;
786 buffer;
788 page;
789 GinMetaPageData *metadata;
791 oldCtx;
792 BuildAccumulator accum;
793 KeyArray datums;
794 BlockNumber blkno,
796 bool cleanupFinish = false;
797 bool fsm_vac = false;
798 int 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;
828 }
829
833 metadata = GinPageGetMeta(metapage);
834
835 if (metadata->head == InvalidBlockNumber)
836 {
837 /* Nothing to do */
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
858
859 /*
860 * Initialize. All temporary space will be in opCtx
861 */
863 "GIN insert cleanup temporary context",
865
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
895 vacuum_delay_point(false);
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 * (Size) 1024))
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);
932 vacuum_delay_point(false);
933 }
934
935 /*
936 * Lock the whole list to remove pages
937 */
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);
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 */
1005 vacuum_delay_point(false);
1006 buffer = ReadBuffer(index, blkno);
1007 LockBuffer(buffer, GIN_SHARE);
1008 page = BufferGetPage(buffer);
1009 }
1010
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 */
1025}
int autovacuum_work_mem
Definition autovacuum.c:122
#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 work_mem
Definition globals.c:131
void IndexFreeSpaceMapVacuum(Relation rel)
Definition indexfsm.c:71
bool ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
Definition lmgr.c:526
void LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
Definition lmgr.c:507
void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
Definition lmgr.c:542
#define ExclusiveLock
Definition lockdefs.h:42
GinState * ginstate
int32 maxvalues
Definition ginfast.c:49

References BuildAccumulator::allocatedMemory, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, AmAutoVacuumWorkerProcess, Assert, attnum, autovacuum_work_mem, BufferGetPage(), ConditionalLockPage(), CurrentMemoryContext, ExclusiveLock, fb(), 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, 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 
)
extern

Definition at line 1908 of file gindatapage.c.

1911{
1912 GinBtreeData btree;
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)
ItemPointerData itemptr

References fb(), ginFindLeafPage(), ginInsertValue(), ginPrepareDataScan(), GinBtreeData::isBuild, GinBtreeData::itemptr, and items.

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

◆ ginInsertValue()

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

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,
827 InvalidBuffer, buildStats);
828 if (done)
829 {
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(), fb(), 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 
)
extern

Definition at line 378 of file ginpostinglist.c.

381{
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 {
407
408 while (aptr - a < na && bptr - b < nb)
409 {
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
static int cmp(const chr *x, const chr *y, size_t len)

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

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

◆ GinNewBuffer()

Buffer GinNewBuffer ( Relation  index)
extern

Definition at line 307 of file ginutil.c.

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

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

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

◆ ginNewScanKey()

void ginNewScanKey ( IndexScanDesc  scan)
extern

Definition at line 267 of file ginscan.c.

268{
269 ScanKey scankey = scan->keyData;
271 int i;
272 int numExcludeOnly;
273 bool hasNullQuery = false;
274 bool attrHasNormalScan[INDEX_MAX_KEYS] = {false};
276
277 /*
278 * Allocate all the scan key information in the key context. (If
279 * extractQuery leaks anything there, it won't be reset until the end of
280 * scan or rescan, but that's OK.)
281 */
283
284 /* if no scan keys provided, allocate extra EVERYTHING GinScanKey */
285 so->keys = (GinScanKey)
286 palloc(Max(scan->numberOfKeys, 1) * sizeof(GinScanKeyData));
287 so->nkeys = 0;
288
289 /* initialize expansible array of GinScanEntry pointers */
290 so->totalentries = 0;
291 so->allocentries = 32;
292 so->entries = (GinScanEntry *)
293 palloc(so->allocentries * sizeof(GinScanEntry));
294
295 so->isVoidRes = false;
296
297 for (i = 0; i < scan->numberOfKeys; i++)
298 {
299 ScanKey skey = &scankey[i];
300 Datum *queryValues;
302 bool *partial_matches = NULL;
303 Pointer *extra_data = NULL;
304 bool *nullFlags = NULL;
305 GinNullCategory *categories;
306 int32 searchMode = GIN_SEARCH_MODE_DEFAULT;
307
308 /*
309 * We assume that GIN-indexable operators are strict, so a null query
310 * argument means an unsatisfiable query.
311 */
312 if (skey->sk_flags & SK_ISNULL)
313 {
314 so->isVoidRes = true;
315 break;
316 }
317
318 /* OK to call the extractQueryFn */
319 queryValues = (Datum *)
320 DatumGetPointer(FunctionCall7Coll(&so->ginstate.extractQueryFn[skey->sk_attno - 1],
321 so->ginstate.supportCollation[skey->sk_attno - 1],
322 skey->sk_argument,
324 UInt16GetDatum(skey->sk_strategy),
326 PointerGetDatum(&extra_data),
328 PointerGetDatum(&searchMode)));
329
330 /*
331 * If bogus searchMode is returned, treat as GIN_SEARCH_MODE_ALL; note
332 * in particular we don't allow extractQueryFn to select
333 * GIN_SEARCH_MODE_EVERYTHING.
334 */
335 if (searchMode < GIN_SEARCH_MODE_DEFAULT ||
336 searchMode > GIN_SEARCH_MODE_ALL)
337 searchMode = GIN_SEARCH_MODE_ALL;
338
339 /* Non-default modes require the index to have placeholders */
340 if (searchMode != GIN_SEARCH_MODE_DEFAULT)
341 hasNullQuery = true;
342
343 /*
344 * In default mode, no keys means an unsatisfiable query.
345 */
346 if (queryValues == NULL || nQueryValues <= 0)
347 {
348 if (searchMode == GIN_SEARCH_MODE_DEFAULT)
349 {
350 so->isVoidRes = true;
351 break;
352 }
353 nQueryValues = 0; /* ensure sane value */
354 }
355
356 /*
357 * Create GinNullCategory representation. If the extractQueryFn
358 * didn't create a nullFlags array, we assume everything is non-null.
359 * While at it, detect whether any null keys are present.
360 */
361 categories = (GinNullCategory *) palloc0(nQueryValues * sizeof(GinNullCategory));
362 if (nullFlags)
363 {
364 int32 j;
365
366 for (j = 0; j < nQueryValues; j++)
367 {
368 if (nullFlags[j])
369 {
370 categories[j] = GIN_CAT_NULL_KEY;
371 hasNullQuery = true;
372 }
373 }
374 }
375
376 ginFillScanKey(so, skey->sk_attno,
377 skey->sk_strategy, searchMode,
378 skey->sk_argument, nQueryValues,
379 queryValues, categories,
380 partial_matches, extra_data);
381
382 /* Remember if we had any non-excludeOnly keys */
383 if (searchMode != GIN_SEARCH_MODE_ALL)
384 attrHasNormalScan[skey->sk_attno - 1] = true;
385 }
386
387 /*
388 * Processing GIN_SEARCH_MODE_ALL scan keys requires us to make a second
389 * pass over the scan keys. Above we marked each such scan key as
390 * excludeOnly. If the involved column has any normal (not excludeOnly)
391 * scan key as well, then we can leave it like that. Otherwise, one
392 * excludeOnly scan key must receive a GIN_CAT_EMPTY_QUERY hidden entry
393 * and be set to normal (excludeOnly = false).
394 */
395 numExcludeOnly = 0;
396 for (i = 0; i < so->nkeys; i++)
397 {
398 GinScanKey key = &so->keys[i];
399
400 if (key->searchMode != GIN_SEARCH_MODE_ALL)
401 continue;
402
403 if (!attrHasNormalScan[key->attnum - 1])
404 {
405 key->excludeOnly = false;
407 attrHasNormalScan[key->attnum - 1] = true;
408 }
409 else
411 }
412
413 /*
414 * If we left any excludeOnly scan keys as-is, move them to the end of the
415 * scan key array: they must appear after normal key(s).
416 */
417 if (numExcludeOnly > 0)
418 {
420 int iNormalKey;
421 int iExcludeOnly;
422
423 /* We'd better have made at least one normal key */
425 /* Make a temporary array to hold the re-ordered scan keys */
426 tmpkeys = (GinScanKey) palloc(so->nkeys * sizeof(GinScanKeyData));
427 /* Re-order the keys ... */
428 iNormalKey = 0;
429 iExcludeOnly = so->nkeys - numExcludeOnly;
430 for (i = 0; i < so->nkeys; i++)
431 {
432 GinScanKey key = &so->keys[i];
433
434 if (key->excludeOnly)
435 {
436 memcpy(tmpkeys + iExcludeOnly, key, sizeof(GinScanKeyData));
437 iExcludeOnly++;
438 }
439 else
440 {
441 memcpy(tmpkeys + iNormalKey, key, sizeof(GinScanKeyData));
442 iNormalKey++;
443 }
444 }
445 Assert(iNormalKey == so->nkeys - numExcludeOnly);
446 Assert(iExcludeOnly == so->nkeys);
447 /* ... and copy them back to so->keys[] */
448 memcpy(so->keys, tmpkeys, so->nkeys * sizeof(GinScanKeyData));
449 pfree(tmpkeys);
450 }
451
452 /*
453 * If there are no regular scan keys, generate an EVERYTHING scankey to
454 * drive a full-index scan.
455 */
456 if (so->nkeys == 0 && !so->isVoidRes)
457 {
458 hasNullQuery = true;
461 (Datum) 0, 0,
462 NULL, NULL, NULL, NULL);
463 }
464
465 /*
466 * If the index is version 0, it may be missing null and placeholder
467 * entries, which would render searches for nulls and full-index scans
468 * unreliable. Throw an error if so.
469 */
470 if (hasNullQuery && !so->isVoidRes)
471 {
473
475 if (ginStats.ginVersion < 1)
478 errmsg("old GIN indexes do not support whole-index scans nor searches for nulls"),
479 errhint("To fix this, do REINDEX INDEX \"%s\".",
481 }
482
484
486 if (scan->instrument)
487 scan->instrument->nsearches++;
488}
void * Pointer
Definition c.h:609
int errhint(const char *fmt,...) pg_attribute_printf(1
Datum FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7)
Definition fmgr.c:1286
#define GIN_SEARCH_MODE_ALL
Definition gin.h:38
#define GIN_SEARCH_MODE_DEFAULT
Definition gin.h:36
struct GinScanKeyData * GinScanKey
#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:159
static void ginScanKeyAddHiddenEntry(GinScanOpaque so, GinScanKey key, GinNullCategory queryCategory)
Definition ginscan.c:143
void ginGetStats(Relation index, GinStatsData *stats)
Definition ginutil.c:592
#define INDEX_MAX_KEYS
#define pgstat_count_index_scan(rel)
Definition pgstat.h:708
#define SK_ISNULL
Definition skey.h:115
#define InvalidStrategy
Definition stratnum.h:24
struct ScanKeyData * keyData
Definition relscan.h:142
struct IndexScanInstrumentation * instrument
Definition relscan.h:160

References Assert, DatumGetPointer(), ereport, errcode(), errhint(), errmsg, ERROR, fb(), FirstOffsetNumber, FunctionCall7Coll(), GIN_CAT_EMPTY_QUERY, GIN_CAT_NULL_KEY, GIN_SEARCH_MODE_ALL, GIN_SEARCH_MODE_DEFAULT, GIN_SEARCH_MODE_EVERYTHING, ginFillScanKey(), ginGetStats(), ginScanKeyAddHiddenEntry(), i, INDEX_MAX_KEYS, IndexScanDescData::indexRelation, IndexScanDescData::instrument, InvalidStrategy, j, IndexScanDescData::keyData, Max, MemoryContextSwitchTo(), IndexScanInstrumentation::nsearches, IndexScanDescData::numberOfKeys, IndexScanDescData::opaque, palloc(), palloc0(), pfree(), pgstat_count_index_scan, PointerGetDatum(), RelationGetRelationName, SK_ISNULL, and UInt16GetDatum().

Referenced by gingetbitmap().

◆ ginoptions()

bytea * ginoptions ( Datum  reloptions,
bool  validate 
)
extern

Definition at line 571 of file ginutil.c.

572{
573 static const relopt_parse_elt tab[] = {
574 {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)},
575 {"gin_pending_list_limit", RELOPT_TYPE_INT, offsetof(GinOptions,
576 pendingListCleanupSize)}
577 };
578
579 return (bytea *) build_reloptions(reloptions, validate,
581 sizeof(GinOptions),
582 tab, lengthof(tab));
583}
static bool validate(Port *port, const char *auth)
Definition auth-oauth.c:638
#define lengthof(array)
Definition c.h:875
void * build_reloptions(Datum reloptions, bool validate, relopt_kind kind, Size relopt_struct_size, const relopt_parse_elt *relopt_elems, int num_relopt_elems)
@ RELOPT_KIND_GIN
Definition reloptions.h:47
@ RELOPT_TYPE_INT
Definition reloptions.h:33
@ RELOPT_TYPE_BOOL
Definition reloptions.h:31
Definition c.h:778

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

Referenced by ginhandler().

◆ GinPageDeletePostingItem()

void GinPageDeletePostingItem ( Page  page,
OffsetNumber  offset 
)
extern

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)
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, fb(), FirstOffsetNumber, GinDataPageGetPostingItem, GinDataPageSetDataSize, GinPageGetOpaque, and GinPageIsLeaf.

Referenced by ginDeletePostingPage(), and ginRedoDeletePage().

◆ ginPostingListDecode()

◆ ginPostingListDecodeAllSegments()

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

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)
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(), fb(), GinPostingList::first, ginCompareItemPointers(), GinNextPostingListSegment, ItemPointerGetOffsetNumber(), itemptr_to_uint64(), len, GinPostingList::nbytes, OffsetNumberIsValid, palloc(), repalloc(), uint64_to_itemptr(), and val.

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

◆ ginPostingListDecodeAllSegmentsToTbm()

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

Definition at line 358 of file ginpostinglist.c.

360{
361 int ndecoded;
363
365 tbm_add_tuples(tbm, items, ndecoded, false);
366 pfree(items);
367
368 return ndecoded;
369}

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

Referenced by GinDataLeafPageGetItemsToTbm().

◆ ginPrepareEntryScan()

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

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
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)
static bool entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack)
static bool entryIsMoveRight(GinBtree btree, Page page)
static BlockNumber entryGetLeftMostPage(GinBtree btree, Page page)
static OffsetNumber entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
static GinPlaceToPageRC entryBeginPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertPayload, BlockNumber updateblkno, void **ptp_workspace, Page *newlpage, Page *newrpage)
static void entryExecPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertPayload, BlockNumber updateblkno, void *ptp_workspace)
static BlockNumber entryLocateEntry(GinBtree btree, GinBtreeStack *stack)
static void * entryPrepareDownlink(GinBtree btree, Buffer lbuf)
GinState * ginstate
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
BlockNumber(* getLeftMostChild)(GinBtree, Page)
void *(* prepareDownlink)(GinBtree, Buffer)
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
GinNullCategory entryCategory
OffsetNumber entryAttnum
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)

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

Referenced by ginEntryInsert(), and startScanEntry().

◆ ginReadTuple()

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

Definition at line 162 of file ginentrypage.c.

164{
165 Pointer ptr = GinGetPosting(itup);
166 int nipd = GinGetNPosting(itup);
168 int ndecoded;
169
170 if (GinItupIsCompressed(itup))
171 {
172 if (nipd > 0)
173 {
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 {
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, fb(), GinGetNPosting, GinGetPosting, GinItupIsCompressed, ginPostingListDecode(), nitems, palloc(), and palloc_array.

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

◆ ginrescan()

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

Definition at line 491 of file ginscan.c.

493{
495
497
498 if (scankey && scan->numberOfKeys > 0)
499 memcpy(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData));
500}

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

Referenced by ginhandler().

◆ ginScanBeginPostingTree()

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

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 
)
extern

Definition at line 177 of file ginbtree.c.

178{
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. */
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, fb(), GinPageGetOpaque, GinPageIsData, GinPageIsLeaf, LockBuffer(), ReadBuffer(), and UnlockReleaseBuffer().

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

◆ ginTraverseLock()

int ginTraverseLock ( Buffer  buffer,
bool  searchMode 
)
extern

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);
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 
)
extern

Definition at line 233 of file ginutil.c.

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

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

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

◆ gintuple_get_key()

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

Definition at line 266 of file ginutil.c.

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

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

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

◆ ginvacuumcleanup()

IndexBulkDeleteResult * ginvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)
extern

Definition at line 725 of file ginvacuum.c.

726{
727 Relation index = info->index;
728 bool needLock;
729 BlockNumber npages,
730 blkno;
732 GinState ginstate;
735 ReadStream *stream;
736
737 /*
738 * In an autovacuum analyze, we want to clean up pending insertions.
739 * Otherwise, an ANALYZE-only call is a no-op.
740 */
741 if (info->analyze_only)
742 {
744 {
745 initGinState(&ginstate, index);
746 ginInsertCleanup(&ginstate, false, true, true, stats);
747 }
748 return stats;
749 }
750
751 /*
752 * Set up all-zero stats and cleanup pending inserts if ginbulkdelete
753 * wasn't called
754 */
755 if (stats == NULL)
756 {
758 initGinState(&ginstate, index);
760 false, true, stats);
761 }
762
763 memset(&idxStat, 0, sizeof(idxStat));
764
765 /*
766 * XXX we always report the heap tuple count as the number of index
767 * entries. This is bogus if the index is partial, but it's real hard to
768 * tell how many distinct heap entries are referenced by a GIN index.
769 */
770 stats->num_index_tuples = Max(info->num_heap_tuples, 0);
771 stats->estimated_count = info->estimated_count;
772
773 /*
774 * Need lock unless it's local to this backend.
775 */
777
778 if (needLock)
781 if (needLock)
783
784 totFreePages = 0;
785
786 /* Scan all blocks starting from the root using streaming reads */
788 p.last_exclusive = npages;
789
790 /*
791 * It is safe to use batchmode as block_range_read_stream_cb takes no
792 * locks.
793 */
797 info->strategy,
798 index,
801 &p,
802 0);
803
804 for (blkno = GIN_ROOT_BLKNO; blkno < npages; blkno++)
805 {
806 Buffer buffer;
807 Page page;
808
809 vacuum_delay_point(false);
810
811 buffer = read_stream_next_buffer(stream, NULL);
812
813 LockBuffer(buffer, GIN_SHARE);
814 page = BufferGetPage(buffer);
815
816 if (GinPageIsRecyclable(page))
817 {
818 Assert(blkno != GIN_ROOT_BLKNO);
820 totFreePages++;
821 }
822 else if (GinPageIsData(page))
823 {
824 idxStat.nDataPages++;
825 }
826 else if (!GinPageIsList(page))
827 {
828 idxStat.nEntryPages++;
829
830 if (GinPageIsLeaf(page))
831 idxStat.nEntries += PageGetMaxOffsetNumber(page);
832 }
833
834 UnlockReleaseBuffer(buffer);
835 }
836
838 read_stream_end(stream);
839
840 /* Update the metapage with accurate page and entry counts */
841 idxStat.nTotalPages = npages;
842 ginUpdateStats(info->index, &idxStat, false);
843
844 /* Finally, vacuum the FSM */
846
847 stats->pages_free = totFreePages;
848
849 if (needLock)
852 if (needLock)
854
855 return stats;
856}
#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:424
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition lmgr.c:474
Buffer read_stream_next_buffer(ReadStream *stream, void **per_buffer_data)
ReadStream * read_stream_begin_relation(int flags, BufferAccessStrategy strategy, Relation rel, ForkNumber forknum, ReadStreamBlockNumberCB callback, void *callback_private_data, size_t per_buffer_data_size)
void read_stream_end(ReadStream *stream)
BlockNumber block_range_read_stream_cb(ReadStream *stream, void *callback_private_data, void *per_buffer_data)
#define READ_STREAM_MAINTENANCE
Definition read_stream.h:28
#define READ_STREAM_USE_BATCHING
Definition read_stream.h:64
#define READ_STREAM_FULL
Definition read_stream.h:43
#define RELATION_IS_LOCAL(relation)
Definition rel.h:657
BlockNumber pages_free
Definition genam.h:91
BlockNumber num_pages
Definition genam.h:85
double num_heap_tuples
Definition genam.h:60
bool analyze_only
Definition genam.h:56
bool estimated_count
Definition genam.h:58

References AmAutoVacuumWorkerProcess, IndexVacuumInfo::analyze_only, Assert, block_range_read_stream_cb(), DataPageDeleteStack::buffer, BufferGetPage(), BlockRangeReadStreamPrivate::current_blocknum, IndexVacuumInfo::estimated_count, IndexBulkDeleteResult::estimated_count, ExclusiveLock, fb(), GIN_ROOT_BLKNO, GIN_SHARE, ginInsertCleanup(), GinPageIsData, GinPageIsLeaf, GinPageIsList, GinPageIsRecyclable(), ginUpdateStats(), IndexVacuumInfo::index, IndexFreeSpaceMapVacuum(), initGinState(), InvalidBuffer, BlockRangeReadStreamPrivate::last_exclusive, LockBuffer(), LockRelationForExtension(), MAIN_FORKNUM, Max, IndexVacuumInfo::num_heap_tuples, IndexBulkDeleteResult::num_index_tuples, IndexBulkDeleteResult::num_pages, PageGetMaxOffsetNumber(), IndexBulkDeleteResult::pages_free, palloc0_object, read_stream_begin_relation(), read_stream_end(), READ_STREAM_FULL, READ_STREAM_MAINTENANCE, read_stream_next_buffer(), READ_STREAM_USE_BATCHING, 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 
)
extern

Definition at line 48 of file ginvacuum.c.

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

References fb(), i, items, palloc_array, and remaining.

Referenced by ginVacuumEntryPage(), and ginVacuumPostingTreeLeaf().

◆ ginVacuumPostingTreeLeaf()

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

Definition at line 738 of file gindatapage.c.

739{
740 Page page = BufferGetPage(buffer);
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 {
751 int oldsegsize;
753 int ncleaned;
754
755 if (!seginfo->items)
757 &seginfo->nitems);
758 if (seginfo->seg)
760 else
762
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
777 ncleaned,
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");
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 */
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 {
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
848
849 MarkBufferDirty(buffer);
850
851 if (RelationNeedsWAL(indexrel))
852 {
854
857 XLogRegisterBufData(0, leaf->walinfo, leaf->walinfolen);
859 PageSetLSN(page, recptr);
860 }
861
863 }
864}
static void dataPlaceToPageLeafRecompress(Buffer buf, disassembledLeaf *leaf)
static void computeLeafRecompressWALData(disassembledLeaf *leaf)
static disassembledLeaf * disassembleLeaf(Page page)
ItemPointer ginVacuumItemPointers(GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining)
Definition ginvacuum.c:48
#define GIN_SEGMENT_DELETE
Definition ginxlog.h:92
#define XLOG_GIN_VACUUM_DATA_LEAF_PAGE
Definition ginxlog.h:141
#define GIN_SEGMENT_UNMODIFIED
Definition ginxlog.h:91
#define GIN_SEGMENT_REPLACE
Definition ginxlog.h:94
#define dlist_foreach(iter, lhead)
Definition ilist.h:623
#define dlist_container(type, membername, ptr)
Definition ilist.h:593
dlist_node * cur
Definition ilist.h:179

References BufferGetPage(), computeLeafRecompressWALData(), dlist_iter::cur, dataPlaceToPageLeafRecompress(), disassembleLeaf(), dlist_container, dlist_foreach, elog, END_CRIT_SECTION, ERROR, fb(), GIN_SEGMENT_DELETE, GIN_SEGMENT_REPLACE, GIN_SEGMENT_UNMODIFIED, ginCompressPostingList(), GinDataPageMaxDataSize, ginPostingListDecode(), ginVacuumItemPointers(), MarkBufferDirty(), PageSetLSN(), palloc(), pfree(), REGBUF_STANDARD, RelationNeedsWAL, SizeOfGinPostingList, START_CRIT_SECTION, XLOG_GIN_VACUUM_DATA_LEAF_PAGE, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), and XLogRegisterBuffer().

Referenced by ginVacuumPostingTreeLeaves().

◆ ginvalidate()

bool ginvalidate ( Oid  opclassoid)
extern

Definition at line 31 of file ginvalidate.c.

32{
33 bool result = true;
37 Oid opcintype;
39 char *opclassname;
40 char *opfamilyname;
42 *oprlist;
45 int i;
46 ListCell *lc;
47
48 /* Fetch opclass information */
51 elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
53
54 opfamilyoid = classform->opcfamily;
55 opcintype = classform->opcintype;
56 opckeytype = classform->opckeytype;
58 opckeytype = opcintype;
59 opclassname = NameStr(classform->opcname);
60
61 /* Fetch opfamily information */
62 opfamilyname = get_opfamily_name(opfamilyoid, false);
63
64 /* Fetch all operators and support functions of the opfamily */
67
68 /* Check individual support functions */
69 for (i = 0; i < proclist->n_members; i++)
70 {
71 HeapTuple proctup = &proclist->members[i]->tuple;
73 bool ok;
74
75 /*
76 * All GIN support functions should be registered with matching
77 * left/right types
78 */
79 if (procform->amproclefttype != procform->amprocrighttype)
80 {
83 errmsg("operator family \"%s\" of access method %s contains support function %s with different left and right input types",
84 opfamilyname, "gin",
85 format_procedure(procform->amproc))));
86 result = false;
87 }
88
89 /*
90 * We can't check signatures except within the specific opclass, since
91 * we need to know the associated opckeytype in many cases.
92 */
93 if (procform->amproclefttype != opcintype)
94 continue;
95
96 /* Check procedure numbers and function signatures */
97 switch (procform->amprocnum)
98 {
100 ok = check_amproc_signature(procform->amproc, INT4OID, false,
101 2, 2, opckeytype, opckeytype);
102 break;
104 /* Some opclasses omit nullFlags */
106 2, 3, opcintype, INTERNALOID,
108 break;
110 /* Some opclasses omit nullFlags and searchMode */
112 5, 7, opcintype, INTERNALOID,
115 break;
117 /* Some opclasses omit queryKeys and nullFlags */
118 ok = check_amproc_signature(procform->amproc, BOOLOID, false,
119 6, 8, INTERNALOID, INT2OID,
120 opcintype, INT4OID,
123 break;
125 ok = check_amproc_signature(procform->amproc, INT4OID, false,
126 4, 4, opckeytype, opckeytype,
128 break;
130 ok = check_amproc_signature(procform->amproc, CHAROID, false,
131 7, 7, INTERNALOID, INT2OID,
132 opcintype, INT4OID,
135 break;
136 case GIN_OPTIONS_PROC:
138 break;
139 default:
142 errmsg("operator family \"%s\" of access method %s contains function %s with invalid support number %d",
143 opfamilyname, "gin",
144 format_procedure(procform->amproc),
145 procform->amprocnum)));
146 result = false;
147 continue; /* don't want additional message */
148 }
149
150 if (!ok)
151 {
154 errmsg("operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d",
155 opfamilyname, "gin",
156 format_procedure(procform->amproc),
157 procform->amprocnum)));
158 result = false;
159 }
160 }
161
162 /* Check individual operators */
163 for (i = 0; i < oprlist->n_members; i++)
164 {
165 HeapTuple oprtup = &oprlist->members[i]->tuple;
167
168 /* TODO: Check that only allowed strategy numbers exist */
169 if (oprform->amopstrategy < 1 || oprform->amopstrategy > 63)
170 {
173 errmsg("operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
174 opfamilyname, "gin",
175 format_operator(oprform->amopopr),
176 oprform->amopstrategy)));
177 result = false;
178 }
179
180 /* gin doesn't support ORDER BY operators */
181 if (oprform->amoppurpose != AMOP_SEARCH ||
182 OidIsValid(oprform->amopsortfamily))
183 {
186 errmsg("operator family \"%s\" of access method %s contains invalid ORDER BY specification for operator %s",
187 opfamilyname, "gin",
188 format_operator(oprform->amopopr))));
189 result = false;
190 }
191
192 /* Check operator signature --- same for all gin strategies */
193 if (!check_amop_signature(oprform->amopopr, BOOLOID,
194 oprform->amoplefttype,
195 oprform->amoprighttype))
196 {
199 errmsg("operator family \"%s\" of access method %s contains operator %s with wrong signature",
200 opfamilyname, "gin",
201 format_operator(oprform->amopopr))));
202 result = false;
203 }
204 }
205
206 /* Now check for inconsistent groups of operators/functions */
209 foreach(lc, grouplist)
210 {
212
213 /* Remember the group exactly matching the test opclass */
214 if (thisgroup->lefttype == opcintype &&
215 thisgroup->righttype == opcintype)
217
218 /*
219 * There is not a lot we can do to check the operator sets, since each
220 * GIN opclass is more or less a law unto itself, and some contain
221 * only operators that are binary-compatible with the opclass datatype
222 * (meaning that empty operator sets can be OK). That case also means
223 * that we shouldn't insist on nonempty function sets except for the
224 * opclass's own group.
225 */
226 }
227
228 /* Check that the originally-named opclass is complete */
229 for (i = 1; i <= GINNProcs; i++)
230 {
231 if (opclassgroup &&
232 (opclassgroup->functionset & (((uint64) 1) << i)) != 0)
233 continue; /* got it */
236 continue; /* optional method */
238 continue; /* don't need both, see check below loop */
241 errmsg("operator class \"%s\" of access method %s is missing support function %d",
242 opclassname, "gin", i)));
243 result = false;
244 }
245 if (!opclassgroup ||
246 ((opclassgroup->functionset & (1 << GIN_CONSISTENT_PROC)) == 0 &&
247 (opclassgroup->functionset & (1 << GIN_TRICONSISTENT_PROC)) == 0))
248 {
251 errmsg("operator class \"%s\" of access method %s is missing support function %d or %d",
252 opclassname, "gin",
254 result = false;
255 }
256
257
261
262 return result;
263}
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:837
void ReleaseCatCacheList(CatCList *list)
Definition catcache.c:2114
#define INFO
Definition elog.h:34
#define GINNProcs
Definition gin.h:31
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
char * get_opfamily_name(Oid opfid, bool missing_ok)
Definition lsyscache.c:1473
END_CATALOG_STRUCT typedef FormData_pg_amop * Form_pg_amop
Definition pg_amop.h:92
END_CATALOG_STRUCT typedef FormData_pg_amproc * Form_pg_amproc
Definition pg_amproc.h:72
END_CATALOG_STRUCT typedef FormData_pg_opclass * Form_pg_opclass
Definition pg_opclass.h:87
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
unsigned int Oid
char * format_procedure(Oid procedure_oid)
Definition regproc.c:305
char * format_operator(Oid operator_oid)
Definition regproc.c:801
Definition pg_list.h:54
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:220
#define SearchSysCacheList1(cacheId, key1)
Definition syscache.h:127

References check_amop_signature(), check_amoptsproc_signature(), check_amproc_signature(), elog, ereport, errcode(), errmsg, ERROR, fb(), Form_pg_amop, Form_pg_amproc, Form_pg_opclass, format_operator(), format_procedure(), get_opfamily_name(), 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, lfirst, NameStr, ObjectIdGetDatum(), OidIsValid, ReleaseCatCacheList(), ReleaseSysCache(), SearchSysCache1(), and SearchSysCacheList1.

Referenced by ginhandler().

◆ initGinState()

void initGinState ( GinState state,
Relation  index 
)
extern

Definition at line 103 of file ginutil.c.

104{
105 TupleDesc origTupdesc = RelationGetDescr(index);
106 int i;
107
108 MemSet(state, 0, sizeof(GinState));
109
110 state->index = index;
111 state->oneCol = (origTupdesc->natts == 1);
112 state->origTupdesc = origTupdesc;
113
114 for (i = 0; i < origTupdesc->natts; i++)
115 {
116 Form_pg_attribute attr = TupleDescAttr(origTupdesc, i);
117
118 if (state->oneCol)
119 state->tupdesc[i] = state->origTupdesc;
120 else
121 {
122 state->tupdesc[i] = CreateTemplateTupleDesc(2);
123
124 TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 1, NULL,
125 INT2OID, -1, 0);
126 TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 2, NULL,
127 attr->atttypid,
128 attr->atttypmod,
129 attr->attndims);
131 attr->attcollation);
132 TupleDescFinalize(state->tupdesc[i]);
133 }
134
135 /*
136 * If the compare proc isn't specified in the opclass definition, look
137 * up the index key type's default btree comparator.
138 */
140 {
141 fmgr_info_copy(&(state->compareFn[i]),
144 }
145 else
146 {
147 TypeCacheEntry *typentry;
148
149 typentry = lookup_type_cache(attr->atttypid,
151 if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
154 errmsg("could not identify a comparison function for type %s",
155 format_type_be(attr->atttypid))));
156 fmgr_info_copy(&(state->compareFn[i]),
157 &(typentry->cmp_proc_finfo),
159 }
160
161 /* Opclass must always provide extract procs */
162 fmgr_info_copy(&(state->extractValueFn[i]),
165 fmgr_info_copy(&(state->extractQueryFn[i]),
168
169 /*
170 * Check opclass capability to do tri-state or binary logic consistent
171 * check.
172 */
174 {
175 fmgr_info_copy(&(state->triConsistentFn[i]),
178 }
179
181 {
182 fmgr_info_copy(&(state->consistentFn[i]),
185 }
186
187 if (state->consistentFn[i].fn_oid == InvalidOid &&
188 state->triConsistentFn[i].fn_oid == InvalidOid)
189 {
190 elog(ERROR, "missing GIN support function (%d or %d) for attribute %d of index \"%s\"",
193 }
194
195 /*
196 * Check opclass capability to do partial match.
197 */
199 {
200 fmgr_info_copy(&(state->comparePartialFn[i]),
203 state->canPartialMatch[i] = true;
204 }
205 else
206 {
207 state->canPartialMatch[i] = false;
208 }
209
210 /*
211 * If the index column has a specified collation, we should honor that
212 * while doing comparisons. However, we may have a collatable storage
213 * type for a noncollatable indexed data type (for instance, hstore
214 * uses text index entries). If there's no index collation then
215 * specify default collation in case the support functions need
216 * collation. This is harmless if the support functions don't care
217 * about collation, so we just do it unconditionally. (We could
218 * alternatively call get_typcollation, but that seems like expensive
219 * overkill --- there aren't going to be any cases where a GIN storage
220 * type has a nondefault collation.)
221 */
222 if (OidIsValid(index->rd_indcollation[i]))
223 state->supportCollation[i] = index->rd_indcollation[i];
224 else
225 state->supportCollation[i] = DEFAULT_COLLATION_OID;
226 }
227}
int16 AttrNumber
Definition attnum.h:21
#define MemSet(start, val, len)
Definition c.h:1109
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition fmgr.c:582
char * format_type_be(Oid type_oid)
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition indexam.c:917
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition indexam.c:883
FormData_pg_attribute * Form_pg_attribute
#define InvalidOid
#define RelationGetDescr(relation)
Definition rel.h:540
FmgrInfo cmp_proc_finfo
Definition typcache.h:77
TupleDesc CreateTemplateTupleDesc(int natts)
Definition tupdesc.c:165
void TupleDescFinalize(TupleDesc tupdesc)
Definition tupdesc.c:508
void TupleDescInitEntryCollation(TupleDesc desc, AttrNumber attributeNumber, Oid collationid)
Definition tupdesc.c:1081
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition tupdesc.c:897
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:389
#define TYPECACHE_CMP_PROC_FINFO
Definition typcache.h:144

References TypeCacheEntry::cmp_proc_finfo, CreateTemplateTupleDesc(), CurrentMemoryContext, elog, ereport, errcode(), errmsg, ERROR, fb(), 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(), TupleDescFinalize(), TupleDescInitEntry(), TupleDescInitEntryCollation(), and TYPECACHE_CMP_PROC_FINFO.

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