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 "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 (ItemPointer a, ItemPointer 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 34 of file gin_private.h.

◆ GIN_EXCLUSIVE

#define GIN_EXCLUSIVE   BUFFER_LOCK_EXCLUSIVE

Definition at line 52 of file gin_private.h.

◆ GIN_SHARE

#define GIN_SHARE   BUFFER_LOCK_SHARE

Definition at line 51 of file gin_private.h.

◆ GIN_UNLOCK

#define GIN_UNLOCK   BUFFER_LOCK_UNLOCK

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

Definition at line 40 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:34

Definition at line 35 of file gin_private.h.

Typedef Documentation

◆ GinBtree

Definition at line 136 of file gin_private.h.

◆ GinBtreeData

◆ GinBtreeStack

◆ GinEntryAccumulator

◆ GinOptions

◆ GinScanEntry

◆ GinScanEntryData

◆ GinScanKey

Definition at line 260 of file gin_private.h.

◆ GinScanKeyData

◆ GinScanOpaque

◆ GinScanOpaqueData

◆ GinState

◆ GinTupleCollector

◆ GinVacuumState

Enumeration Type Documentation

◆ GinPlaceToPageRC

Enumerator
GPTP_NO_WORK 
GPTP_INSERT 
GPTP_SPLIT 

Definition at line 139 of file gin_private.h.

140{
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
1857 UnlockReleaseBuffer(buffer);
1858
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:4356
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5518
void MarkBufferDirty(Buffer buffer)
Definition bufmgr.c:3056
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:466
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition bufpage.c:423
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition bufpage.h:390
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:344
Buffer GinNewBuffer(Relation index)
Definition ginutil.c:306
#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:3142
#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:478
void XLogRegisterData(const void *data, uint32 len)
Definition xloginsert.c:368
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition xloginsert.c:245
void XLogBeginInsert(void)
Definition xloginsert.c:152
#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:5501
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:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#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
#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:873
#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 613 of file gininsert.c.

614{
615 IndexBuildResult *result;
616 double reltuples;
622 Datum key;
623 GinNullCategory category;
624 uint32 nlist;
627
629 elog(ERROR, "index \"%s\" already contains data",
631
632 initGinState(&buildstate.ginstate, index);
633 buildstate.indtuples = 0;
634 memset(&buildstate.buildStats, 0, sizeof(GinStatsData));
635
636 /* Initialize fields for parallel build too. */
637 buildstate.bs_numtuples = 0;
638 buildstate.bs_reltuples = 0;
639 buildstate.bs_leader = NULL;
640 memset(&buildstate.tid, 0, sizeof(ItemPointerData));
641
642 /* initialize the meta page */
644
645 /* initialize the root page */
647
653
654
658
659 /* count the root as first entry page */
660 buildstate.buildStats.nEntryPages++;
661
662 /*
663 * create a temporary memory context that is used to hold data not yet
664 * dumped out to the index
665 */
667 "Gin build temporary context",
669
670 /*
671 * create a temporary memory context that is used for calling
672 * ginExtractEntries(), and can be reset after each tuple
673 */
675 "Gin build temporary context for user-defined function",
677
678 buildstate.accum.ginstate = &buildstate.ginstate;
679 ginInitBA(&buildstate.accum);
680
681 /* Report table scan phase started */
684
685 /*
686 * Attempt to launch parallel worker scan when required
687 *
688 * XXX plan_create_index_workers makes the number of workers dependent on
689 * maintenance_work_mem, requiring 32MB for each worker. For GIN that's
690 * reasonable too, because we sort the data just like btree. It does
691 * ignore the memory used to accumulate data in memory (set by work_mem),
692 * but there is no way to communicate that to plan_create_index_workers.
693 */
694 if (indexInfo->ii_ParallelWorkers > 0)
695 _gin_begin_parallel(state, heap, index, indexInfo->ii_Concurrent,
696 indexInfo->ii_ParallelWorkers);
697
698 /*
699 * If parallel build requested and at least one worker process was
700 * successfully launched, set up coordination state, wait for workers to
701 * complete. Then read all tuples from the shared tuplesort and insert
702 * them into the index.
703 *
704 * In serial mode, simply scan the table and build the index one index
705 * tuple at a time.
706 */
707 if (state->bs_leader)
708 {
710
712 coordinate->isWorker = false;
713 coordinate->nParticipants =
714 state->bs_leader->nparticipanttuplesorts;
715 coordinate->sharedsort = state->bs_leader->sharedsort;
716
717 /*
718 * Begin leader tuplesort.
719 *
720 * In cases where parallelism is involved, the leader receives the
721 * same share of maintenance_work_mem as a serial sort (it is
722 * generally treated in the same way as a serial sort once we return).
723 * Parallel worker Tuplesortstates will have received only a fraction
724 * of maintenance_work_mem, though.
725 *
726 * We rely on the lifetime of the Leader Tuplesortstate almost not
727 * overlapping with any worker Tuplesortstate's lifetime. There may
728 * be some small overlap, but that's okay because we rely on leader
729 * Tuplesortstate only allocating a small, fixed amount of memory
730 * here. When its tuplesort_performsort() is called (by our caller),
731 * and significant amounts of memory are likely to be used, all
732 * workers must have already freed almost all memory held by their
733 * Tuplesortstates (they are about to go away completely, too). The
734 * overall effect is that maintenance_work_mem always represents an
735 * absolute high watermark on the amount of memory used by a CREATE
736 * INDEX operation, regardless of the use of parallelism or any other
737 * factor.
738 */
739 state->bs_sortstate =
743
744 /* scan the relation in parallel and merge per-worker results */
745 reltuples = _gin_parallel_merge(state);
746
747 _gin_end_parallel(state->bs_leader, state);
748 }
749 else /* no parallel index build */
750 {
751 /*
752 * Do the heap scan. We disallow sync scan here because
753 * dataPlaceToPage prefers to receive tuples in TID order.
754 */
755 reltuples = table_index_build_scan(heap, index, indexInfo, false, true,
757
758 /* dump remaining entries to the index */
761 while ((list = ginGetBAEntry(&buildstate.accum,
762 &attnum, &key, &category, &nlist)) != NULL)
763 {
764 /* there could be many entries, so be willing to abort here */
766 ginEntryInsert(&buildstate.ginstate, attnum, key, category,
767 list, nlist, &buildstate.buildStats);
768 }
770 }
771
774
775 /*
776 * Update metapage stats
777 */
778 buildstate.buildStats.nTotalPages = RelationGetNumberOfBlocks(index);
779 ginUpdateStats(index, &buildstate.buildStats, true);
780
781 /*
782 * We didn't write WAL records as we built the index, so if WAL-logging is
783 * required, write all pages to the WAL now.
784 */
786 {
789 true);
790 }
791
792 /*
793 * Return statistics
794 */
796
797 result->heap_tuples = reltuples;
798 result->index_tuples = buildstate.indtuples;
799
800 return result;
801}
void pgstat_progress_update_param(int index, int64 val)
#define RelationGetNumberOfBlocks(reln)
Definition bufmgr.h:307
uint32_t uint32
Definition c.h:546
#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:346
static void _gin_end_parallel(GinLeader *ginleader, GinBuildState *state)
Definition gininsert.c:1107
static void _gin_begin_parallel(GinBuildState *buildstate, Relation heap, Relation index, bool isconcurrent, int request)
Definition gininsert.c:928
static double _gin_parallel_merge(GinBuildState *state)
Definition gininsert.c:1639
static void ginBuildCallback(Relation index, ItemPointer tid, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition gininsert.c:447
void GinInitBuffer(Buffer b, uint32 f)
Definition ginutil.c:356
void GinInitMetabuffer(Buffer b)
Definition ginutil.c:362
void ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
Definition ginutil.c:618
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:105
#define RelationGetRelationName(relation)
Definition rel.h:548
@ MAIN_FORKNUM
Definition relpath.h:58
double heap_tuples
Definition genam.h:38
double index_tuples
Definition genam.h:39
int ii_ParallelWorkers
Definition execnodes.h:220
bool ii_Concurrent
Definition execnodes.h:212
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:1766
#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 807 of file gininsert.c.

808{
811
812 /* An empty GIN index has two pages. */
817
818 /* Initialize and xlog metabuffer and root buffer. */
827
828 /* Unlock and release the buffers. */
831}
Buffer ExtendBufferedRel(BufferManagerRelation bmr, ForkNumber forkNum, BufferAccessStrategy strategy, uint32 flags)
Definition bufmgr.c:964
@ 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 675 of file ginutil.c.

676{
677 switch (phasenum)
678 {
680 return "initializing";
682 return "scanning table";
684 return "sorting tuples (workers)";
686 return "merging tuples (workers)";
688 return "sorting tuples";
690 return "merging tuples";
691 default:
692 return NULL;
693 }
694}
#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:126

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

566{
567 Relation index = info->index;
570 Buffer buffer;
573
575 "Gin vacuum temporary context",
577 gvs.index = index;
578 gvs.callback = callback;
579 gvs.callback_state = callback_state;
580 gvs.strategy = info->strategy;
581 initGinState(&gvs.ginstate, index);
582
583 /* first time through? */
584 if (stats == NULL)
585 {
586 /* Yes, so initialize stats to zeroes */
588
589 /*
590 * and cleanup any pending inserts
591 */
593 false, true, stats);
594 }
595
596 /* we'll re-count the tuples each time */
597 stats->num_index_tuples = 0;
598 gvs.result = stats;
599
600 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
601 RBM_NORMAL, info->strategy);
602
603 /* find leaf page */
604 for (;;)
605 {
606 Page page = BufferGetPage(buffer);
607 IndexTuple itup;
608
609 LockBuffer(buffer, GIN_SHARE);
610
611 Assert(!GinPageIsData(page));
612
613 if (GinPageIsLeaf(page))
614 {
615 LockBuffer(buffer, GIN_UNLOCK);
616 LockBuffer(buffer, GIN_EXCLUSIVE);
617
618 if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page))
619 {
620 LockBuffer(buffer, GIN_UNLOCK);
621 continue; /* check it one more */
622 }
623 break;
624 }
625
627
629 blkno = GinGetDownlink(itup);
630 Assert(blkno != InvalidBlockNumber);
631
632 UnlockReleaseBuffer(buffer);
633 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
634 RBM_NORMAL, info->strategy);
635 }
636
637 /* right now we found leftmost page in entry's BTree */
638
639 for (;;)
640 {
641 Page page = BufferGetPage(buffer);
643 uint32 i;
644
645 Assert(!GinPageIsData(page));
646
648
649 blkno = GinPageGetOpaque(page)->rightlink;
650
651 if (resPage)
652 {
655 MarkBufferDirty(buffer);
656 xlogVacuumPage(gvs.index, buffer);
657 UnlockReleaseBuffer(buffer);
659 }
660 else
661 {
662 UnlockReleaseBuffer(buffer);
663 }
664
665 vacuum_delay_point(false);
666
667 for (i = 0; i < nRoot; i++)
668 {
670 vacuum_delay_point(false);
671 }
672
673 if (blkno == InvalidBlockNumber) /* rightmost page */
674 break;
675
676 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
677 RBM_NORMAL, info->strategy);
678 LockBuffer(buffer, GIN_EXCLUSIVE);
679 }
680
681 MemoryContextDelete(gvs.tmpCxt);
682
683 return gvs.result;
684}
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition bufmgr.c:911
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:328
@ RBM_NORMAL
Definition bufmgr.h:46
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition bufpage.h:243
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition bufpage.h:353
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition bufpage.h:371
#define GIN_UNLOCK
Definition gin_private.h:50
#define GIN_EXCLUSIVE
Definition gin_private.h:52
#define GIN_SHARE
Definition gin_private.h:51
#define GIN_ROOT_BLKNO
Definition ginblock.h:52
#define GinGetDownlink(itup)
Definition ginblock.h:257
#define GinPageIsData(page)
Definition ginblock.h:115
#define GinPageIsLeaf(page)
Definition ginblock.h:112
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition ginfast.c:780
static void xlogVacuumPage(Relation index, Buffer buffer)
Definition ginvacuum.c:89
static void ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
Definition ginvacuum.c:408
static Page ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
Definition ginvacuum.c:455
int i
Definition isn.c:77
IndexTupleData * IndexTuple
Definition itup.h:53
#define AmAutoVacuumWorkerProcess()
Definition miscadmin.h:383
#define FirstOffsetNumber
Definition off.h:27
MemoryContext tmpCxt
Definition ginvacuum.c:35
double num_index_tuples
Definition genam.h:85
Relation index
Definition genam.h:52
BufferAccessStrategy strategy
Definition genam.h:59
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
void vacuum_delay_point(bool is_analyze)
Definition vacuum.c:2426

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, AmAutoVacuumWorkerProcess, Assert, DataPageDeleteStack::blkno, 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 525 of file gin_private.h.

528{
529 /* attribute number is the first sort key */
530 if (attnuma != attnumb)
531 return (attnuma < attnumb) ? -1 : 1;
532
533 return ginCompareEntries(ginstate, attnuma, a, categorya, b, categoryb);
534
535}
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 503 of file gin_private.h.

506{
507 /* if not of same null category, sort by that first */
508 if (categorya != categoryb)
509 return (categorya < categoryb) ? -1 : 1;
510
511 /* all null items in same category are equal */
513 return 0;
514
515 /* both not null, so safe to call the compareFn */
516 return DatumGetInt32(FunctionCall2Coll(&ginstate->compareFn[attnum - 1],
517 ginstate->supportCollation[attnum - 1],
518 a, b));
519}
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition fmgr.c:1150
#define GIN_CAT_NORM_KEY
Definition ginblock.h:208
static int32 DatumGetInt32(Datum X)
Definition postgres.h:212
Oid supportCollation[INDEX_MAX_KEYS]
Definition gin_private.h:89
FmgrInfo compareFn[INDEX_MAX_KEYS]
Definition gin_private.h:80

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:834
#define SHORTALIGN(LEN)
Definition c.h:822
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:619
static int ginCompareItemPointers(ItemPointer a, ItemPointer 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:471
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 346 of file gininsert.c.

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

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

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:3121
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition bufmgr.c:864
#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:826
#define Max(x, y)
Definition c.h:991
#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:202
bool oneCol
Definition gin_private.h:61
TupleDesc tupdesc[INDEX_MAX_KEYS]
Definition gin_private.h:75
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:543
#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:451
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:223
PageHeaderData * PageHeader
Definition bufpage.h:173
#define GinGetPendingListCleanupSize(relation)
Definition gin_private.h:40
#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:409
#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 356 of file ginutil.c.

357{
359}
static Size BufferGetPageSize(Buffer buffer)
Definition bufmgr.h:455

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:788
#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:84
FmgrInfo consistentFn[INDEX_MAX_KEYS]
Definition gin_private.h:83

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

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

345{
346 GinPageOpaque opaque;
347
348 PageInit(page, pageSize, sizeof(GinPageOpaqueData));
349
350 opaque = GinPageGetOpaque(page);
351 opaque->flags = f;
353}
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 856 of file gininsert.c.

861{
862 GinState *ginstate = (GinState *) indexInfo->ii_AmCache;
865 int i;
866
867 /* Initialize GinState cache if first call in this statement */
868 if (ginstate == NULL)
869 {
871 ginstate = palloc_object(GinState);
872 initGinState(ginstate, index);
873 indexInfo->ii_AmCache = ginstate;
875 }
876
878 "Gin insert temporary context",
880
882
884 {
886
887 memset(&collector, 0, sizeof(GinTupleCollector));
888
889 for (i = 0; i < ginstate->origTupdesc->natts; i++)
891 (OffsetNumber) (i + 1),
892 values[i], isnull[i],
893 ht_ctid);
894
896 }
897 else
898 {
899 for (i = 0; i < ginstate->origTupdesc->natts; i++)
900 ginHeapTupleInsert(ginstate, (OffsetNumber) (i + 1),
901 values[i], isnull[i],
902 ht_ctid);
903 }
904
907
908 return false;
909}
static Datum values[MAXATTR]
Definition bootstrap.c:155
#define GinGetUseFastUpdate(relation)
Definition gin_private.h:35
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:838
void * ii_AmCache
Definition execnodes.h:225
MemoryContext ii_Context
Definition execnodes.h:228

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:120
#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 306 of file ginutil.c.

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

References BMR_REL, BufferGetPage(), ConditionalLockBuffer(), EB_LOCK_FIRST, ExtendBufferedRel(), 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:537
int errhint(const char *fmt,...)
Definition elog.c:1330
Datum FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7)
Definition fmgr.c:1285
#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:591
#define INDEX_MAX_KEYS
#define pgstat_count_index_scan(rel)
Definition pgstat.h:705
#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 570 of file ginutil.c.

571{
572 static const relopt_parse_elt tab[] = {
573 {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)},
574 {"gin_pending_list_limit", RELOPT_TYPE_INT, offsetof(GinOptions,
575 pendingListCleanupSize)}
576 };
577
578 return (bytea *) build_reloptions(reloptions, validate,
580 sizeof(GinOptions),
581 tab, lengthof(tab));
582}
static bool validate(Port *port, const char *auth)
Definition auth-oauth.c:638
#define lengthof(array)
Definition c.h:803
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:706

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 ginDeletePage(), 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 232 of file ginutil.c.

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

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

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

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

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

References AmAutoVacuumWorkerProcess, IndexVacuumInfo::analyze_only, Assert, DataPageDeleteStack::blkno, BufferGetPage(), IndexVacuumInfo::estimated_count, IndexBulkDeleteResult::estimated_count, ExclusiveLock, fb(), GIN_ROOT_BLKNO, GIN_SHARE, ginInsertCleanup(), GinPageIsData, GinPageIsLeaf, GinPageIsList, GinPageIsRecyclable(), ginUpdateStats(), IndexVacuumInfo::index, IndexFreeSpaceMapVacuum(), initGinState(), LockBuffer(), LockRelationForExtension(), MAIN_FORKNUM, Max, IndexVacuumInfo::num_heap_tuples, IndexBulkDeleteResult::num_index_tuples, IndexBulkDeleteResult::num_pages, PageGetMaxOffsetNumber(), IndexBulkDeleteResult::pages_free, palloc0_object, RBM_NORMAL, ReadBufferExtended(), RecordFreeIndexPage(), RELATION_IS_LOCAL, RelationGetNumberOfBlocks, IndexVacuumInfo::strategy, UnlockRelationForExtension(), UnlockReleaseBuffer(), and vacuum_delay_point().

Referenced by ginhandler().

◆ ginVacuumItemPointers()

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

Definition at line 47 of file ginvacuum.c.

49{
50 int i,
51 remaining = 0;
53
54 /*
55 * Iterate over TIDs array
56 */
57 for (i = 0; i < nitem; i++)
58 {
59 if (gvs->callback(items + i, gvs->callback_state))
60 {
61 gvs->result->tuples_removed += 1;
62 if (!tmpitems)
63 {
64 /*
65 * First TID to be deleted: allocate memory to hold the
66 * remaining items.
67 */
70 }
71 }
72 else
73 {
74 gvs->result->num_index_tuples += 1;
75 if (tmpitems)
77 remaining++;
78 }
79 }
80
82 return tmpitems;
83}
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:47
#define GIN_SEGMENT_DELETE
Definition ginxlog.h:92
#define XLOG_GIN_VACUUM_DATA_LEAF_PAGE
Definition ginxlog.h:141
#define GIN_SEGMENT_UNMODIFIED
Definition ginxlog.h:91
#define GIN_SEGMENT_REPLACE
Definition ginxlog.h:94
#define dlist_foreach(iter, lhead)
Definition ilist.h:623
#define dlist_container(type, membername, ptr)
Definition ilist.h:593
dlist_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:765
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:1403
FormData_pg_amop * Form_pg_amop
Definition pg_amop.h:88
FormData_pg_amproc * Form_pg_amproc
Definition pg_amproc.h:68
FormData_pg_opclass * Form_pg_opclass
Definition pg_opclass.h:83
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
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(int 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(), 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 }
133
134 /*
135 * If the compare proc isn't specified in the opclass definition, look
136 * up the index key type's default btree comparator.
137 */
139 {
140 fmgr_info_copy(&(state->compareFn[i]),
143 }
144 else
145 {
146 TypeCacheEntry *typentry;
147
148 typentry = lookup_type_cache(attr->atttypid,
150 if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
153 errmsg("could not identify a comparison function for type %s",
154 format_type_be(attr->atttypid))));
155 fmgr_info_copy(&(state->compareFn[i]),
156 &(typentry->cmp_proc_finfo),
158 }
159
160 /* Opclass must always provide extract procs */
161 fmgr_info_copy(&(state->extractValueFn[i]),
164 fmgr_info_copy(&(state->extractQueryFn[i]),
167
168 /*
169 * Check opclass capability to do tri-state or binary logic consistent
170 * check.
171 */
173 {
174 fmgr_info_copy(&(state->triConsistentFn[i]),
177 }
178
180 {
181 fmgr_info_copy(&(state->consistentFn[i]),
184 }
185
186 if (state->consistentFn[i].fn_oid == InvalidOid &&
187 state->triConsistentFn[i].fn_oid == InvalidOid)
188 {
189 elog(ERROR, "missing GIN support function (%d or %d) for attribute %d of index \"%s\"",
192 }
193
194 /*
195 * Check opclass capability to do partial match.
196 */
198 {
199 fmgr_info_copy(&(state->comparePartialFn[i]),
202 state->canPartialMatch[i] = true;
203 }
204 else
205 {
206 state->canPartialMatch[i] = false;
207 }
208
209 /*
210 * If the index column has a specified collation, we should honor that
211 * while doing comparisons. However, we may have a collatable storage
212 * type for a noncollatable indexed data type (for instance, hstore
213 * uses text index entries). If there's no index collation then
214 * specify default collation in case the support functions need
215 * collation. This is harmless if the support functions don't care
216 * about collation, so we just do it unconditionally. (We could
217 * alternatively call get_typcollation, but that seems like expensive
218 * overkill --- there aren't going to be any cases where a GIN storage
219 * type has a nondefault collation.)
220 */
221 if (OidIsValid(index->rd_indcollation[i]))
222 state->supportCollation[i] = index->rd_indcollation[i];
223 else
224 state->supportCollation[i] = DEFAULT_COLLATION_OID;
225 }
226}
int16 AttrNumber
Definition attnum.h:21
#define MemSet(start, val, len)
Definition c.h:1013
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition fmgr.c:581
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:182
void TupleDescInitEntryCollation(TupleDesc desc, AttrNumber attributeNumber, Oid collationid)
Definition tupdesc.c:1026
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition tupdesc.c:842
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:160
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:386
#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(), 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().